106f6ba60Sopenharmony_ci/* 206f6ba60Sopenharmony_ci * Copyright (c) Huawei Technologies Co., Ltd. 2021. All rights reserved. 306f6ba60Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 406f6ba60Sopenharmony_ci * you may not use this file except in compliance with the License. 506f6ba60Sopenharmony_ci * You may obtain a copy of the License at 606f6ba60Sopenharmony_ci * 706f6ba60Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 806f6ba60Sopenharmony_ci * 906f6ba60Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software 1006f6ba60Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 1106f6ba60Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1206f6ba60Sopenharmony_ci * See the License for the specific language governing permissions and 1306f6ba60Sopenharmony_ci * limitations under the License. 1406f6ba60Sopenharmony_ci */ 1506f6ba60Sopenharmony_ci#ifndef HIPERF_VIRTUAL_RUNTIME_H 1606f6ba60Sopenharmony_ci#define HIPERF_VIRTUAL_RUNTIME_H 1706f6ba60Sopenharmony_ci#include <unistd.h> 1806f6ba60Sopenharmony_ci#include <sys/types.h> 1906f6ba60Sopenharmony_ci#include <pthread.h> 2006f6ba60Sopenharmony_ci#include <functional> 2106f6ba60Sopenharmony_ci#include <map> 2206f6ba60Sopenharmony_ci#if defined(is_ohos) && is_ohos 2306f6ba60Sopenharmony_ci#include "call_stack.h" 2406f6ba60Sopenharmony_ci#endif 2506f6ba60Sopenharmony_ci#include "hashlistpp.h" 2606f6ba60Sopenharmony_ci#include "perf_event_record.h" 2706f6ba60Sopenharmony_ci#include "symbols_file.h" 2806f6ba60Sopenharmony_ci#include "virtual_thread.h" 2906f6ba60Sopenharmony_ci#include "native_hook_config.pb.h" 3006f6ba60Sopenharmony_ci 3106f6ba60Sopenharmony_cinamespace OHOS { 3206f6ba60Sopenharmony_cinamespace Developtools { 3306f6ba60Sopenharmony_cinamespace NativeDaemon { 3406f6ba60Sopenharmony_ci/* 3506f6ba60Sopenharmony_ciThis Class contains userspace thread objects. and kernel space objects 3606f6ba60Sopenharmony_ciIt represents a virtual operating environment, mainly referring to the relationship between pid, 3706f6ba60Sopenharmony_cimmaps, and symbols. 3806f6ba60Sopenharmony_ci 3906f6ba60Sopenharmony_ciIt mainly receives data is ip pointer (virtual address), pid 4006f6ba60Sopenharmony_ciAccording to these data, it will find the corresponding mmap and its corresponding elf (also called 4106f6ba60Sopenharmony_ciDSO) 4206f6ba60Sopenharmony_ci 4306f6ba60Sopenharmony_ciThen find the corresponding symbol in the corresponding elf symbol file according to the offset 4406f6ba60Sopenharmony_cirecorded in the corresponding mmap. 4506f6ba60Sopenharmony_ci*/ 4606f6ba60Sopenharmony_ci 4706f6ba60Sopenharmony_ciclass VirtualRuntime { 4806f6ba60Sopenharmony_cipublic: 4906f6ba60Sopenharmony_ci VirtualRuntime() = default; 5006f6ba60Sopenharmony_ci VirtualRuntime(const NativeHookConfig& hookConfig); 5106f6ba60Sopenharmony_ci virtual ~VirtualRuntime(); 5206f6ba60Sopenharmony_ci // thread need hook the record 5306f6ba60Sopenharmony_ci // from the record , it will call back to write some Simulated Record 5406f6ba60Sopenharmony_ci // case 1. some mmap will be create when it read mmaps for each new process (from record sample) 5506f6ba60Sopenharmony_ci 5606f6ba60Sopenharmony_ci // set symbols path , it will send to every symobile file for search 5706f6ba60Sopenharmony_ci bool SetSymbolsPaths(const std::vector<std::string> &symbolsPaths); 5806f6ba60Sopenharmony_ci 5906f6ba60Sopenharmony_ci // any mode 6006f6ba60Sopenharmony_ci static_assert(sizeof(pid_t) == sizeof(int)); 6106f6ba60Sopenharmony_ci 6206f6ba60Sopenharmony_ci const std::unordered_map<std::string, std::unique_ptr<SymbolsFile>> &GetSymbolsFiles() const 6306f6ba60Sopenharmony_ci { 6406f6ba60Sopenharmony_ci return symbolsFiles_; 6506f6ba60Sopenharmony_ci } 6606f6ba60Sopenharmony_ci 6706f6ba60Sopenharmony_ci const DfxSymbol GetSymbol(CallFrame& callFrame, pid_t pid, pid_t tid, 6806f6ba60Sopenharmony_ci const perf_callchain_context &context = PERF_CONTEXT_MAX); 6906f6ba60Sopenharmony_ci 7006f6ba60Sopenharmony_ci VirtualThread &GetThread(pid_t pid, pid_t tid); 7106f6ba60Sopenharmony_ci const std::map<pid_t, VirtualThread> &GetThreads() const 7206f6ba60Sopenharmony_ci { 7306f6ba60Sopenharmony_ci return userSpaceThreadMap_; 7406f6ba60Sopenharmony_ci } 7506f6ba60Sopenharmony_ci 7606f6ba60Sopenharmony_ci bool UnwindStack(std::vector<u64>& regs, 7706f6ba60Sopenharmony_ci const u8* stack_addr, 7806f6ba60Sopenharmony_ci int stack_size, 7906f6ba60Sopenharmony_ci pid_t pid, 8006f6ba60Sopenharmony_ci pid_t tid, 8106f6ba60Sopenharmony_ci std::vector<CallFrame>& callFrames, 8206f6ba60Sopenharmony_ci size_t maxStackLevel); 8306f6ba60Sopenharmony_ci bool GetSymbolName(pid_t pid, pid_t tid, std::vector<CallFrame>& callFrames, int offset, bool first, 8406f6ba60Sopenharmony_ci bool onlyjs = false); 8506f6ba60Sopenharmony_ci void ClearMaps(); 8606f6ba60Sopenharmony_ci void FillMapsCache(std::string& currentFileName, std::shared_ptr<DfxMap> mapItem); 8706f6ba60Sopenharmony_ci void HandleMapInfo(std::vector<uint64_t> info, const std::string& filePath, pid_t pid, pid_t tid); 8806f6ba60Sopenharmony_ci void RemoveMaps(uint64_t addr); 8906f6ba60Sopenharmony_ci // threads 9006f6ba60Sopenharmony_ci VirtualThread &UpdateThread(pid_t pid, pid_t tid, const std::string name = ""); 9106f6ba60Sopenharmony_ci void FillSymbolNameId(CallFrame& callFrame, DfxSymbol& symbol); 9206f6ba60Sopenharmony_ci void FillFileSet(CallFrame& callFrame, const DfxSymbol& symbol); 9306f6ba60Sopenharmony_ci uint32_t FillArkTsFilePath(std::string_view& jstr); 9406f6ba60Sopenharmony_ci uint32_t FindArkTsFilePath(std::string_view& jstr); 9506f6ba60Sopenharmony_ci bool ArktsGetSymbolCache(CallFrame& callFrame, DfxSymbol &symbol); 9606f6ba60Sopenharmony_ci uint32_t GetJsSymbolCacheSize(); 9706f6ba60Sopenharmony_ci void FillJsSymbolCache(CallFrame& callFrame, const DfxSymbol& symbol); 9806f6ba60Sopenharmony_ci std::vector<uint64_t>& GetOfflineMaps() 9906f6ba60Sopenharmony_ci { 10006f6ba60Sopenharmony_ci return offlineMapAddr_; 10106f6ba60Sopenharmony_ci } 10206f6ba60Sopenharmony_ci 10306f6ba60Sopenharmony_ci void ClearOfflineMaps() 10406f6ba60Sopenharmony_ci { 10506f6ba60Sopenharmony_ci offlineMapAddr_.clear(); 10606f6ba60Sopenharmony_ci } 10706f6ba60Sopenharmony_ci 10806f6ba60Sopenharmony_ci std::map<uint64_t, std::shared_ptr<MemMaps>>& GetMapsCache() 10906f6ba60Sopenharmony_ci { 11006f6ba60Sopenharmony_ci return mapsCache_; 11106f6ba60Sopenharmony_ci } 11206f6ba60Sopenharmony_ci 11306f6ba60Sopenharmony_ci std::pair<std::shared_ptr<MemMaps>, uint32_t> FindMap(uint64_t addr); 11406f6ba60Sopenharmony_ci uint64_t soBegin_ {0}; 11506f6ba60Sopenharmony_ci // debug time 11606f6ba60Sopenharmony_ci#ifdef HIPERF_DEBUG_TIME 11706f6ba60Sopenharmony_ci std::chrono::microseconds updateSymbolsTimes_ = std::chrono::microseconds::zero(); 11806f6ba60Sopenharmony_ci std::chrono::microseconds unwindFromRecordTimes_ = std::chrono::microseconds::zero(); 11906f6ba60Sopenharmony_ci std::chrono::microseconds unwindCallStackTimes_ = std::chrono::microseconds::zero(); 12006f6ba60Sopenharmony_ci std::chrono::microseconds symbolicRecordTimes_ = std::chrono::microseconds::zero(); 12106f6ba60Sopenharmony_ci std::chrono::microseconds updateThreadTimes_ = std::chrono::microseconds::zero(); 12206f6ba60Sopenharmony_ci#endif 12306f6ba60Sopenharmony_ci const bool loadSymboleWhenNeeded_ = true; // thie is a feature config 12406f6ba60Sopenharmony_ci void UpdateSymbols(std::string filename, std::shared_ptr<DfxMap> map); 12506f6ba60Sopenharmony_ci // we don't know whether hap vma mapping is stand for a so 12606f6ba60Sopenharmony_ci // thus we need try to parse it first 12706f6ba60Sopenharmony_ci bool UpdateHapSymbols(std::shared_ptr<DfxMap> map); 12806f6ba60Sopenharmony_ci bool IsSymbolExist(const std::string& fileName); 12906f6ba60Sopenharmony_ci void DelSymbolFile(const std::string& fileName); 13006f6ba60Sopenharmony_ci void UpdateMaps(pid_t pid, pid_t tid); 13106f6ba60Sopenharmony_ci std::vector<std::shared_ptr<DfxMap>>& GetProcessMaps() 13206f6ba60Sopenharmony_ci { 13306f6ba60Sopenharmony_ci return processMaps_; 13406f6ba60Sopenharmony_ci } 13506f6ba60Sopenharmony_ci 13606f6ba60Sopenharmony_cipublic: 13706f6ba60Sopenharmony_ci enum SymbolCacheLimit : std::size_t { 13806f6ba60Sopenharmony_ci USER_SYMBOL_CACHE_LIMIT = 10000, 13906f6ba60Sopenharmony_ci }; 14006f6ba60Sopenharmony_ci 14106f6ba60Sopenharmony_ciprivate: 14206f6ba60Sopenharmony_ci struct SymbolCacheKey : public std::pair<uint64_t, uint32_t> { 14306f6ba60Sopenharmony_ci uint64_t& ip = first; 14406f6ba60Sopenharmony_ci uint32_t& filePathId = second; 14506f6ba60Sopenharmony_ci explicit SymbolCacheKey() = default; 14606f6ba60Sopenharmony_ci virtual ~SymbolCacheKey() = default; 14706f6ba60Sopenharmony_ci SymbolCacheKey(const SymbolCacheKey &) = default; 14806f6ba60Sopenharmony_ci SymbolCacheKey& operator=(const SymbolCacheKey& sym) 14906f6ba60Sopenharmony_ci { 15006f6ba60Sopenharmony_ci ip = sym.ip; 15106f6ba60Sopenharmony_ci filePathId = sym.filePathId; 15206f6ba60Sopenharmony_ci return *this; 15306f6ba60Sopenharmony_ci } 15406f6ba60Sopenharmony_ci SymbolCacheKey(const std::pair<uint64_t, uint32_t>& arg) : pair(arg), ip(first), filePathId(second) {} 15506f6ba60Sopenharmony_ci SymbolCacheKey(uint64_t ip, uint32_t filePathId) : pair(ip, filePathId), ip(first), filePathId(second) {} 15606f6ba60Sopenharmony_ci }; 15706f6ba60Sopenharmony_ci 15806f6ba60Sopenharmony_ci // boost library recommendation algorithm to reduce hash collisions. 15906f6ba60Sopenharmony_ci struct HashPair { 16006f6ba60Sopenharmony_ci size_t operator() (const SymbolCacheKey& key) const 16106f6ba60Sopenharmony_ci { 16206f6ba60Sopenharmony_ci std::hash<uint64_t> hasher; 16306f6ba60Sopenharmony_ci size_t seed = 0; 16406f6ba60Sopenharmony_ci // 6 and 2 is the number of displacements 16506f6ba60Sopenharmony_ci seed ^= hasher(key.ip) + 0x9e3779b9 + (seed << 6) + (seed >> 2); 16606f6ba60Sopenharmony_ci seed ^= hasher(key.filePathId) + 0x9e3779b9 + (seed << 6) + (seed >> 2); 16706f6ba60Sopenharmony_ci return seed; 16806f6ba60Sopenharmony_ci } 16906f6ba60Sopenharmony_ci }; 17006f6ba60Sopenharmony_ci#if defined(is_ohos) && is_ohos 17106f6ba60Sopenharmony_ci CallStack callstack_; 17206f6ba60Sopenharmony_ci#endif 17306f6ba60Sopenharmony_ci // pid map with user space thread 17406f6ba60Sopenharmony_ci pid_t pid_ = 0; 17506f6ba60Sopenharmony_ci pthread_mutex_t threadMapsLock_; 17606f6ba60Sopenharmony_ci std::map<pid_t, VirtualThread> userSpaceThreadMap_; 17706f6ba60Sopenharmony_ci // not pid , just map 17806f6ba60Sopenharmony_ci std::vector<DfxMap> kernelSpaceMaps_; 17906f6ba60Sopenharmony_ci pthread_mutex_t processSymbolsFileLock_; 18006f6ba60Sopenharmony_ci std::unordered_set<uint32_t> fileSet_; // for mapItem filePathId_ 18106f6ba60Sopenharmony_ci std::unordered_map<std::string, uint32_t> functionMap_; 18206f6ba60Sopenharmony_ci std::unordered_map<std::string, std::unique_ptr<SymbolsFile>> symbolsFiles_; 18306f6ba60Sopenharmony_ci std::unordered_map<SymbolCacheKey, DfxSymbol, HashPair> userSymbolCache_; 18406f6ba60Sopenharmony_ci bool GetSymbolCache(uint64_t ip, DfxSymbol &symbol, const VirtualThread &thread); 18506f6ba60Sopenharmony_ci void UpdateSymbolCache(uint64_t ip, DfxSymbol &symbol, HashList<uint64_t, DfxSymbol> &cache); 18606f6ba60Sopenharmony_ci 18706f6ba60Sopenharmony_ci // find synbols function name 18806f6ba60Sopenharmony_ci void MakeCallFrame(DfxSymbol &symbol, CallFrame &callFrame); 18906f6ba60Sopenharmony_ci 19006f6ba60Sopenharmony_ci std::string ReadThreadName(pid_t tid); 19106f6ba60Sopenharmony_ci VirtualThread &CreateThread(pid_t pid, pid_t tid); 19206f6ba60Sopenharmony_ci 19306f6ba60Sopenharmony_ci const DfxSymbol GetKernelSymbol(uint64_t ip, const std::vector<std::shared_ptr<DfxMap>> &maps, 19406f6ba60Sopenharmony_ci const VirtualThread &thread); 19506f6ba60Sopenharmony_ci const DfxSymbol GetUserSymbol(uint64_t ip, const VirtualThread &thread); 19606f6ba60Sopenharmony_ci 19706f6ba60Sopenharmony_ci std::vector<std::string> symbolsPaths_; 19806f6ba60Sopenharmony_ci 19906f6ba60Sopenharmony_ci friend class VirtualRuntimeTest; 20006f6ba60Sopenharmony_ci friend class VirtualThread; 20106f6ba60Sopenharmony_ci std::vector<std::shared_ptr<DfxMap>> processMaps_; 20206f6ba60Sopenharmony_ci std::unordered_set<uint64_t> failedIPs_; 20306f6ba60Sopenharmony_ci const NativeHookConfig hookConfig_; 20406f6ba60Sopenharmony_ci uint32_t memMapFilePathId_ = 0; 20506f6ba60Sopenharmony_ci std::map<uint64_t, std::shared_ptr<MemMaps>> mapsCache_; // key is memMap soBegin, value is MemMaps 20606f6ba60Sopenharmony_ci std::vector<uint64_t> offlineMapAddr_; // element is memMap soBegin 20706f6ba60Sopenharmony_ci std::unordered_map<std::string_view, uint32_t> jsUrlMap_; // Key is js url , value is filePathId 20806f6ba60Sopenharmony_ci}; 20906f6ba60Sopenharmony_ci} // namespace NativeDaemon 21006f6ba60Sopenharmony_ci} // namespace Developtools 21106f6ba60Sopenharmony_ci} // namespace OHOS 21206f6ba60Sopenharmony_ci#endif