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 "Runtime"
16
17#include "virtual_runtime.h"
18
19#include <cinttypes>
20#include <iostream>
21#include <sstream>
22#include <unistd.h>
23#if !is_mingw
24#include <sys/mman.h>
25#endif
26
27#include "dfx_map.h"
28#include "hiperf_hilog.h"
29#include "register.h"
30#include "spe_decoder.h"
31#include "symbols_file.h"
32#include "utilities.h"
33
34using namespace std::chrono;
35namespace OHOS {
36namespace Developtools {
37namespace HiPerf {
38namespace {
39// if ip is 0 , 1 both not useful
40const uint64_t BAD_IP_ADDRESS = 2;
41}
42// we unable to access 'swapper' from /proc/0/
43VirtualRuntime::VirtualRuntime(bool onDevice)
44{
45    UpdateThread(0, 0, "swapper");
46}
47
48VirtualRuntime::~VirtualRuntime()
49{
50    if (savedCmdLines_.is_open()) {
51        savedCmdLines_.close();
52    }
53}
54
55std::string VirtualRuntime::ReadFromSavedCmdLines(pid_t tid)
56{
57    if (!savedCmdLines_.is_open()) {
58        savedCmdLines_.open(SAVED_CMDLINES, std::ios::in);
59    }
60    if (!savedCmdLines_.is_open()) {
61        return EMPTY_STRING;
62    }
63    savedCmdLines_.seekg(0, std::ios::beg);
64    std::string line;
65    std::string threadid = std::to_string(tid);
66    while (getline(savedCmdLines_, line)) {
67        if (line.find(threadid) != std::string::npos) {
68            constexpr size_t sizeLimit {2};
69            std::vector<std::string> linesToken = StringSplit(line, " ");
70            if (linesToken.size() < sizeLimit) {
71                return EMPTY_STRING;
72            }
73            if (threadid != linesToken[0]) {
74                continue;
75            }
76            return linesToken[1];
77        }
78    }
79    return EMPTY_STRING;
80}
81
82std::string VirtualRuntime::ReadThreadName(pid_t tid, bool isThread)
83{
84    std::string comm = "";
85    if (tid == SYSMGR_PID) {
86        comm = SYSMGR_NAME;
87    } else if (tid == devhostPid_) {
88        comm = DEVHOST_FILE_NAME;
89    } else if (isThread) {
90        comm = ReadFileToString(StringPrintf("/proc/%d/comm", tid)).c_str();
91    } else {
92        comm = ReadFileToString(StringPrintf("/proc/%d/cmdline", tid)).c_str();
93    }
94    if (comm == EMPTY_STRING) {
95        comm = ReadFromSavedCmdLines(tid);
96    }
97    comm.erase(std::remove(comm.begin(), comm.end(), '\r'), comm.end());
98    comm.erase(std::remove(comm.begin(), comm.end(), '\n'), comm.end());
99    return comm;
100}
101
102VirtualThread &VirtualRuntime::UpdateThread(pid_t pid, pid_t tid, const std::string name)
103{
104#ifdef HIPERF_DEBUG_TIME
105    const auto startTime = steady_clock::now();
106#endif
107    VirtualThread &thread = GetThread(pid, tid, name);
108    if (!name.empty()) {
109        thread.name_ = name;
110    }
111#ifdef HIPERF_DEBUG_TIME
112    updateThreadTimes_ += duration_cast<microseconds>(steady_clock::now() - startTime);
113#endif
114    return thread;
115}
116
117VirtualThread &VirtualRuntime::CreateThread(pid_t pid, pid_t tid, const std::string name)
118{
119    // make a new one
120    if (pid == tid) {
121        userSpaceThreadMap_.emplace(std::piecewise_construct, std::forward_as_tuple(tid),
122                                    std::forward_as_tuple(pid, symbolsFiles_));
123    } else {
124        // for thread we need give it process info( for same mmap)
125        userSpaceThreadMap_.emplace(
126            std::piecewise_construct, std::forward_as_tuple(tid),
127            std::forward_as_tuple(pid, tid, GetThread(pid, pid), symbolsFiles_));
128    }
129    VirtualThread &thread = userSpaceThreadMap_.at(tid);
130    if (recordCallBack_) {
131        if (pid == tid && !IsKernelThread(pid)) {
132#ifdef HIPERF_DEBUG_TIME
133            const auto startTime = steady_clock::now();
134#endif
135            thread.ParseMap();
136#ifdef HIPERF_DEBUG_TIME
137            threadParseMapsTimes_ += duration_cast<microseconds>(steady_clock::now() - startTime);
138#endif
139        }
140#ifdef HIPERF_DEBUG_TIME
141        const auto startCreateMmapTime = steady_clock::now();
142#endif
143        thread.name_ = name;
144        if (thread.name_.empty()) {
145            thread.name_ = ReadThreadName(tid, pid != tid);
146        }
147        HLOGD("create a new thread record for %u:%u:%s with %zu dso", pid, tid,
148              thread.name_.c_str(), thread.GetMaps().size());
149        // we need make a PerfRecordComm
150        auto commRecord = std::make_unique<PerfRecordComm>(IsKernelThread(pid), pid, tid, thread.name_);
151        recordCallBack_(std::move(commRecord));
152        // only work for pid
153        if (pid == tid) {
154            if (isHM_) {
155                thread.FixHMBundleMap();
156            }
157            std::shared_ptr<DfxMap> prevMap = nullptr;
158            for (auto &map : thread.GetMaps()) {
159                // so in hap is load before start perf record
160                // dynamic load library should be treat in the same way
161                bool updateNormalSymbol = true;
162                if (map->name.find(".hap") != std::string::npos && (map->prots & PROT_EXEC)) {
163                    map->prevMap = prevMap;
164                    updateNormalSymbol = !UpdateHapSymbols(map);
165                    HLOGD("UpdateHapSymbols");
166                }
167                auto mmapRecord =
168                    std::make_unique<PerfRecordMmap2>(false, thread.pid_, thread.tid_, map);
169                HLOGD("make PerfRecordMmap2 %d:%d:%s:%s(0x%" PRIx64 "-0x%" PRIx64 ")@%" PRIx64 " ",
170                      thread.pid_, thread.tid_, thread.name_.c_str(), map->name.c_str(),
171                      map->begin, map->end, map->offset);
172                recordCallBack_(std::move(mmapRecord));
173                if (updateNormalSymbol) {
174                    UpdateSymbols(map, pid);
175                }
176                prevMap = map;
177            }
178        }
179        HLOGV("thread created");
180#ifdef HIPERF_DEBUG_TIME
181        threadCreateMmapTimes_ +=
182            duration_cast<microseconds>(steady_clock::now() - startCreateMmapTime);
183#endif
184    }
185    return thread;
186}
187
188bool VirtualRuntime::UpdateHapSymbols(std::shared_ptr<DfxMap> map)
189{
190    if (map == nullptr) {
191        return false;
192    }
193    HLOGV("hap name:%s", map->name.c_str());
194    // found it by name
195    auto symbolsFile = SymbolsFile::CreateSymbolsFile(map->name);
196    CHECK_TRUE(symbolsFile == nullptr, false, 1,
197               "Failed to load CreateSymbolsFile for exec section in hap(%s)", map->name.c_str());
198    symbolsFile->SetMapsInfo(map);
199    // update maps name if load debuginfo successfully
200    CHECK_TRUE(!symbolsFile->LoadDebugInfo(map), false, 1,
201               "Failed to load debuginfo for exec section in hap(%s)", map->name.c_str());
202
203    if (!loadSymboleWhenNeeded_) { // todo misspelling
204        symbolsFile->LoadSymbols(map);
205    }
206    symbolsFiles_.emplace_back(std::move(symbolsFile));
207    return true;
208}
209
210VirtualThread &VirtualRuntime::GetThread(pid_t pid, pid_t tid, const std::string name)
211{
212    if (userSpaceThreadMap_.find(pid) == userSpaceThreadMap_.end()) {
213        // no pid found
214        // create process first
215        CreateThread(pid, pid);
216    }
217
218    auto it = userSpaceThreadMap_.find(tid);
219    if (it == userSpaceThreadMap_.end()) {
220        // we also need thread
221        return CreateThread(pid, tid, name);
222    } else {
223        return it->second;
224    }
225}
226
227std::shared_ptr<DfxMap> VirtualRuntime::UpdateThreadMaps(pid_t pid, pid_t tid, const std::string filename,
228                                                         uint64_t begin, uint64_t len, uint64_t offset, uint32_t prot)
229{
230    VirtualThread &thread = GetThread(pid, tid);
231    std::shared_ptr<DfxMap> map = thread.CreateMapItem(filename, begin, len, offset, prot);
232    if (isHM_) {
233        thread.FixHMBundleMap();
234    }
235    return map;
236}
237
238void VirtualRuntime::UpdateKernelModulesSpaceMaps()
239{
240    // found the kernel modules
241    std::vector<DfxMap> koMaps;
242    std::ifstream ifs("/proc/modules", std::ifstream::in);
243    if (!ifs.is_open()) {
244        perror("kernel modules read failed(/proc/modules)\n");
245        return;
246    }
247    std::string line;
248    while (getline(ifs, line)) {
249        uint64_t addr = 0;
250        uint64_t size = 0;
251        char module[line.size()];
252        /*
253        name       size  load     map
254        hi_mipi_rx 53248 0 - Live 0xbf109000 (O)
255        hi3516cv500_hdmi 237568 0 - Live 0xbf0bb000 (O)
256        hifb 143360 0 - Live 0xbf089000 (O)
257        hi3516cv500_vo_dev 98304 0 - Live 0xbf070000 (O)
258        hi3516cv500_tde 110592 0 - Live 0xbf04a000 (O)
259        hi3516cv500_sys 36864 0 - Live 0xbf03a000 (O)
260        hi3516cv500_base 20480 5
261        hi_mipi_rx,hi3516cv500_hdmi,hifb,hi3516cv500_vo_dev,hi3516cv500_tde,hi3516cv500_sys,
262        hi3516cv500_base,sys_config,hi_proc,hi_irq,Live 0xbf000000 (O)
263        */
264        int ret = sscanf_s(line.c_str(), "%s%" PRIu64 "%*u%*s%*s 0x%" PRIx64 "", module,
265                           sizeof(module), &size, &addr, sizeof(addr));
266        constexpr int numSlices {3};
267        if (ret == numSlices) {
268            auto &map = koMaps.emplace_back(addr, addr + size, 0, "", std::string(module));
269            HLOGV("add ko map %s", map.ToString().c_str());
270        } else {
271            HLOGE("unknown line %d: '%s'", ret, line.c_str());
272        }
273    }
274
275    if (std::all_of(koMaps.begin(), koMaps.end(),
276                    [](const DfxMap &item) { return item.begin == 0; })) {
277        koMaps.clear();
278        HLOGW("no addr found in /proc/modules. remove all the ko");
279    }
280    if (recordCallBack_) {
281        for (const auto &map : koMaps) {
282            auto record = std::make_unique<PerfRecordMmap>(true, 0, 0, map.begin,
283                                                           map.end - map.begin, 0, map.name);
284            recordCallBack_(std::move(record));
285        }
286    }
287    std::move(koMaps.begin(), koMaps.end(), std::back_inserter(kernelSpaceMemMaps_));
288}
289
290void VirtualRuntime::UpdateKernelSpaceMaps()
291{
292    // add kernel first
293    auto &map = kernelSpaceMemMaps_.emplace_back(0, std::numeric_limits<uint64_t>::max(), 0, "", KERNEL_MMAP_NAME);
294    if (recordCallBack_) {
295        auto record = std::make_unique<PerfRecordMmap>(true, 0, 0, map.begin,
296                                                       map.end - map.begin, 0, map.name);
297        recordCallBack_(std::move(record));
298    }
299}
300
301void VirtualRuntime::UpdateKernelModulesSymbols()
302{
303    HLOGD("load ko symbol and build id");
304    for (auto &map : kernelSpaceMemMaps_) {
305        if (map.name == KERNEL_MMAP_NAME) {
306            continue;
307        }
308        auto kernelModuleFile = SymbolsFile::CreateSymbolsFile(SYMBOL_KERNEL_MODULE_FILE, map.name);
309        if (symbolsPaths_.size() > 0) {
310            kernelModuleFile->setSymbolsFilePath(symbolsPaths_); // also load from search path
311        }
312        kernelModuleFile->LoadSymbols();
313        symbolsFiles_.emplace_back(std::move(kernelModuleFile));
314    }
315}
316
317void VirtualRuntime::UpdateKernelSymbols()
318{
319    HLOGD("create a kernel mmap record");
320    // found kernel source
321    auto kernelFile = SymbolsFile::CreateSymbolsFile(KERNEL_MMAP_NAME);
322    // set symbol path If it exists
323    if (symbolsPaths_.size() > 0) {
324        kernelFile->setSymbolsFilePath(symbolsPaths_); // also load from search path
325    }
326    if (!IsRoot()) {
327        HLOGD("user mode do not load kernel syms");
328        printf("Hiperf is not running as root mode. Do not need load kernel syms\n");
329    }
330    if (kernelFile->LoadSymbols()) {
331        auto record = std::make_unique<PerfRecordMmap>(
332            true, 0, 0, kernelFile->textExecVaddr_, kernelFile->textExecVaddrRange_,
333            kernelFile->textExecVaddrFileOffset_, KERNEL_MMAP_NAME);
334
335        if (recordCallBack_) {
336            recordCallBack_(std::move(record));
337        }
338        symbolsFiles_.emplace_back(std::move(kernelFile));
339    } else {
340        HLOGW("kernel symbol not found.\n");
341    }
342}
343
344void VirtualRuntime::UpdatekernelMap(uint64_t begin, uint64_t end, uint64_t offset,
345                                     std::string filename)
346{
347    HLOGV("update kernel map name:'%s' 0x%" PRIx64 " - 0x%" PRIx64 "@0x%08" PRIx64 "",
348          filename.c_str(), begin, end, offset);
349
350    HLOG_ASSERT(!filename.empty());
351    auto it = find(kernelSpaceMemMaps_.begin(), kernelSpaceMemMaps_.end(), filename);
352    if (it == kernelSpaceMemMaps_.end()) {
353        kernelSpaceMemMaps_.emplace_back(begin, end, offset, "", filename);
354    } else {
355        it->begin = begin;
356        it->end = end;
357        it->offset = offset;
358        it->name = filename;
359    }
360}
361
362void VirtualRuntime::DedupFromRecord(PerfRecordSample *recordSample)
363{
364    CHECK_TRUE(recordSample == nullptr, NO_RETVAL, 0, "");
365    u64 nr = recordSample->data_.nr;
366    if (nr == 0) {
367        collectSymbolCallBack_(recordSample);
368        return;
369    }
370    u32 pid = recordSample->data_.pid;
371    u64 *ips = recordSample->data_.ips;
372    StackId stackId;
373    stackId.value = 0;
374    auto entry = processStackMap_.find(pid);
375    std::shared_ptr<UniqueStackTable> table = nullptr;
376    if (entry != processStackMap_.end()) {
377        table = entry->second;
378    } else {
379        table = std::make_shared<UniqueStackTable>(pid);
380        processStackMap_[pid] = table;
381    }
382    CHECK_TRUE(table == nullptr, NO_RETVAL, 0, "");
383    while (table->PutIpsInTable(&stackId, ips, nr) == 0) {
384        // try expand hashtable if collison can not resolved
385        if (!table->Resize()) {
386            HLOGW("Hashtable size limit, ip compress failed!");
387            collectSymbolCallBack_(recordSample);
388            return;
389        }
390    }
391    // callstack dedup success
392    recordSample->stackId_.value = stackId.value;
393    recordSample->header.size -= (sizeof(u64) * nr - sizeof(stackId));
394    recordSample->data_.nr = 0;
395    recordSample->data_.ips = nullptr;
396    recordSample->removeStack_ = true;
397}
398
399void VirtualRuntime::CollectDedupSymbol(kSymbolsHits &kernelSymbolsHits,
400                                        uSymbolsHits &userSymbolsHits)
401{
402    Node *node = nullptr;
403    Node *head = nullptr;
404    u32 pid;
405    for (const auto &tableEntry : processStackMap_) {
406        const auto &table = tableEntry.second;
407        if (table == nullptr) {
408            continue;
409        }
410        pid = table->GetPid();
411        head = table->GetHeadNode();
412        const auto &idxes = table->GetUsedIndexes();
413        for (const auto idx : idxes) {
414            node = head + idx;
415            if (node == nullptr) {
416                continue;
417            }
418            if (node->value != 0) {
419                if (node->section.inKernel) {
420                    uint64_t ip = node->section.ip | KERNEL_PREFIX;
421                    if (ip == PERF_CONTEXT_KERNEL || ip == PERF_CONTEXT_USER) {
422                        continue;
423                    }
424                    kernelSymbolsHits.insert(ip);
425                } else {
426                    userSymbolsHits[pid].insert(node->section.ip);
427                }
428            } else {
429                HLOGD("node value error 0x%x", idx);
430            }
431        }
432    }
433}
434
435void VirtualRuntime::UpdateFromRecord(PerfEventRecord &record)
436{
437#ifdef HIPERF_DEBUG_TIME
438    const auto startTime = steady_clock::now();
439#endif
440    if (record.GetType() == PERF_RECORD_SAMPLE) {
441        auto recordSample = static_cast<PerfRecordSample *>(&record);
442        UpdateFromRecord(*recordSample);
443#ifdef HIPERF_DEBUG_TIME
444        processSampleRecordTimes_ += duration_cast<microseconds>(steady_clock::now() - startTime);
445#endif
446    } else if (record.GetType() == PERF_RECORD_MMAP) {
447        auto recordMmap = static_cast<PerfRecordMmap *>(&record);
448        UpdateFromRecord(*recordMmap);
449#ifdef HIPERF_DEBUG_TIME
450        processMmapRecordTimes_ += duration_cast<microseconds>(steady_clock::now() - startTime);
451#endif
452    } else if (record.GetType() == PERF_RECORD_MMAP2) {
453        auto recordMmap2 = static_cast<PerfRecordMmap2 *>(&record);
454        UpdateFromRecord(*recordMmap2);
455#ifdef HIPERF_DEBUG_TIME
456        processMmap2RecordTimes_ += duration_cast<microseconds>(steady_clock::now() - startTime);
457#endif
458    } else if (record.GetType() == PERF_RECORD_COMM) {
459        auto recordComm = static_cast<PerfRecordComm *>(&record);
460        UpdateFromRecord(*recordComm);
461#ifdef HIPERF_DEBUG_TIME
462        processCommRecordTimes_ += duration_cast<microseconds>(steady_clock::now() - startTime);
463#endif
464    } else if (record.GetType() == PERF_RECORD_AUXTRACE) {
465        auto recordAuxTrace = static_cast<PerfRecordAuxtrace *>(&record);
466        UpdateFromRecord(*recordAuxTrace);
467#ifdef HIPERF_DEBUG_TIME
468        processCommRecordTimes_ += duration_cast<microseconds>(steady_clock::now() - startTime);
469#endif
470    } else {
471        HLOGW("skip record type %d", record.GetType());
472    }
473}
474
475void VirtualRuntime::MakeCallFrame(DfxSymbol &symbol, DfxFrame &callFrame)
476{
477    callFrame.funcOffset = symbol.funcVaddr_;
478    callFrame.mapOffset = symbol.offsetToVaddr_;
479    callFrame.symbolFileIndex = symbol.symbolFileIndex_;
480    callFrame.funcName = symbol.GetName();
481    if (callFrame.funcName.empty()) {
482        HLOGD("callFrame.funcName:%s, GetName:%s\n", callFrame.funcName.c_str(), symbol.GetName().data());
483    }
484
485    callFrame.index = static_cast<size_t>(symbol.index_);
486    callFrame.mapName = symbol.module_.empty() ? symbol.comm_ : symbol.module_;
487    HLOG_ASSERT_MESSAGE(!callFrame.funcName.empty(), "%s", symbol.ToDebugString().c_str());
488}
489
490void VirtualRuntime::SymbolicCallFrame(PerfRecordSample &recordSample, uint64_t ip,
491                                       pid_t serverPid, perf_callchain_context context)
492{
493    pid_t pid = static_cast<pid_t>(recordSample.data_.pid);
494    pid_t tid = static_cast<pid_t>(recordSample.data_.tid);
495    if (serverPid != pid) {
496        pid = tid = serverPid;
497    }
498    auto symbol = GetSymbol(ip, pid, tid, context);
499    MakeCallFrame(symbol, recordSample.callFrames_.emplace_back(ip, 0));
500    HLOGV(" (%zu)unwind symbol: %*s%s", recordSample.callFrames_.size(),
501          static_cast<int>(recordSample.callFrames_.size()), "",
502          recordSample.callFrames_.back().ToSymbolString().c_str());
503}
504
505bool VirtualRuntime::RecoverCallStack(PerfRecordSample &recordSample)
506{
507    auto StackTable = processStackMap_.find(recordSample.data_.pid);
508    CHECK_TRUE(StackTable == processStackMap_.end(), false, 1, "not found %" PRIu32 " pid", recordSample.data_.pid);
509    recordSample.ips_.clear();
510    if (StackTable->second != nullptr) {
511        StackTable->second->GetIpsByStackId(recordSample.stackId_, recordSample.ips_);
512    }
513    recordSample.RecoverCallStack();
514    return true;
515}
516
517void VirtualRuntime::SymbolicRecord(PerfRecordSample &recordSample)
518{
519#ifdef HIPERF_DEBUG_TIME
520    const auto startTime = steady_clock::now();
521#endif
522    // Symbolic the Call Stack
523    recordSample.callFrames_.clear();
524    perf_callchain_context context = PERF_CONTEXT_MAX;
525    pid_t serverPid;
526    if (recordSample.data_.nr == 0) {
527        serverPid = recordSample.GetServerPidof(0);
528        SymbolicCallFrame(recordSample, recordSample.data_.ip, serverPid, PERF_CONTEXT_MAX);
529    }
530    for (u64 i = 0; i < recordSample.data_.nr; i++) {
531        uint64_t ip = recordSample.data_.ips[i];
532        if (ip >= PERF_CONTEXT_MAX) {
533            std::string contextName = UpdatePerfContext(ip, context);
534            HLOGV("context switch to %s", contextName.c_str());
535            continue;
536        } else if (ip < BAD_IP_ADDRESS) {
537            // ip 0 or 1 or less than 0
538            continue;
539        }
540        serverPid = recordSample.GetServerPidof(i);
541        SymbolicCallFrame(recordSample, ip, serverPid, context);
542    }
543#ifdef HIPERF_DEBUG_TIME
544    auto usedTime = duration_cast<microseconds>(steady_clock::now() - startTime);
545    if (usedTime.count() != 0) {
546        HLOGV("cost %0.3f ms to symbolic ", usedTime.count() / MS_DURATION);
547    }
548    symbolicRecordTimes_ += usedTime;
549#endif
550}
551
552void VirtualRuntime::NeedDropKernelCallChain(PerfRecordSample &sample)
553{
554    // only do this in record mode.
555    if (recordCallBack_ == nullptr || needkernelCallChain_ ||
556        !sample.inKernel() || sample.data_.nr == 0) {
557        return;
558    }
559
560    u64 skip = 0;
561    u64 skipPid = 0;
562    u64 *ips = sample.data_.ips;
563    for (; skip < sample.data_.nr; skip++) {
564        if (ips[skip] == PERF_CONTEXT_KERNEL) {
565            skipPid++;
566        }
567        if (ips[skip] == PERF_CONTEXT_USER) {
568            break;
569        }
570    }
571    sample.skipKernel_ = skip;
572    sample.data_.nr -= skip;
573    sample.header.size -= sizeof(u64) * skip;
574    if (sample.data_.server_nr > 0) {
575        sample.skipPid_ = skipPid;
576        sample.data_.server_nr -= skipPid;
577        sample.header.size -= sizeof(u64) * skipPid;
578    }
579}
580
581void VirtualRuntime::UnwindFromRecord(PerfRecordSample &recordSample)
582{
583#if defined(is_ohos) && is_ohos
584#ifdef HIPERF_DEBUG_TIME
585    const auto startTime = steady_clock::now();
586#endif
587    HLOGV("unwind record (time:%llu)", recordSample.data_.time);
588    // if we have userstack ?
589    if (recordSample.data_.stack_size > 0) {
590        pid_t serverPid = recordSample.GetUstackServerPid();
591        pid_t pid = static_cast<pid_t>(recordSample.data_.pid);
592        pid_t tid = static_cast<pid_t>(recordSample.data_.tid);
593        if (serverPid != pid) {
594            pid = tid = serverPid;
595        }
596        auto &thread = UpdateThread(pid, tid);
597        callstack_.UnwindCallStack(thread, recordSample.data_.user_abi == PERF_SAMPLE_REGS_ABI_32,
598                                   recordSample.data_.user_regs, recordSample.data_.reg_nr,
599                                   recordSample.data_.stack_data, recordSample.data_.dyn_size,
600                                   recordSample.callFrames_);
601#ifdef HIPERF_DEBUG_TIME
602        unwindCallStackTimes_ += duration_cast<microseconds>(steady_clock::now() - startTime);
603#endif
604        size_t oldSize = recordSample.callFrames_.size();
605        HLOGV("unwind %zu", recordSample.callFrames_.size());
606        callstack_.ExpandCallStack(thread.tid_, recordSample.callFrames_, callstackMergeLevel_);
607        HLOGV("expand %zu (+%zu)", recordSample.callFrames_.size(),
608              recordSample.callFrames_.size() - oldSize);
609
610        recordSample.ReplaceWithCallStack(oldSize);
611    }
612
613#ifdef HIPERF_DEBUG_TIME
614    unwindFromRecordTimes_ += duration_cast<microseconds>(steady_clock::now() - startTime);
615#endif
616
617    NeedDropKernelCallChain(recordSample);
618    // we will not do this in non record mode.
619    if (dedupStack_ && recordCallBack_ != nullptr) {
620        DedupFromRecord(&recordSample);
621    }
622#endif
623
624    // we will not do this in record mode
625    if (recordCallBack_ == nullptr) {
626        if (dedupStack_ && recordSample.stackId_.section.id > 0 && recordSample.data_.nr == 0) {
627            RecoverCallStack(recordSample);
628        }
629        // find the symbols , reabuild frame info
630        SymbolicRecord(recordSample);
631    }
632}
633
634void VirtualRuntime::SetCollectSymbolCallBack(CollectSymbolCallBack collectSymbolCallBack)
635{
636    collectSymbolCallBack_ = collectSymbolCallBack;
637}
638
639void VirtualRuntime::UpdateFromRecord(PerfRecordSample &recordSample)
640{
641    UpdateThread(recordSample.data_.pid, recordSample.data_.tid);
642    if (recordSample.data_.server_nr) {
643        // update all server threads
644        for (size_t i = 0; i < recordSample.data_.server_nr; i++) {
645            pid_t pid = static_cast<pid_t>(recordSample.data_.server_pids[i]);
646            UpdateThread(pid, pid);
647        }
648    }
649    // unwind
650    if (disableUnwind_) {
651        return;
652    } else {
653        UnwindFromRecord(recordSample);
654    }
655}
656
657void VirtualRuntime::UpdateFromRecord(PerfRecordMmap &recordMmap)
658{
659    HLOGV("  MMAP: size %d pid %u tid %u", recordMmap.header.size, recordMmap.data_.pid,
660          recordMmap.data_.tid);
661    HLOGV("  MMAP: %s dso '%s' (0x%llx-0x%llx)@0x%llx", recordMmap.inKernel() ? "kernel" : "user",
662          recordMmap.data_.filename, recordMmap.data_.addr,
663          recordMmap.data_.addr + recordMmap.data_.len, recordMmap.data_.pgoff);
664    // kernel mmap
665    // don't overwrite the vailed mmap , so we also check the recordMmap.data_.len
666    if (IsKernelThread(recordMmap.data_.pid)) {
667        UpdateKernelThreadMap(recordMmap.data_.pid, recordMmap.data_.addr,
668                              recordMmap.data_.len, recordMmap.data_.filename);
669    } else if (recordMmap.inKernel()) {
670        UpdatekernelMap(recordMmap.data_.addr, recordMmap.data_.addr + recordMmap.data_.len,
671                        recordMmap.data_.pgoff, recordMmap.data_.filename);
672    } else {
673        NeedAdaptSandboxPath(recordMmap.data_.filename, recordMmap.data_.pid, recordMmap.header.size);
674        FixHMBundleMmap(recordMmap.data_.filename, recordMmap.data_.pid, recordMmap.header.size);
675        auto map = UpdateThreadMaps(recordMmap.data_.pid, recordMmap.data_.tid, recordMmap.data_.filename,
676                                    recordMmap.data_.addr, recordMmap.data_.len, recordMmap.data_.pgoff);
677        UpdateSymbols(map, recordMmap.data_.pid);
678    }
679}
680
681bool VirtualRuntime::CheckValidSandBoxMmap(PerfRecordMmap2 &recordMmap2)
682{
683    static std::shared_ptr<DfxMap> prevMap;
684    if ((recordMmap2.data_.prot & PROT_EXEC) != 0) {
685        // fake first segment, when second segment come.
686        auto symFile = SymbolsFile::CreateSymbolsFile(SYMBOL_ELF_FILE, recordMmap2.data_.filename);
687        CHECK_TRUE(symFile == nullptr, false, 1, "CheckValidSandBoxMmap Failed to create symbolFile!");
688
689        std::shared_ptr<DfxMap> curMap;
690        if (strstr(recordMmap2.data_.filename, ".hap") != nullptr) {
691            curMap = std::make_shared<DfxMap>(
692                recordMmap2.data_.addr,
693                recordMmap2.data_.addr + recordMmap2.data_.len,
694                recordMmap2.data_.pgoff,
695                "", // prot
696                recordMmap2.data_.filename
697            );
698            curMap->prevMap = prevMap;
699        }
700
701        CHECK_TRUE(!symFile->LoadDebugInfo(curMap), false, 1, "CheckValidSandBoxMmap Failed to load debuginfo!");
702
703        if (!loadSymboleWhenNeeded_) {
704            symFile->LoadSymbols(curMap);
705        }
706
707        if (strstr(recordMmap2.data_.filename, ".hap") == nullptr) {
708            auto elfLoadInfoMap = symFile->GetPtLoads();
709            u64 begin = recordMmap2.data_.addr - elfLoadInfoMap[0].mmapLen;
710            u64 len = elfLoadInfoMap[0].mmapLen;
711            u64 pgoff = elfLoadInfoMap[0].offset & (~(elfLoadInfoMap[0].align >= 1 ? elfLoadInfoMap[0].align - 1 : 0));
712            std::unique_ptr<PerfRecordMmap2> mmap2FirstSeg =
713                std::make_unique<PerfRecordMmap2>(recordMmap2.inKernel(), recordMmap2.data_.pid, recordMmap2.data_.tid,
714                begin, len, pgoff, 0, 0, 0, PROT_READ, 0, std::string(recordMmap2.data_.filename));
715            UpdateThreadMaps(mmap2FirstSeg->data_.pid, mmap2FirstSeg->data_.tid, mmap2FirstSeg->data_.filename,
716                mmap2FirstSeg->data_.addr, mmap2FirstSeg->data_.len, mmap2FirstSeg->data_.pgoff);
717            recordCallBack_(std::move(mmap2FirstSeg));
718        } else {
719            auto elfLoadInfoMap = symFile->GetPtLoads();
720            u64 begin = recordMmap2.data_.addr - elfLoadInfoMap[0].mmapLen;
721            u64 len = elfLoadInfoMap[0].mmapLen;
722            u64 pgoff = elfLoadInfoMap[0].offset &
723                        (~(elfLoadInfoMap[0].align >= 1 ? elfLoadInfoMap[0].align - 1 : 0));
724            std::unique_ptr<PerfRecordMmap2> mmap2FirstSeg =
725                std::make_unique<PerfRecordMmap2>(recordMmap2.inKernel(), recordMmap2.data_.pid, recordMmap2.data_.tid,
726                begin, len, pgoff, 0, 0, 0, PROT_READ, 0, curMap->name);
727            UpdateThreadMaps(mmap2FirstSeg->data_.pid, mmap2FirstSeg->data_.tid, curMap->name,
728                mmap2FirstSeg->data_.addr, mmap2FirstSeg->data_.len, mmap2FirstSeg->data_.pgoff);
729            recordCallBack_(std::move(mmap2FirstSeg));
730
731            std::unique_ptr<PerfRecordMmap2> mmap2SecondSegment =
732                std::make_unique<PerfRecordMmap2>(recordMmap2.inKernel(), recordMmap2.data_.pid, recordMmap2.data_.tid,
733                recordMmap2.data_.addr,
734                recordMmap2.data_.len,
735                recordMmap2.data_.pgoff - prevMap->offset, // minus load offset of hap
736                0, 0, 0, recordMmap2.data_.prot, 0, curMap->name);
737            UpdateThreadMaps(mmap2SecondSegment->data_.pid, mmap2SecondSegment->data_.tid, curMap->name,
738                mmap2SecondSegment->data_.addr, mmap2SecondSegment->data_.len, mmap2SecondSegment->data_.pgoff);
739            recordCallBack_(std::move(mmap2SecondSegment));
740            recordMmap2.discard_ = true;
741        }
742        symbolsFiles_.emplace_back(std::move(symFile));
743        return true;
744    } else if (recordMmap2.data_.pgoff == 0) {
745        recordMmap2.discard_ = true;
746    }
747
748    if (strstr(recordMmap2.data_.filename, ".hap") != nullptr) {
749        prevMap = std::make_shared<DfxMap>(
750            recordMmap2.data_.addr,
751            recordMmap2.data_.addr + recordMmap2.data_.len,
752            recordMmap2.data_.pgoff,
753            "", // prot
754            recordMmap2.data_.filename
755        );
756        HLOGD("CheckValidSandBoxMmap Update prev map!");
757    }
758    return !recordMmap2.discard_;
759}
760
761void VirtualRuntime::UpdateFromRecord(PerfRecordMmap2 &recordMmap2)
762{
763    if (!OHOS::HiviewDFX::DfxMaps::IsLegalMapItem(recordMmap2.data_.filename)) {
764        return;
765    }
766
767    HLOGV("  MMAP2: size %d pid %u tid %u", recordMmap2.header.size, recordMmap2.data_.pid,
768          recordMmap2.data_.tid);
769    HLOGV("  MMAP2: %s dso '%s' (0x%llx-0x%llx)@0x%llx prot:%u", recordMmap2.inKernel() ? "kernel" : "user",
770          recordMmap2.data_.filename, recordMmap2.data_.addr,
771          recordMmap2.data_.addr + recordMmap2.data_.len, recordMmap2.data_.pgoff, recordMmap2.data_.prot);
772
773    if (recordCallBack_) {
774        if (NeedAdaptSandboxPath(recordMmap2.data_.filename, recordMmap2.data_.pid, recordMmap2.header.size)) {
775            FixHMBundleMmap(recordMmap2.data_.filename, recordMmap2.data_.pid, recordMmap2.header.size);
776            CHECK_TRUE(!CheckValidSandBoxMmap(recordMmap2), NO_RETVAL, 0, "");
777        }
778    }
779    auto map = UpdateThreadMaps(recordMmap2.data_.pid, recordMmap2.data_.tid, recordMmap2.data_.filename,
780                                recordMmap2.data_.addr, recordMmap2.data_.len, recordMmap2.data_.pgoff,
781                                recordMmap2.data_.prot);
782    UpdateSymbols(map, recordMmap2.data_.pid);
783}
784
785void VirtualRuntime::UpdateFromRecord(PerfRecordComm &recordComm)
786{
787    recordComm.DumpLog(__FUNCTION__);
788    UpdateThread(recordComm.data_.pid, recordComm.data_.tid, recordComm.data_.comm);
789}
790
791void VirtualRuntime::UpdateFromRecord(PerfRecordAuxtrace &recordAuxTrace)
792{
793    if (recordCallBack_ == nullptr) {
794#if defined(is_ohos) && is_ohos
795        recordAuxTrace.DumpLog(__FUNCTION__);
796        SpeDecoder *decoder = SpeDecoderDataNew(recordAuxTrace.rawData_, recordAuxTrace.data_.size);
797        CHECK_TRUE(decoder == nullptr, NO_RETVAL, 0, "");
798        std::vector<SpeRecord> records;
799        while (true) {
800            int ret = SpeDecode(decoder);
801            if (ret <= 0) {
802                break;
803            }
804            struct SpeRecord record = SpeRecord(decoder->record);
805            records.emplace_back(record);
806        }
807        std::vector<ReportItemAuxRawData> auxRawData;
808        for (auto rec: records) {
809            u64 pc = 0;
810            if (rec.from_ip) {
811                pc = rec.from_ip;
812            } else if (rec.to_ip) {
813                pc = rec.to_ip;
814            } else {
815                continue;
816            }
817            DfxSymbol symbol = GetSymbol(pc, recordAuxTrace.data_.reserved__, recordAuxTrace.data_.tid);
818            HLOGV("pc 0x%llx symbol %s", pc, symbol.ToDebugString().c_str());
819            struct ReportItemAuxRawData reportItem = {rec.type, 0.0f, 1, symbol.comm_.data(), pc,
820                                                      symbol.module_.data(), symbol.GetName().data(),
821                                                      symbol.fileVaddr_};
822            auxRawData.emplace_back(reportItem);
823            HLOGV("type %u, from_ip: 0x%llx, to_ip: 0x%llx, timestamp: %llu, virt_addr: 0x%llx, phys_addr: 0x%llx",
824                  rec.type, rec.from_ip, rec.to_ip, rec.timestamp, rec.virt_addr, rec.phys_addr);
825        }
826        AddReportItems(auxRawData);
827        SpeDecoderFree(decoder);
828#endif
829    }
830}
831
832void VirtualRuntime::SymbolSpeRecord(PerfRecordAuxtrace &recordAuxTrace)
833{
834#if defined(is_ohos) && is_ohos
835    recordAuxTrace.DumpLog(__FUNCTION__);
836    SpeDecoder *decoder = SpeDecoderDataNew(recordAuxTrace.rawData_, recordAuxTrace.data_.size);
837    CHECK_TRUE(decoder == nullptr, NO_RETVAL, 0, "");
838    while (true) {
839        int ret = SpeDecode(decoder);
840        if (ret <= 0) {
841            break;
842        }
843        struct SpeRecord record = SpeRecord(decoder->record);
844        u64 pc = 0;
845        if (record.from_ip) {
846            pc = record.from_ip;
847        } else if (record.to_ip) {
848            pc = record.to_ip;
849        } else {
850            continue;
851        }
852
853        DfxSymbol symbol = GetSymbol(pc, recordAuxTrace.data_.reserved__, recordAuxTrace.data_.tid);
854        HLOGV("pc 0x%llx symbol %s", pc, symbol.ToDebugString().c_str());
855    }
856    SpeDecoderFree(decoder);
857#endif
858}
859
860void VirtualRuntime::SetRecordMode(RecordCallBack recordCallBack)
861{
862    recordCallBack_ = recordCallBack;
863}
864
865void VirtualRuntime::UpdateSymbols(std::shared_ptr<DfxMap> map, pid_t pid)
866{
867    CHECK_TRUE(map == nullptr || map->symbolFileIndex != -1, NO_RETVAL, 0, "");
868    HLOGD("try to find symbols for file: %s", map->name.c_str());
869    for (size_t i = 0; i < symbolsFiles_.size(); ++i) {
870        if (symbolsFiles_[i]->filePath_ == map->name) {
871            map->symbolFileIndex = static_cast<int32_t>(i);
872            HLOGV("already have '%s', symbol index:%zu", map->name.c_str(), i);
873            return;
874        }
875    }
876
877#ifdef HIPERF_DEBUG_TIME
878    const auto startTime = steady_clock::now();
879#endif
880    /**
881     * map[]     map.name = SymbolsFile.filePath_         prot    SymbolsFileType
882     * seg1      /data/storage/el1/bundle/entry.hap       r--p    ABC
883     * seg2      /data/storage/el1/bundle/entry.hap       r-xp    ELF
884     * seg3      /data/storage/el1/bundle/entry.hap       r--p    ABC
885     * seg4      /data/storage/el1/bundle/entry.hap       r--p    ABC
886     * seg1      /system/app/SceneBoard/SceneBoard.hap    r--p    ABC
887     * seg2      /system/app/SceneBoard/SceneBoard.hap    r--p    ABC
888     * seg3      /system/app/SceneBoard/SceneBoard.hap    r--p    ABC
889     * segN      .hap                                     r--p    .an/jit/etc
890     * 1.map.name == symbolsFile.filePath_
891     * 2.map.FileType == symbolsFiles_[map.symbolFileIndex]
892     * 3.cache pc->map->symbolsFiles[map.symbolFileIndex]
893     * 4.must ensure map.mapType assigned with SymbolsFile constructions at the same time.
894    */
895    auto symbolsFile = SymbolsFile::CreateSymbolsFile(map->name, pid);
896    symbolsFile->SetMapsInfo(map);
897    if (enableDebugInfoSymbolic_ && symbolsFile->symbolFileType_ == SymbolsFileType::SYMBOL_ELF_FILE) {
898        symbolsFile->EnableMiniDebugInfo();
899    }
900    // set symbol path If it exists
901    if (symbolsPaths_.size() > 0) {
902        // also load from search path
903        symbolsFile->setSymbolsFilePath(symbolsPaths_);
904    }
905    if (loadSymboleWhenNeeded_) {
906        // load it when we need it
907        symbolsFiles_.emplace_back(std::move(symbolsFile));
908    } else if (symbolsFile->LoadSymbols()) {
909        symbolsFiles_.emplace_back(std::move(symbolsFile));
910    } else {
911        HLOGW("symbols file for '%s' not found.", map->name.c_str());
912    }
913#ifdef HIPERF_DEBUG_TIME
914    auto usedTime = duration_cast<microseconds>(steady_clock::now() - startTime);
915    if (usedTime.count() != 0) {
916        HLOGV("cost %0.3f ms to load '%s'", usedTime.count() / MS_DURATION, map->name.c_str());
917    }
918    updateSymbolsTimes_ += usedTime;
919#endif
920}
921
922const DfxSymbol VirtualRuntime::GetKernelSymbol(uint64_t ip, const std::vector<DfxMap> &memMaps,
923                                                const VirtualThread &thread)
924{
925    DfxSymbol vaddrSymbol(ip, thread.name_);
926    for (auto &map : memMaps) {
927        if (ip > map.begin && ip < map.end) {
928            HLOGM("found addr 0x%" PRIx64 " in kernel map 0x%" PRIx64 " - 0x%" PRIx64 " from %s",
929                  ip, map.begin, map.end, map.name.c_str());
930            vaddrSymbol.module_ = map.name;
931            // found symbols by file name
932            for (auto &symbolsFile : symbolsFiles_) {
933                if (symbolsFile->filePath_ == map.name) {
934                    vaddrSymbol.symbolFileIndex_ = symbolsFile->id_;
935                    vaddrSymbol.fileVaddr_ =
936                        symbolsFile->GetVaddrInSymbols(ip, map.begin, map.offset);
937                    perf_callchain_context context = PERF_CONTEXT_KERNEL;
938                    if (GetSymbolCache(vaddrSymbol.fileVaddr_, vaddrSymbol, context)) {
939                        return vaddrSymbol;
940                    }
941                    HLOGV("found symbol vaddr 0x%" PRIx64 " for runtime vaddr 0x%" PRIx64
942                          " at '%s'",
943                          vaddrSymbol.fileVaddr_, ip, map.name.c_str());
944                    if (!symbolsFile->SymbolsLoaded()) {
945                        symbolsFile->LoadSymbols();
946                    }
947                    DfxSymbol foundSymbols = symbolsFile->GetSymbolWithVaddr(vaddrSymbol.fileVaddr_);
948                    foundSymbols.taskVaddr_ = ip;
949                    if (!foundSymbols.IsValid()) {
950                        HLOGW("addr 0x%" PRIx64 " vaddr  0x%" PRIx64 " NOT found in symbol file %s",
951                              ip, vaddrSymbol.fileVaddr_, map.name.c_str());
952                        return vaddrSymbol;
953                    } else {
954                        return foundSymbols;
955                    }
956                }
957            }
958            HLOGW("addr 0x%" PRIx64 " in map but NOT found the symbol file %s", ip,
959                  map.name.c_str());
960        } else {
961            HLOGM("addr 0x%" PRIx64 " not in map 0x%" PRIx64 " - 0x%" PRIx64 " from %s", ip,
962                  map.begin, map.end, map.name.c_str());
963        }
964    }
965    return vaddrSymbol;
966}
967
968const DfxSymbol VirtualRuntime::GetKernelThreadSymbol(uint64_t ip, const VirtualThread &thread)
969{
970    DfxSymbol vaddrSymbol(ip, thread.name_);
971    int64_t mapIndex = thread.FindMapIndexByAddr(ip);
972    if (mapIndex < 0) {
973        HLOGV("not found in any map");
974        return vaddrSymbol;
975    }
976
977    auto map = thread.GetMaps()[mapIndex];
978    CHECK_TRUE(map == nullptr, vaddrSymbol, 0, "");
979    HLOGM("found addr 0x%" PRIx64 " in kthread map 0x%" PRIx64 " - 0x%" PRIx64 " from %s",
980            ip, map->begin, map->end, map->name.c_str());
981    // found symbols by file name
982    for (auto &symbolsFile : symbolsFiles_) {
983        if (symbolsFile->filePath_ == map->name) {
984            vaddrSymbol.symbolFileIndex_ = symbolsFile->id_;
985            vaddrSymbol.module_ = map->name;
986            vaddrSymbol.fileVaddr_ =
987                symbolsFile->GetVaddrInSymbols(ip, map->begin, map->offset);
988            perf_callchain_context context = PERF_CONTEXT_MAX;
989            if (GetSymbolCache(vaddrSymbol.fileVaddr_, vaddrSymbol, context)) {
990                return vaddrSymbol;
991            }
992            HLOGV("found symbol vaddr 0x%" PRIx64 " for runtime vaddr 0x%" PRIx64 " at '%s'",
993                    vaddrSymbol.fileVaddr_, ip, map->name.c_str());
994            if (!symbolsFile->SymbolsLoaded()) {
995                symbolsFile->LoadDebugInfo();
996                symbolsFile->LoadSymbols(map);
997            }
998            auto foundSymbols = symbolsFile->GetSymbolWithVaddr(vaddrSymbol.fileVaddr_);
999            foundSymbols.taskVaddr_ = ip;
1000            if (!foundSymbols.IsValid()) {
1001                HLOGW("addr 0x%" PRIx64 " vaddr  0x%" PRIx64 " NOT found in symbol file %s",
1002                        ip, vaddrSymbol.fileVaddr_, map->name.c_str());
1003                return vaddrSymbol;
1004            } else {
1005                return foundSymbols;
1006            }
1007        }
1008    }
1009    HLOGW("addr 0x%" PRIx64 " in map but NOT found the symbol file %s", ip,
1010            map->name.c_str());
1011    return vaddrSymbol;
1012}
1013
1014const DfxSymbol VirtualRuntime::GetUserSymbol(uint64_t ip, const VirtualThread &thread)
1015{
1016    DfxSymbol vaddrSymbol(ip, thread.name_);
1017    int64_t mapIndex = thread.FindMapIndexByAddr(ip);
1018    if (mapIndex >= 0) {
1019        auto map = thread.GetMaps()[mapIndex];
1020        SymbolsFile *symbolsFile = thread.FindSymbolsFileByMap(map);
1021        if (symbolsFile != nullptr) {
1022            vaddrSymbol.symbolFileIndex_ = symbolsFile->id_;
1023            vaddrSymbol.module_ = map->name;
1024            vaddrSymbol.fileVaddr_ = symbolsFile->GetVaddrInSymbols(ip, map->begin, map->offset);
1025            perf_callchain_context context = PERF_CONTEXT_USER;
1026            if (GetSymbolCache(vaddrSymbol.fileVaddr_, vaddrSymbol, context)) {
1027                return vaddrSymbol;
1028            }
1029            HLOGV("found symbol vaddr 0x%" PRIx64 " for runtime vaddr 0x%" PRIx64 " at '%s'",
1030                  vaddrSymbol.fileVaddr_, ip, map->name.c_str());
1031            if (!symbolsFile->SymbolsLoaded()) {
1032                symbolsFile->LoadDebugInfo(map);
1033                symbolsFile->LoadSymbols(map);
1034            }
1035            DfxSymbol foundSymbols;
1036            if (!symbolsFile->IsAbc()) {
1037                foundSymbols = symbolsFile->GetSymbolWithVaddr(vaddrSymbol.fileVaddr_);
1038            } else {
1039                HLOGD("symbolsFile:%s is ABC :%d", symbolsFile->filePath_.c_str(), symbolsFile->IsAbc());
1040                foundSymbols = symbolsFile->GetSymbolWithPcAndMap(ip, map);
1041            }
1042
1043            if (foundSymbols.IsValid()) {
1044                return foundSymbols;
1045            } else {
1046                HLOGW("addr 0x%" PRIx64 " vaddr  0x%" PRIx64 " NOT found in symbol file %s", ip,
1047                      vaddrSymbol.fileVaddr_, map->name.c_str());
1048                if (symbolsFile->IsAbc()) {
1049                    symbolsFile->symbolsMap_.insert(std::make_pair(ip, vaddrSymbol));
1050                }
1051                return vaddrSymbol;
1052            }
1053        } else {
1054            HLOGW("addr 0x%" PRIx64 " in map but NOT found the symbol file %s", ip, map->name.c_str());
1055        }
1056    } else {
1057        HLOGV("not found in any map");
1058    }
1059    return vaddrSymbol;
1060}
1061
1062bool VirtualRuntime::GetSymbolCache(uint64_t fileVaddr, DfxSymbol &symbol,
1063                                    const perf_callchain_context &context)
1064{
1065    if (context == PERF_CONTEXT_MAX and kThreadSymbolCache_.count(fileVaddr)) {
1066        CHECK_TRUE(kThreadSymbolCache_.find(symbol.fileVaddr_) == kThreadSymbolCache_.end(), false, 0, "");
1067        symbol = kThreadSymbolCache_[symbol.fileVaddr_];
1068        symbol.hit_++;
1069        HLOGV("hit kernel thread cache 0x%" PRIx64 " %d", fileVaddr, symbol.hit_);
1070        return true;
1071    } else if (context != PERF_CONTEXT_USER and kernelSymbolCache_.count(fileVaddr)) {
1072        CHECK_TRUE(kernelSymbolCache_.find(symbol.fileVaddr_) == kernelSymbolCache_.end(), false, 0, "");
1073        symbol = kernelSymbolCache_[symbol.fileVaddr_];
1074        symbol.hit_++;
1075        HLOGV("hit kernel cache 0x%" PRIx64 " %d", fileVaddr, symbol.hit_);
1076        return true;
1077    } else if (userSymbolCache_.count(symbol.fileVaddr_) != 0) {
1078        const DfxSymbol &cachedSymbol = userSymbolCache_[symbol.fileVaddr_];
1079        // must be the same file
1080        if (cachedSymbol.module_ != symbol.module_) {
1081            return false;
1082        }
1083        symbol = cachedSymbol;
1084        symbol.hit_++;
1085        HLOGV("hit user cache 0x%" PRIx64 " %d %s", fileVaddr, symbol.hit_,
1086            symbol.ToDebugString().c_str());
1087        return true;
1088    } else {
1089        HLOGM("cache miss k %zu u %zu kt %zu", kernelSymbolCache_.size(),
1090              userSymbolCache_.size(), kThreadSymbolCache_.size());
1091    }
1092    return false;
1093}
1094
1095DfxSymbol VirtualRuntime::GetSymbol(uint64_t ip, pid_t pid, pid_t tid, const perf_callchain_context &context)
1096{
1097    HLOGV("try find tid %u ip 0x%" PRIx64 " in %zu symbolsFiles\n", tid, ip, symbolsFiles_.size());
1098    DfxSymbol symbol;
1099
1100    if (IsKernelThread(pid)) {
1101        VirtualThread &kthread = GetThread(pid, tid);
1102        HLOGM("try found addr in kernel thread %u with %zu maps", pid,
1103              kthread.GetMaps().size());
1104        symbol = GetKernelThreadSymbol(ip, kthread);
1105        HLOGM("add addr to kernel thread cache 0x%" PRIx64 " cache size %zu", ip,
1106              kThreadSymbolCache_.size());
1107        kThreadSymbolCache_[symbol.fileVaddr_] = symbol;
1108        if (symbol.IsValid()) {
1109            return symbol;
1110        }
1111    }
1112
1113    if (context == PERF_CONTEXT_USER or (context == PERF_CONTEXT_MAX and !symbol.IsValid())) {
1114        // check userspace memmap
1115        symbol = GetUserSymbol(ip, GetThread(pid, tid));
1116        if (userSymbolCache_.find(symbol.fileVaddr_) == userSymbolCache_.end()) {
1117            userSymbolCache_.reserve(USER_SYMBOL_CACHE_LIMIT);
1118        }
1119        userSymbolCache_[symbol.fileVaddr_] = symbol;
1120        HLOGV("cache ip 0x%" PRIx64 " to %s", ip,
1121              userSymbolCache_[symbol.fileVaddr_].ToDebugString().c_str());
1122    }
1123
1124    if (context == PERF_CONTEXT_KERNEL or (context == PERF_CONTEXT_MAX and !symbol.IsValid())) {
1125        // check kernelspace
1126        HLOGM("try found addr in kernelspace %zu maps", kernelSpaceMemMaps_.size());
1127        symbol = GetKernelSymbol(ip, kernelSpaceMemMaps_, GetThread(pid, tid));
1128        HLOGM("add addr to kernel cache 0x%" PRIx64 " cache size %zu", ip,
1129              kernelSymbolCache_.size());
1130        kernelSymbolCache_[symbol.fileVaddr_] = symbol;
1131    }
1132    return symbol;
1133}
1134
1135bool VirtualRuntime::SetSymbolsPaths(const std::vector<std::string> &symbolsPaths)
1136{
1137    std::unique_ptr<SymbolsFile> symbolsFile = SymbolsFile::CreateSymbolsFile(SYMBOL_UNKNOW_FILE);
1138    CHECK_TRUE(symbolsFile == nullptr, false, 0, "");
1139    // we need check if the path is accessible
1140    bool accessible = symbolsFile->setSymbolsFilePath(symbolsPaths);
1141    if (accessible) {
1142        symbolsPaths_ = symbolsPaths;
1143    } else {
1144        if (!symbolsPaths.empty()) {
1145            HLOGE("some symbols path unable access");
1146        }
1147    }
1148    return accessible;
1149}
1150
1151void VirtualRuntime::UpdateFromPerfData(const std::vector<SymbolFileStruct> &symbolFileStructs)
1152{
1153    // review: if we need move to some other place ?
1154    HLOG_ASSERT_MESSAGE(symbolsFiles_.size() == 0, " symbolsFiles_ size is %zu",
1155                        symbolsFiles_.size());
1156    for (const auto &symbolFileStruct : symbolFileStructs) {
1157        HLOGV("symbolFileStruct.filePath_:'%s'", symbolFileStruct.filePath_.c_str());
1158        HLOGV("symbolFileStruct.buildId_:'%s'", symbolFileStruct.buildId_.c_str());
1159        HLOGV("process symbols file:'%s':'%s'", symbolFileStruct.filePath_.c_str(),
1160              symbolFileStruct.buildId_.c_str());
1161
1162        // load from symbolFileStruct (perf.data)
1163        std::unique_ptr<SymbolsFile> symbolsFile = SymbolsFile::LoadSymbolsFromSaved(symbolFileStruct);
1164        if (symbolsFile == nullptr) {
1165            continue;
1166        }
1167        // reaload from sybol path If it exists
1168        if (symbolsPaths_.size() > 0) {
1169            HLOGV("try again with symbolsPaths setup");
1170            symbolsFile->setSymbolsFilePath(symbolsPaths_); // also load from search path
1171            // use give us path ,we must reload it.
1172            symbolsFile->LoadSymbols();
1173        }
1174        symbolsFile->id_ = static_cast<int32_t>(symbolsFiles_.size());
1175        symbolsFiles_.emplace_back(std::move(symbolsFile));
1176    }
1177}
1178
1179void VirtualRuntime::ImportUniqueStackNodes(const std::vector<UniStackTableInfo>& uniStackTableInfos)
1180{
1181    for (const UniStackTableInfo& item : uniStackTableInfos) {
1182        auto stackTable = std::make_shared<UniqueStackTable>(item.pid, item.tableSize);
1183        for (const UniStackNode& node : item.nodes) {
1184            stackTable->ImportNode(node.index, node.node);
1185        }
1186        processStackMap_[item.pid] = std::move(stackTable);
1187    }
1188}
1189
1190/*
1191   ARM functions
1192       The table below lists the symbols exported by the vDSO.
1193
1194       symbol                 version
1195       ────────────────────────────────────────────────────────────
1196       __vdso_gettimeofday    LINUX_2.6 (exported since Linux 4.1)
1197       __vdso_clock_gettime   LINUX_2.6 (exported since Linux 4.1)
1198
1199       Additionally, the ARM port has a code page full of utility
1200       functions.  Since it's just a raw page of code, there is no ELF
1201       information for doing symbol lookups or versioning.  It does
1202       provide support for different versions though.
1203
1204       For information on this code page, it's best to refer to the
1205       kernel documentation as it's extremely detailed and covers
1206       everything you need to know:
1207       Documentation/arm/kernel_user_helpers.txt.
1208
1209   aarch64 functions
1210       The table below lists the symbols exported by the vDSO.
1211
1212       symbol                   version
1213       ──────────────────────────────────────
1214       __kernel_rt_sigreturn    LINUX_2.6.39
1215       __kernel_gettimeofday    LINUX_2.6.39
1216       __kernel_clock_gettime   LINUX_2.6.39
1217       __kernel_clock_getres    LINUX_2.6.39
1218*/
1219void VirtualRuntime::LoadVdso()
1220{
1221#if !is_mingw
1222    VirtualThread myThread(getpid(), symbolsFiles_);
1223    myThread.ParseMap();
1224    for (const auto &map : myThread.GetMaps()) {
1225        if (map->IsVdsoMap()) {
1226            std::string memory(map->end - map->begin, '\0');
1227            std::copy(reinterpret_cast<char *>((map->begin)), reinterpret_cast<char *>((map->end)),
1228                      &memory[0]);
1229            std::string tempPath("/data/local/tmp/");
1230            std::string tempFileName = tempPath + map->name;
1231            if (!WriteStringToFile(tempFileName, memory)) {
1232                printf("vdso temp file create fail at %s\n", tempFileName.c_str());
1233            } else {
1234                HLOGD("vdso temp file create at %s:%zu", tempFileName.c_str(), memory.size());
1235                auto symbolsFile = SymbolsFile::CreateSymbolsFile(map->name);
1236                symbolsFile->setSymbolsFilePath(tempPath); // also load from search path
1237                symbolsFiles_.emplace_back(std::move(symbolsFile));
1238                return;
1239            }
1240        }
1241    }
1242    HLOGD("no vdso found");
1243#endif
1244}
1245
1246void VirtualRuntime::UpdateServiceSpaceMaps()
1247{
1248    VirtualThread &kthread = GetThread(SYSMGR_PID, SYSMGR_PID);
1249    kthread.ParseServiceMap(SYSMGR_FILE_NAME);
1250    if (recordCallBack_) {
1251        for (const auto &map : kthread.GetMaps()) {
1252            auto record =
1253            std::make_unique<PerfRecordMmap>(true, SYSMGR_PID, SYSMGR_PID,
1254                                             map->begin, map->end - map->begin,
1255                                             0, SYSMGR_FILE_NAME);
1256            recordCallBack_(std::move(record));
1257        }
1258    }
1259}
1260
1261void VirtualRuntime::UpdateServiceSymbols()
1262{
1263    HLOGD("try to update kernel thread symbols for kernel service");
1264    std::string fileName = SYSMGR_FILE_NAME;
1265    auto symbolsFile = SymbolsFile::CreateSymbolsFile(SYMBOL_KERNEL_THREAD_FILE, fileName);
1266
1267    HLOGD("add kernel service symbol file: %s", fileName.c_str());
1268    if (symbolsFile->LoadSymbols()) {
1269        symbolsFiles_.emplace_back(std::move(symbolsFile));
1270    } else {
1271        HLOGW("symbols file for '%s' not found.", fileName.c_str());
1272    }
1273}
1274
1275void VirtualRuntime::UpdateKernelThreadMap(pid_t pid, uint64_t begin, uint64_t len,
1276                                           std::string filename)
1277{
1278    HLOGV("update kernel thread map pid %u name:'%s'", pid, filename.c_str());
1279
1280    VirtualThread &thread = GetThread(pid, pid);
1281    thread.CreateMapItem(filename, begin, len, 0u);
1282}
1283
1284void VirtualRuntime::UpdateDevhostSpaceMaps()
1285{
1286    VirtualThread &kthread = GetThread(devhostPid_, devhostPid_);
1287    kthread.ParseDevhostMap(devhostPid_);
1288    if (recordCallBack_) {
1289        for (const auto &map : kthread.GetMaps()) {
1290            auto record =
1291            std::make_unique<PerfRecordMmap>(false, devhostPid_, devhostPid_,
1292                                             map->begin, map->end - map->begin,
1293                                             0, map->name);
1294            recordCallBack_(std::move(record));
1295        }
1296    }
1297}
1298
1299void VirtualRuntime::UpdateDevhostSymbols()
1300{
1301    HLOGD("try to update kernel thread symbols for devhost");
1302    auto kallsyms = SymbolsFile::CreateSymbolsFile(SYMBOL_KERNEL_THREAD_FILE, DEVHOST_FILE_NAME);
1303    // file name of devhost.ko
1304    std::map<std::string_view, std::unique_ptr<SymbolsFile>> koMaps;
1305    koMaps[DEVHOST_FILE_NAME] =
1306        SymbolsFile::CreateSymbolsFile(SYMBOL_KERNEL_THREAD_FILE, DEVHOST_LINUX_FILE_NAME);
1307
1308    if (kallsyms->LoadSymbols()) {
1309        for (auto &symbol : kallsyms->GetSymbols()) {
1310            if (koMaps.find(symbol.module_) == koMaps.end()) {
1311                std::string filename = std::string(symbol.module_);
1312                // [devhost] to /liblinux/devhost.ko
1313                filename.erase(filename.begin());
1314                filename.erase(filename.end() - 1);
1315                filename = DEVHOST_LINUX_PREFIX + filename + KERNEL_MODULES_EXT_NAME;
1316                koMaps[symbol.module_] =
1317                    SymbolsFile::CreateSymbolsFile(SYMBOL_KERNEL_THREAD_FILE, filename);
1318            }
1319            if (koMaps[symbol.module_] == nullptr) {
1320                continue;
1321            }
1322            koMaps[symbol.module_]->AddSymbol(std::move(symbol));
1323        }
1324
1325        HLOGD("devhost loaded %zu symbolfiles", koMaps.size());
1326        for (auto &it : koMaps) {
1327            if (it.second == nullptr) {
1328                continue;
1329            }
1330            HLOGD("Load %zu symbols to %s", it.second->GetSymbols().size(),
1331                  it.second->filePath_.c_str());
1332            symbolsFiles_.emplace_back(std::move(it.second));
1333        }
1334    } else {
1335        HLOGW("symbols file for devhost parse failed.");
1336    }
1337
1338    // update normal symbole files
1339    VirtualThread &kthread = GetThread(devhostPid_, devhostPid_);
1340    for (const auto &map : kthread.GetMaps()) {
1341        UpdateSymbols(map, devhostPid_);
1342    }
1343}
1344
1345void VirtualRuntime::FixHMBundleMmap(char *filename, int pid, u16 &headerSize)
1346{
1347    if (!isHM_) {
1348        return;
1349    }
1350    // fix bundle path in mmap
1351    std::string newFilename = filename;
1352    VirtualThread &thread = GetThread(pid, pid);
1353    if (NeedAdaptHMBundlePath(newFilename, thread.name_)) {
1354        size_t oldSize = strlen(filename);
1355        (void)memset_s(filename, KILO, '\0', KILO);
1356        if (strncpy_s(filename, KILO, newFilename.c_str(), newFilename.size()) != 0) {
1357            HLOGD("strncpy_s recordMmap2 failed!");
1358        }
1359        headerSize += newFilename.size() - oldSize;
1360    }
1361}
1362
1363void VirtualRuntime::SetDevhostPid(pid_t devhost)
1364{
1365    HLOGD("Set devhost pid: %d", devhost);
1366    devhostPid_ = devhost;
1367}
1368
1369bool VirtualRuntime::IsKernelThread(pid_t pid)
1370{
1371    if (!isHM_) {
1372        return false;
1373    }
1374    return pid == SYSMGR_PID || pid == devhostPid_;
1375}
1376
1377} // namespace HiPerf
1378} // namespace Developtools
1379} // namespace OHOS
1380