148f512ceSopenharmony_ci/*
248f512ceSopenharmony_ci * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
348f512ceSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
448f512ceSopenharmony_ci * you may not use this file except in compliance with the License.
548f512ceSopenharmony_ci * You may obtain a copy of the License at
648f512ceSopenharmony_ci *
748f512ceSopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
848f512ceSopenharmony_ci *
948f512ceSopenharmony_ci * Unless required by applicable law or agreed to in writing, software
1048f512ceSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
1148f512ceSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1248f512ceSopenharmony_ci * See the License for the specific language governing permissions and
1348f512ceSopenharmony_ci * limitations under the License.
1448f512ceSopenharmony_ci */
1548f512ceSopenharmony_ci#ifndef HIPERF_VIRTUAL_RUNTIME_H
1648f512ceSopenharmony_ci#define HIPERF_VIRTUAL_RUNTIME_H
1748f512ceSopenharmony_ci
1848f512ceSopenharmony_ci#include <functional>
1948f512ceSopenharmony_ci#include <fstream>
2048f512ceSopenharmony_ci#if defined(is_ohos) && is_ohos
2148f512ceSopenharmony_ci#include "callstack.h"
2248f512ceSopenharmony_ci#endif
2348f512ceSopenharmony_ci#include "hashlist.h"
2448f512ceSopenharmony_ci#include "perf_event_record.h"
2548f512ceSopenharmony_ci#include "symbols_file.h"
2648f512ceSopenharmony_ci#include "virtual_thread.h"
2748f512ceSopenharmony_ci
2848f512ceSopenharmony_cinamespace OHOS {
2948f512ceSopenharmony_cinamespace Developtools {
3048f512ceSopenharmony_cinamespace HiPerf {
3148f512ceSopenharmony_ci/*
3248f512ceSopenharmony_ciThis Class contains userspace thread objects. and kernel space objects
3348f512ceSopenharmony_ciIt represents a virtual operating environment, mainly referring to the relationship between pid,
3448f512ceSopenharmony_cimmaps, and symbols.
3548f512ceSopenharmony_ci
3648f512ceSopenharmony_ciIt mainly receives data is ip pointer (virtual address), pid
3748f512ceSopenharmony_ciAccording to these data, it will find the corresponding mmap and its corresponding elf (also called
3848f512ceSopenharmony_ciDSO)
3948f512ceSopenharmony_ci
4048f512ceSopenharmony_ciThen find the corresponding symbol in the corresponding elf symbol file according to the offset
4148f512ceSopenharmony_cirecorded in the corresponding mmap.
4248f512ceSopenharmony_ci*/
4348f512ceSopenharmony_ciusing kSymbolsHits = std::unordered_set<uint64_t>;
4448f512ceSopenharmony_ciusing uSymbolsHits = std::unordered_map<pid_t, std::unordered_set<uint64_t>>;
4548f512ceSopenharmony_ci
4648f512ceSopenharmony_ciclass VirtualRuntime {
4748f512ceSopenharmony_cipublic:
4848f512ceSopenharmony_ci    explicit VirtualRuntime(bool onDevice = true);
4948f512ceSopenharmony_ci    ~VirtualRuntime();
5048f512ceSopenharmony_ci    // thread need hook the record
5148f512ceSopenharmony_ci    // from the record , it will call back to write some Simulated Record
5248f512ceSopenharmony_ci    // case 1. some mmap will be create when it read mmaps for each new process (from record sample)
5348f512ceSopenharmony_ci
5448f512ceSopenharmony_ci    using RecordCallBack = std::function<bool(std::unique_ptr<PerfEventRecord>)>;
5548f512ceSopenharmony_ci    using CollectSymbolCallBack = std::function<void(PerfRecordSample*)>;
5648f512ceSopenharmony_ci
5748f512ceSopenharmony_ci    void SetRecordMode(RecordCallBack recordCallBack);
5848f512ceSopenharmony_ci    void SetCollectSymbolCallBack(CollectSymbolCallBack collectSymbolCallBack);
5948f512ceSopenharmony_ci
6048f512ceSopenharmony_ci    // this both used in report and record follow
6148f512ceSopenharmony_ci    // it process the record, and rebuild the trhread maps
6248f512ceSopenharmony_ci    // It internally determines whether to go to the Record process (which will generate virtual
6348f512ceSopenharmony_ci    // events) or the Report process by judging whether SetRecordMode has been passed.
6448f512ceSopenharmony_ci    void UpdateFromRecord(PerfEventRecord &record);
6548f512ceSopenharmony_ci    void NeedDropKernelCallChain(PerfRecordSample &sample);
6648f512ceSopenharmony_ci    // in reocrd mode
6748f512ceSopenharmony_ci    // we make a kernel symbols from some proc file
6848f512ceSopenharmony_ci    void UpdateKernelSpaceMaps();
6948f512ceSopenharmony_ci    void UpdateKernelModulesSpaceMaps();
7048f512ceSopenharmony_ci    void UpdateServiceSpaceMaps();
7148f512ceSopenharmony_ci    void UpdateDevhostSpaceMaps();
7248f512ceSopenharmony_ci    // load vdso
7348f512ceSopenharmony_ci    void LoadVdso();
7448f512ceSopenharmony_ci
7548f512ceSopenharmony_ci    void UpdateKernelSymbols();
7648f512ceSopenharmony_ci    void UpdateKernelModulesSymbols();
7748f512ceSopenharmony_ci    void UpdateServiceSymbols();
7848f512ceSopenharmony_ci    void UpdateDevhostSymbols();
7948f512ceSopenharmony_ci
8048f512ceSopenharmony_ci    pid_t devhostPid_ = -1;
8148f512ceSopenharmony_ci    void SetDevhostPid(pid_t devhost);
8248f512ceSopenharmony_ci    void FixHMBundleMmap(char *filename, int pid, u16 &headerSize);
8348f512ceSopenharmony_ci
8448f512ceSopenharmony_ci    // set symbols path , it will send to every symobile file for search
8548f512ceSopenharmony_ci    bool SetSymbolsPaths(const std::vector<std::string> &symbolsPaths);
8648f512ceSopenharmony_ci
8748f512ceSopenharmony_ci    // any mode
8848f512ceSopenharmony_ci    static_assert(sizeof(pid_t) == sizeof(int));
8948f512ceSopenharmony_ci
9048f512ceSopenharmony_ci    const std::vector<std::unique_ptr<SymbolsFile>> &GetSymbolsFiles() const
9148f512ceSopenharmony_ci    {
9248f512ceSopenharmony_ci        return symbolsFiles_;
9348f512ceSopenharmony_ci    }
9448f512ceSopenharmony_ci
9548f512ceSopenharmony_ci    const ProcessStackMap* GetUniStackTable()
9648f512ceSopenharmony_ci    {
9748f512ceSopenharmony_ci        return &processStackMap_;
9848f512ceSopenharmony_ci    }
9948f512ceSopenharmony_ci
10048f512ceSopenharmony_ci    void SetCallStackExpend(size_t mergeLevel = 0)
10148f512ceSopenharmony_ci    {
10248f512ceSopenharmony_ci        callstackMergeLevel_ = mergeLevel;
10348f512ceSopenharmony_ci    }
10448f512ceSopenharmony_ci
10548f512ceSopenharmony_ci    void SetDisableUnwind(bool disableUnwind)
10648f512ceSopenharmony_ci    {
10748f512ceSopenharmony_ci        HLOGV("disableUnwind change to %d", disableUnwind);
10848f512ceSopenharmony_ci        disableUnwind_ = disableUnwind;
10948f512ceSopenharmony_ci    }
11048f512ceSopenharmony_ci
11148f512ceSopenharmony_ci    void EnableDebugInfoSymbolic(bool enable)
11248f512ceSopenharmony_ci    {
11348f512ceSopenharmony_ci        enableDebugInfoSymbolic_ = enable;
11448f512ceSopenharmony_ci    }
11548f512ceSopenharmony_ci    void SetDedupStack()
11648f512ceSopenharmony_ci    {
11748f512ceSopenharmony_ci        dedupStack_ = true;
11848f512ceSopenharmony_ci    }
11948f512ceSopenharmony_ci
12048f512ceSopenharmony_ci    void ImportUniqueStackNodes(const std::vector<UniStackTableInfo>&);
12148f512ceSopenharmony_ci
12248f512ceSopenharmony_ci    bool isHM_ = false;
12348f512ceSopenharmony_ci    void SetHM(bool isHM)
12448f512ceSopenharmony_ci    {
12548f512ceSopenharmony_ci        isHM_ = isHM;
12648f512ceSopenharmony_ci    }
12748f512ceSopenharmony_ci
12848f512ceSopenharmony_ci    void SetNeedKernelCallChain(bool kernelCallChain)
12948f512ceSopenharmony_ci    {
13048f512ceSopenharmony_ci        needkernelCallChain_ = kernelCallChain;
13148f512ceSopenharmony_ci    }
13248f512ceSopenharmony_ci    DfxSymbol GetSymbol(uint64_t ip, pid_t pid, pid_t tid,
13348f512ceSopenharmony_ci                           const perf_callchain_context &context = PERF_CONTEXT_MAX);
13448f512ceSopenharmony_ci
13548f512ceSopenharmony_ci    VirtualThread &GetThread(pid_t pid, pid_t tid, const std::string name = "");
13648f512ceSopenharmony_ci    const std::map<pid_t, VirtualThread> &GetThreads() const
13748f512ceSopenharmony_ci    {
13848f512ceSopenharmony_ci        return userSpaceThreadMap_;
13948f512ceSopenharmony_ci    }
14048f512ceSopenharmony_ci    void SymbolicRecord(PerfRecordSample &recordSample);
14148f512ceSopenharmony_ci    void SymbolSpeRecord(PerfRecordAuxtrace &recordAuxTrace);
14248f512ceSopenharmony_ci
14348f512ceSopenharmony_ci    // report use
14448f512ceSopenharmony_ci    void UpdateFromPerfData(const std::vector<SymbolFileStruct> &);
14548f512ceSopenharmony_ci    void UnwindFromRecord(PerfRecordSample &recordSample);
14648f512ceSopenharmony_ci    std::string ReadThreadName(pid_t tid, bool isThread);
14748f512ceSopenharmony_ci    std::string ReadFromSavedCmdLines(pid_t tid);
14848f512ceSopenharmony_ci    bool IsKernelThread(pid_t pid);
14948f512ceSopenharmony_ci    void CollectDedupSymbol(kSymbolsHits &kernelSymbolsHits,
15048f512ceSopenharmony_ci                            uSymbolsHits &userSymbolsHits);
15148f512ceSopenharmony_ci    // debug time
15248f512ceSopenharmony_ci#ifdef HIPERF_DEBUG_TIME
15348f512ceSopenharmony_ci    std::chrono::microseconds updateSymbolsTimes_ = std::chrono::microseconds::zero();
15448f512ceSopenharmony_ci    std::chrono::microseconds unwindFromRecordTimes_ = std::chrono::microseconds::zero();
15548f512ceSopenharmony_ci    std::chrono::microseconds unwindCallStackTimes_ = std::chrono::microseconds::zero();
15648f512ceSopenharmony_ci    std::chrono::microseconds symbolicRecordTimes_ = std::chrono::microseconds::zero();
15748f512ceSopenharmony_ci    std::chrono::microseconds updateThreadTimes_ = std::chrono::microseconds::zero();
15848f512ceSopenharmony_ci    std::chrono::microseconds processSampleRecordTimes_ = std::chrono::microseconds::zero();
15948f512ceSopenharmony_ci    std::chrono::microseconds processMmapRecordTimes_ = std::chrono::microseconds::zero();
16048f512ceSopenharmony_ci    std::chrono::microseconds processMmap2RecordTimes_ = std::chrono::microseconds::zero();
16148f512ceSopenharmony_ci    std::chrono::microseconds processCommRecordTimes_ = std::chrono::microseconds::zero();
16248f512ceSopenharmony_ci    std::chrono::microseconds threadParseMapsTimes_ = std::chrono::microseconds::zero();
16348f512ceSopenharmony_ci    std::chrono::microseconds threadCreateMmapTimes_ = std::chrono::microseconds::zero();
16448f512ceSopenharmony_ci#endif
16548f512ceSopenharmony_ci    const bool loadSymboleWhenNeeded_ = true; // this is a feature config
16648f512ceSopenharmony_ci
16748f512ceSopenharmony_ciprivate:
16848f512ceSopenharmony_ci    bool needkernelCallChain_ = false;
16948f512ceSopenharmony_ci    bool disableUnwind_ = true;
17048f512ceSopenharmony_ci    bool enableDebugInfoSymbolic_ = false;
17148f512ceSopenharmony_ci    bool dedupStack_ = false;
17248f512ceSopenharmony_ci    size_t callstackMergeLevel_ = 1;
17348f512ceSopenharmony_ci    std::ifstream savedCmdLines_;
17448f512ceSopenharmony_ci#if defined(is_ohos) && is_ohos
17548f512ceSopenharmony_ci    CallStack callstack_;
17648f512ceSopenharmony_ci#endif
17748f512ceSopenharmony_ci    // pid map with user space thread
17848f512ceSopenharmony_ci    std::map<pid_t, VirtualThread> userSpaceThreadMap_;
17948f512ceSopenharmony_ci    // not pid , just memmap
18048f512ceSopenharmony_ci    std::vector<DfxMap> kernelSpaceMemMaps_;
18148f512ceSopenharmony_ci    ProcessStackMap processStackMap_;
18248f512ceSopenharmony_ci    RecordCallBack recordCallBack_;
18348f512ceSopenharmony_ci    CollectSymbolCallBack collectSymbolCallBack_;
18448f512ceSopenharmony_ci    std::vector<std::unique_ptr<SymbolsFile>> symbolsFiles_;
18548f512ceSopenharmony_ci    enum SymbolCacheLimit : std::size_t {
18648f512ceSopenharmony_ci        KERNEL_SYMBOL_CACHE_LIMIT = 4000,
18748f512ceSopenharmony_ci        USER_SYMBOL_CACHE_LIMIT = 4000,
18848f512ceSopenharmony_ci    };
18948f512ceSopenharmony_ci    HashList<uint64_t, DfxSymbol> userSymbolCache_;
19048f512ceSopenharmony_ci    HashList<uint64_t, DfxSymbol> kernelSymbolCache_ {KERNEL_SYMBOL_CACHE_LIMIT};
19148f512ceSopenharmony_ci    HashList<uint64_t, DfxSymbol> kThreadSymbolCache_ {KERNEL_SYMBOL_CACHE_LIMIT};
19248f512ceSopenharmony_ci    bool GetSymbolCache(uint64_t fileVaddr, DfxSymbol &symbol,
19348f512ceSopenharmony_ci                        const perf_callchain_context &context);
19448f512ceSopenharmony_ci    // find synbols function name
19548f512ceSopenharmony_ci    void MakeCallFrame(DfxSymbol &symbol, DfxFrame &callFrame);
19648f512ceSopenharmony_ci    void UpdateSymbols(std::shared_ptr<DfxMap> map, pid_t pid);
19748f512ceSopenharmony_ci    // we don't know whether hap vma mapping is stand for a so
19848f512ceSopenharmony_ci    // thus we need try to parse it first
19948f512ceSopenharmony_ci    bool UpdateHapSymbols(std::shared_ptr<DfxMap> map);
20048f512ceSopenharmony_ci    void UpdateFromRecord(PerfRecordSample &recordSample);
20148f512ceSopenharmony_ci    void UpdateFromRecord(PerfRecordMmap &recordMmap);
20248f512ceSopenharmony_ci    void UpdateFromRecord(PerfRecordMmap2 &recordMmap2);
20348f512ceSopenharmony_ci    void UpdateFromRecord(PerfRecordComm &recordComm);
20448f512ceSopenharmony_ci    void DedupFromRecord(PerfRecordSample *recordSample);
20548f512ceSopenharmony_ci    void UpdateFromRecord(PerfRecordAuxtrace &recordAuxTrace);
20648f512ceSopenharmony_ci    // threads
20748f512ceSopenharmony_ci    VirtualThread &UpdateThread(pid_t pid, pid_t tid, const std::string name = "");
20848f512ceSopenharmony_ci    VirtualThread &CreateThread(pid_t pid, pid_t tid, const std::string name = "");
20948f512ceSopenharmony_ci
21048f512ceSopenharmony_ci    // maps
21148f512ceSopenharmony_ci    std::shared_ptr<DfxMap> UpdateThreadMaps(pid_t pid, pid_t tid, const std::string filename, uint64_t begin,
21248f512ceSopenharmony_ci                          uint64_t len, uint64_t offset, uint32_t prot = 0);
21348f512ceSopenharmony_ci    void UpdatekernelMap(uint64_t begin, uint64_t end, uint64_t offset, std::string filename);
21448f512ceSopenharmony_ci
21548f512ceSopenharmony_ci    const DfxSymbol GetKernelSymbol(uint64_t ip, const std::vector<DfxMap> &memMaps,
21648f512ceSopenharmony_ci                                 const VirtualThread &thread);
21748f512ceSopenharmony_ci    const DfxSymbol GetUserSymbol(uint64_t ip, const VirtualThread &thread);
21848f512ceSopenharmony_ci    const DfxSymbol GetKernelThreadSymbol(uint64_t ip, const VirtualThread &thread);
21948f512ceSopenharmony_ci#ifdef HIPERF_DEBUG
22048f512ceSopenharmony_ci    std::unordered_set<uint64_t> missedRuntimeVaddr_;
22148f512ceSopenharmony_ci#endif
22248f512ceSopenharmony_ci    void SymbolicCallFrame(PerfRecordSample &recordSample, uint64_t ip,
22348f512ceSopenharmony_ci                           pid_t serverPid, perf_callchain_context context);
22448f512ceSopenharmony_ci    bool RecoverCallStack(PerfRecordSample &recordSample);
22548f512ceSopenharmony_ci    std::vector<std::string> symbolsPaths_;
22648f512ceSopenharmony_ci
22748f512ceSopenharmony_ci    // kernel thread
22848f512ceSopenharmony_ci    void UpdateKernelThreadMap(pid_t pid, uint64_t begin, uint64_t len, std::string filename);
22948f512ceSopenharmony_ci
23048f512ceSopenharmony_ci    FRIEND_TEST(VirtualRuntimeTest, SetRecordMode);
23148f512ceSopenharmony_ci    FRIEND_TEST(VirtualRuntimeTest, UpdateKernelSymbols);
23248f512ceSopenharmony_ci    FRIEND_TEST(VirtualRuntimeTest, UpdateKernelModulesSymbols);
23348f512ceSopenharmony_ci    FRIEND_TEST(VirtualRuntimeTest, SetCallStackExpend);
23448f512ceSopenharmony_ci    FRIEND_TEST(VirtualRuntimeTest, SetDisableUnwind);
23548f512ceSopenharmony_ci    FRIEND_TEST(VirtualRuntimeTest, UnwindFromRecord);
23648f512ceSopenharmony_ci    friend class VirtualRuntimeTest;
23748f512ceSopenharmony_ci
23848f512ceSopenharmony_ci    bool CheckValidSandBoxMmap(PerfRecordMmap2 &recordMmap2);
23948f512ceSopenharmony_ci};
24048f512ceSopenharmony_ci} // namespace HiPerf
24148f512ceSopenharmony_ci} // namespace Developtools
24248f512ceSopenharmony_ci} // namespace OHOS
24348f512ceSopenharmony_ci#endif // HIPERF_VIRTUAL_RUNTIME_H
244