• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) Huawei Technologies Co., Ltd. 2021. All rights reserved.
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 "common.h"
27 #include "symbols_file.h"
28 #include "utilities.h"
29 #include "virtual_runtime.h"
30 namespace OHOS {
31 namespace Developtools {
32 namespace NativeDaemon {
33 #ifdef DEBUG_TIME
IsSorted() const34 bool VirtualThread::IsSorted() const
35 {
36     for (std::size_t index = 1; index < maps_->size(); ++index) {
37         if ((*maps_)[index - 1].end > (*maps_)[index].begin) {
38             std::cout << "maps_ order error:\n"
39                       << "    " << (*maps_)[index - 1].begin << "-" << (*maps_)[index - 1].end
40                       << "    " << (*maps_)[index].begin << "-" << (*maps_)[index].end;
41             return false;
42         }
43     }
44     return true;
45 }
46 #endif
47 
FindMemMapsByAddr(uint64_t addr) const48 const std::pair<std::shared_ptr<MemMaps>, uint32_t> VirtualThread::FindMemMapsByAddr(uint64_t addr) const
49 {
50     return virtualruntime_->FindMap(addr);
51 }
52 
FindMapByAddr(uint64_t addr) const53 const std::shared_ptr<DfxMap> VirtualThread::FindMapByAddr(uint64_t addr) const
54 {
55     HLOGM("try found vaddr 0x%" PRIx64 " in maps %zu ", addr, maps_->size());
56     if (maps_->size() == 0) {
57         return nullptr;
58     }
59     if (maps_->front()->begin > addr) {
60         return nullptr;
61     }
62     if (maps_->back()->end <= addr) {
63         return nullptr;
64     }
65     constexpr int two {2};
66     std::size_t left {0};
67     std::size_t right {maps_->size()};
68     std::size_t mid = (right - left) / two + left;
69     while (left < right) {
70         if (addr < (*maps_)[mid]->end) {
71             right = mid;
72             mid = (right - left) / two + left;
73             continue;
74         }
75         if (addr >= (*maps_)[mid]->end) {
76             left = mid + 1;
77             mid = (right - left) / two + left;
78             continue;
79         }
80     }
81     if (addr >= (*maps_)[left]->begin and addr < (*maps_)[left]->end) {
82         if (left > 0) {
83             (*maps_)[left]->prevMap = (*maps_)[left - 1];
84         }
85         return (*maps_)[left];
86     }
87     return nullptr;
88 }
VirtualThread(pid_t pid,pid_t tid,const std::unordered_map<std::string,std::unique_ptr<SymbolsFile>> & symbolsFiles,VirtualRuntime * runtime,bool parseFlag)89 VirtualThread::VirtualThread(pid_t pid,
90                              pid_t tid,
91                              const std::unordered_map<std::string, std::unique_ptr<SymbolsFile>>& symbolsFiles,
92                              VirtualRuntime* runtime,
93                              bool parseFlag)
94     : pid_(pid), tid_(tid), symbolsFiles_(symbolsFiles), virtualruntime_(runtime)
95 {
96     maps_ = &virtualruntime_->processMaps_;
97     if (parseFlag) {
98         if (virtualruntime_->processMaps_.size() == 0) {
99             this->ParseMap(virtualruntime_->processMaps_);
100         }
101     }
102 
103     this->name_ = ReadThreadName(pid);
104     HLOGM("%d %d map from parent size is %zu", pid, tid, maps_->size());
105 }
106 
ReadThreadName(pid_t tid)107 std::string VirtualThread::ReadThreadName(pid_t tid)
108 {
109     std::string comm = ReadFileToString(StringPrintf("/proc/%d/comm", tid)).c_str();
110     comm.erase(std::remove(comm.begin(), comm.end(), '\r'), comm.end());
111     comm.erase(std::remove(comm.begin(), comm.end(), '\n'), comm.end());
112     return comm;
113 }
114 
FindMapByFileInfo(const std::string name,uint64_t offset) const115 const std::shared_ptr<DfxMap> VirtualThread::FindMapByFileInfo(const std::string name, uint64_t offset) const
116 {
117     for (auto map : *maps_) {
118         if (name != map->name) {
119             continue;
120         }
121         // check begin and length
122         if (offset >= map->offset && (offset - map->offset) < (map->end - map->begin)) {
123             HLOGMMM("found fileoffset 0x%" PRIx64 " in map (0x%" PRIx64 " - 0x%" PRIx64
124                     " pageoffset 0x%" PRIx64 ")  from %s",
125                     offset, map->begin, map->end, map->offset, map->name.c_str());
126             return map;
127         }
128     }
129     HLOGM("NOT found offset 0x%" PRIx64 " in maps %zu ", offset, maps_->size());
130     return nullptr;
131 }
132 
FindSymbolsFileByMap(std::shared_ptr<DfxMap> inMap) const133 SymbolsFile *VirtualThread::FindSymbolsFileByMap(std::shared_ptr<DfxMap> inMap) const
134 {
135     auto search = symbolsFiles_.find(inMap->name);
136     if (search != symbolsFiles_.end()) {
137         auto& symbolsFile = search->second;
138         HLOGM("found symbol for map '%s'", inMap->name.c_str());
139         symbolsFile->LoadDebugInfo(inMap);
140         return symbolsFile.get();
141     }
142 #ifdef DEBUG_MISS_SYMBOL
143     if (find(missedSymbolFile_.begin(), missedSymbolFile_.end(), inMap->name) ==
144         missedSymbolFile_.end()) {
145         missedSymbolFile_.emplace_back(inMap->name);
146         HLOGW("NOT found symbol for map '%s'", inMap->name.c_str());
147         for (auto &file : symbolsFiles_) {
148             HLOGW(" we have '%s'", file->filePath_.c_str());
149         }
150     }
151 #endif
152     return nullptr;
153 }
154 
FindSymbolsFileByName(const std::string & name) const155 SymbolsFile *VirtualThread::FindSymbolsFileByName(const std::string &name) const
156 {
157     auto search = symbolsFiles_.find(name);
158     if (search != symbolsFiles_.end()) {
159         auto& symbolsFile = search->second;
160         HLOGM("found symbol for map '%s'", name.c_str());
161         symbolsFile->LoadDebugInfo();
162         return symbolsFile.get();
163     }
164 #ifdef DEBUG_MISS_SYMBOL
165     if (find(missedSymbolFile_.begin(), missedSymbolFile_.end(), name) ==
166         missedSymbolFile_.end()) {
167         missedSymbolFile_.emplace_back(name);
168         HLOGW("NOT found symbol for map '%s'", name.c_str());
169         for (auto &file : symbolsFiles_) {
170             HLOGW(" we have '%s'", file->filePath_.c_str());
171         }
172     }
173 #endif
174     return nullptr;
175 }
176 
ReportVaddrMapMiss(uint64_t vaddr) const177 void VirtualThread::ReportVaddrMapMiss(uint64_t vaddr) const
178 {
179 #ifdef HIPERF_DEBUG
180     if (DebugLogger::GetInstance()->GetLogLevel() <= LEVEL_VERBOSE) {
181         if (missedRuntimeVaddr_.find(vaddr) == missedRuntimeVaddr_.end()) {
182             missedRuntimeVaddr_.insert(vaddr);
183             HLOGV("vaddr %" PRIx64 " not found in any map", vaddr);
184             for (auto &map : *maps_) {
185                 HLOGV("map %s ", map->ToString().c_str());
186             }
187         }
188     }
189 #endif
190 }
191 
ReadRoMemory(uint64_t vaddr,uint8_t * data,size_t size) const192 bool VirtualThread::ReadRoMemory(uint64_t vaddr, uint8_t *data, size_t size) const
193 {
194     auto [curMemMaps, itemIndex] = virtualruntime_->FindMap(vaddr);
195     if (curMemMaps != nullptr) {
196         // found symbols by file name
197         SymbolsFile *symbolsFile = FindSymbolsFileByMap((curMemMaps->GetMaps())[itemIndex]);
198         if (symbolsFile != nullptr) {
199             std::shared_ptr<DfxMap> map = (curMemMaps->GetMaps())[itemIndex];
200             HLOGM("read vaddr from addr is 0x%" PRIx64 "  mapStart :0x%" PRIx64 " mapOffset :0x%" PRIx64 " at '%s'",
201                   vaddr - map->begin, map->begin, map->offset, map->name.c_str());
202             map->elf = symbolsFile->GetElfFile();
203             if (map->elf != nullptr) {
204                 auto fileOffset = map->FileOffsetFromAddr(vaddr);
205                 fileOffset -= map->elf->GetBaseOffset();
206                 map->elf->Read(fileOffset, data, size);
207                 return true;
208             }
209             HLOGE("ElfFile(%s) is null or read file offset from addr fail", curMemMaps->name_.c_str());
210             return false;
211         } else {
212             HLOGE("found addr %" PRIx64 " in map but not loaded symbole %s", vaddr, curMemMaps->name_.c_str());
213         }
214     } else {
215 #ifdef HIPERF_DEBUG
216         ReportVaddrMapMiss(vaddr);
217 #endif
218     }
219     return false;
220 }
221 
ParseMap(std::vector<std::shared_ptr<DfxMap>> & memMaps,bool update)222 bool VirtualThread::ParseMap(std::vector<std::shared_ptr<DfxMap>>& memMaps, bool update)
223 {
224     std::string mapPath = StringPrintf("/proc/%d/maps", pid_);
225     std::shared_ptr<DfxMaps> dfxMaps = OHOS::HiviewDFX::DfxMaps::Create(pid_, mapPath);
226     if (dfxMaps == nullptr) {
227         HLOGE("VirtualThread Failed to Parse Map.");
228         return false;
229     }
230     memMaps = dfxMaps->GetMaps();
231     bool mapsAdded = !update;
232     std::vector<std::shared_ptr<DfxMap>> tempMap;
233     std::string tempMapName;
234     std::shared_ptr<DfxMap> prevMap = nullptr;
235     for (auto memMapItem : memMaps) {
236         if (!update) {
237             virtualruntime_->FillMapsCache(tempMapName, memMapItem);
238             bool updateNormalSymbol = true;
239             if (memMapItem->name.find(".hap") != std::string::npos && (memMapItem->prots & PROT_EXEC)) {
240                 memMapItem->prevMap = prevMap;
241                 HLOGD("update hap(%s) symbols", memMapItem->name.c_str());
242                 updateNormalSymbol = !virtualruntime_->UpdateHapSymbols(memMapItem);
243             }
244             if (updateNormalSymbol) {
245                 virtualruntime_->UpdateSymbols(memMapItem->name);
246             }
247             prevMap = memMapItem;
248         } else if (!virtualruntime_->IsSymbolExist(memMapItem->name)) {
249             virtualruntime_->FillMapsCache(tempMapName, memMapItem);
250             mapsAdded = true;
251             tempMap.push_back(memMapItem);
252             bool updateNormalSymbol = true;
253             if (memMapItem->name.find(".hap") != std::string::npos && (memMapItem->prots & PROT_EXEC)) {
254                 memMapItem->prevMap = prevMap;
255                 HLOGD("update hap(%s) symbols", memMapItem->name.c_str());
256                 updateNormalSymbol = !virtualruntime_->UpdateHapSymbols(memMapItem);
257             }
258             if (updateNormalSymbol) {
259                 virtualruntime_->UpdateSymbols(memMapItem->name);
260             }
261             prevMap = memMapItem;
262         }
263     }
264 
265     // Find if there are duplicate mapping intervals, and if there are, overwrite the old data with the new data.
266     for (auto tempMapIter = tempMap.begin(); tempMapIter != tempMap.end(); ++tempMapIter) {
267         auto memMapIter = std::find_if(memMaps.begin(), memMaps.end(), [&](const std::shared_ptr<DfxMap>& map) {
268             if ((*tempMapIter)->begin == map->begin && (*tempMapIter)->end == map->end) {
269                 return true;
270             }
271             return false;
272         });
273         if (memMapIter != memMaps.end()) {
274             virtualruntime_->DelSymbolFile((*memMapIter)->name);
275             memMaps.erase(memMapIter);
276         }
277     }
278     memMaps.insert(memMaps.end(), tempMap.begin(), tempMap.end());
279 
280     if (mapsAdded) {
281         PROFILER_LOG_DEBUG(LOG_CORE, "maps changed and need sort");
282         SortMaps();
283     } else {
284         PROFILER_LOG_DEBUG(LOG_CORE, "maps no change");
285         return false;
286     }
287     virtualruntime_->soBegin_ = 0;
288     return true;
289 }
290 
SortMaps()291 void VirtualThread::SortMaps()
292 {
293     for (size_t currPos = 1; currPos < maps_->size(); ++currPos) {
294         int targetPos = static_cast<int>(currPos - 1);
295         while (targetPos >= 0 && (*maps_)[currPos]->end < (*maps_)[targetPos]->end) {
296             --targetPos;
297         }
298         if (targetPos < static_cast<int>(currPos - 1)) {
299             auto target = (*maps_)[currPos];
300             for (size_t k = currPos - 1; k > static_cast<size_t>(targetPos); --k) {
301                 (*maps_)[k + 1] = (*maps_)[k];
302             }
303             (*maps_)[targetPos + 1] = target;
304         }
305     }
306     return;
307 }
308 
CreateMapItem(const std::string filename,uint64_t begin,uint64_t len,uint64_t offset)309 void VirtualThread::CreateMapItem(const std::string filename, uint64_t begin, uint64_t len,
310                                   uint64_t offset)
311 {
312     if (!OHOS::HiviewDFX::DfxMaps::IsLegalMapItem(filename)) {
313         return; // skip some memmap
314     }
315     uint32_t prots =  PROT_EXEC;
316 
317     std::shared_ptr<DfxMap> map = std::make_shared<DfxMap>(begin, begin + len, offset, prots, filename);
318     maps_->emplace_back(map);
319     std::string tempMapName{" "};
320     virtualruntime_->FillMapsCache(tempMapName, map);
321     SortMaps();
322 }
323 } // namespace NativeDaemon
324 } // namespace Developtools
325 } // namespace OHOS