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" 30namespace OHOS { 31namespace Developtools { 32namespace NativeDaemon { 33#ifdef DEBUG_TIME 34bool 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 48const std::pair<std::shared_ptr<MemMaps>, uint32_t> VirtualThread::FindMemMapsByAddr(uint64_t addr) const 49{ 50 return virtualruntime_->FindMap(addr); 51} 52 53const 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} 89VirtualThread::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 107std::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 115const 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 133SymbolsFile *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 (const auto &file : symbolsFiles_) { 148 HLOGW(" we have '%s'", file->filePath_.c_str()); 149 } 150 } 151#endif 152 return nullptr; 153} 154 155SymbolsFile *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 (const auto &file : symbolsFiles_) { 170 HLOGW(" we have '%s'", file->filePath_.c_str()); 171 } 172 } 173#endif 174 return nullptr; 175} 176 177void 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 192bool 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 222bool 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, memMapItem); 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, memMapItem); 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 291void 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 309void 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