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#define HILOG_TAG "Dump"
1648f512ceSopenharmony_ci
1748f512ceSopenharmony_ci#include "subcommand_dump.h"
1848f512ceSopenharmony_ci
1948f512ceSopenharmony_ci#include <cerrno>
2048f512ceSopenharmony_ci#include <cinttypes>
2148f512ceSopenharmony_ci#include <cstring>
2248f512ceSopenharmony_ci#include <iostream>
2348f512ceSopenharmony_ci#include <memory>
2448f512ceSopenharmony_ci
2548f512ceSopenharmony_ci#include "debug_logger.h"
2648f512ceSopenharmony_ci#include "hiperf_hilog.h"
2748f512ceSopenharmony_ci#include "option.h"
2848f512ceSopenharmony_ci#include "perf_event_record.h"
2948f512ceSopenharmony_ci#include "perf_events.h"
3048f512ceSopenharmony_ci#include "register.h"
3148f512ceSopenharmony_ci#include "spe_decoder.h"
3248f512ceSopenharmony_ci#include "symbols_file.h"
3348f512ceSopenharmony_ci#include "utilities.h"
3448f512ceSopenharmony_ci#include "virtual_runtime.h"
3548f512ceSopenharmony_ci
3648f512ceSopenharmony_cinamespace OHOS {
3748f512ceSopenharmony_cinamespace Developtools {
3848f512ceSopenharmony_cinamespace HiPerf {
3948f512ceSopenharmony_ciusing namespace OHOS::HiviewDFX;
4048f512ceSopenharmony_ci
4148f512ceSopenharmony_cistatic const std::string DEFAULT_DUMP_FILENAME = "perf.data";
4248f512ceSopenharmony_ci
4348f512ceSopenharmony_cibool SubCommandDump::CheckInputFile()
4448f512ceSopenharmony_ci{
4548f512ceSopenharmony_ci    if (!dumpFileName_.empty()) {
4648f512ceSopenharmony_ci        if (elfFileName_.empty() && protobufDumpFileName_.empty()) {
4748f512ceSopenharmony_ci            return true;
4848f512ceSopenharmony_ci        }
4948f512ceSopenharmony_ci    } else if (!elfFileName_.empty()) {
5048f512ceSopenharmony_ci        if (protobufDumpFileName_.empty()) {
5148f512ceSopenharmony_ci            return true;
5248f512ceSopenharmony_ci        }
5348f512ceSopenharmony_ci    } else if (!protobufDumpFileName_.empty()) {
5448f512ceSopenharmony_ci        return true;
5548f512ceSopenharmony_ci    } else { // all is empty
5648f512ceSopenharmony_ci        dumpFileName_ = DEFAULT_DUMP_FILENAME;
5748f512ceSopenharmony_ci        return true;
5848f512ceSopenharmony_ci    }
5948f512ceSopenharmony_ci
6048f512ceSopenharmony_ci    printf("options conflict, please check usage\n");
6148f512ceSopenharmony_ci    return false;
6248f512ceSopenharmony_ci}
6348f512ceSopenharmony_ci
6448f512ceSopenharmony_cibool SubCommandDump::ParseOption(std::vector<std::string> &args)
6548f512ceSopenharmony_ci{
6648f512ceSopenharmony_ci    if (!Option::GetOptionValue(args, "--head", dumpHeader_)) {
6748f512ceSopenharmony_ci        HLOGD("get option --head failed");
6848f512ceSopenharmony_ci        return false;
6948f512ceSopenharmony_ci    }
7048f512ceSopenharmony_ci    if (!Option::GetOptionValue(args, "-f", dumpFeatures_)) {
7148f512ceSopenharmony_ci        HLOGD("get option -f failed");
7248f512ceSopenharmony_ci        return false;
7348f512ceSopenharmony_ci    }
7448f512ceSopenharmony_ci    if (!Option::GetOptionValue(args, "-d", dumpData_)) {
7548f512ceSopenharmony_ci        HLOGD("get option -d failed");
7648f512ceSopenharmony_ci        return false;
7748f512ceSopenharmony_ci    }
7848f512ceSopenharmony_ci    if (!Option::GetOptionValue(args, "--sympath", dumpSymbolsPaths_)) {
7948f512ceSopenharmony_ci        HLOGD("get option --sympath failed");
8048f512ceSopenharmony_ci        return false;
8148f512ceSopenharmony_ci    }
8248f512ceSopenharmony_ci    if (!Option::GetOptionValue(args, "--elf", elfFileName_)) {
8348f512ceSopenharmony_ci        HLOGD("get option --elf failed");
8448f512ceSopenharmony_ci        return false;
8548f512ceSopenharmony_ci    }
8648f512ceSopenharmony_ci    if (!Option::GetOptionValue(args, "-i", dumpFileName_)) {
8748f512ceSopenharmony_ci        return false;
8848f512ceSopenharmony_ci    }
8948f512ceSopenharmony_ci#if defined(HAVE_PROTOBUF) && HAVE_PROTOBUF
9048f512ceSopenharmony_ci    if (!Option::GetOptionValue(args, "--proto", protobufDumpFileName_)) {
9148f512ceSopenharmony_ci        HLOGD("get option --proto failed");
9248f512ceSopenharmony_ci        return false;
9348f512ceSopenharmony_ci    }
9448f512ceSopenharmony_ci#endif
9548f512ceSopenharmony_ci    if (!Option::GetOptionValue(args, "-o", outputFilename_)) {
9648f512ceSopenharmony_ci        return false;
9748f512ceSopenharmony_ci    }
9848f512ceSopenharmony_ci    if (!Option::GetOptionValue(args, "--export", exportSampleIndex_)) {
9948f512ceSopenharmony_ci        HLOGD("get option --export failed");
10048f512ceSopenharmony_ci        return false;
10148f512ceSopenharmony_ci    }
10248f512ceSopenharmony_ci
10348f512ceSopenharmony_ci    if (dumpHeader_ || dumpFeatures_ || dumpData_) {
10448f512ceSopenharmony_ci        dumpAll_ = false;
10548f512ceSopenharmony_ci    }
10648f512ceSopenharmony_ci    if (!args.empty()) {
10748f512ceSopenharmony_ci        printf("'%s' option usage error, please check usage.\n", VectorToString(args).c_str());
10848f512ceSopenharmony_ci        return false;
10948f512ceSopenharmony_ci    }
11048f512ceSopenharmony_ci
11148f512ceSopenharmony_ci    return CheckInputFile();
11248f512ceSopenharmony_ci}
11348f512ceSopenharmony_ci
11448f512ceSopenharmony_cibool SubCommandDump::PrepareDumpOutput()
11548f512ceSopenharmony_ci{
11648f512ceSopenharmony_ci    if (outputFilename_.empty()) {
11748f512ceSopenharmony_ci        return true;
11848f512ceSopenharmony_ci    }
11948f512ceSopenharmony_ci    std::string resolvedPath = CanonicalizeSpecPath(outputFilename_.c_str());
12048f512ceSopenharmony_ci    g_outputDump = fopen(resolvedPath.c_str(), "w");
12148f512ceSopenharmony_ci    if (g_outputDump == nullptr) {
12248f512ceSopenharmony_ci        printf("unable open file to '%s' because '%d'\n", outputFilename_.c_str(), errno);
12348f512ceSopenharmony_ci        return false;
12448f512ceSopenharmony_ci    }
12548f512ceSopenharmony_ci    printf("dump result will save at '%s'\n", outputFilename_.c_str());
12648f512ceSopenharmony_ci    return true;
12748f512ceSopenharmony_ci}
12848f512ceSopenharmony_ci
12948f512ceSopenharmony_ciSubCommandDump::~SubCommandDump()
13048f512ceSopenharmony_ci{
13148f512ceSopenharmony_ci    if (g_outputDump != nullptr && g_outputDump != stdout) {
13248f512ceSopenharmony_ci        fclose(g_outputDump);
13348f512ceSopenharmony_ci    }
13448f512ceSopenharmony_ci    SymbolsFile::onRecording_ = true; // back to default for UT
13548f512ceSopenharmony_ci}
13648f512ceSopenharmony_ci
13748f512ceSopenharmony_cibool SubCommandDump::OnSubCommand(std::vector<std::string> &args)
13848f512ceSopenharmony_ci{
13948f512ceSopenharmony_ci    if (!PrepareDumpOutput()) {
14048f512ceSopenharmony_ci        return false;
14148f512ceSopenharmony_ci    }
14248f512ceSopenharmony_ci
14348f512ceSopenharmony_ci    if (!elfFileName_.empty()) {
14448f512ceSopenharmony_ci        return DumpElfFile();
14548f512ceSopenharmony_ci    }
14648f512ceSopenharmony_ci
14748f512ceSopenharmony_ci#if defined(HAVE_PROTOBUF) && HAVE_PROTOBUF
14848f512ceSopenharmony_ci    if (!protobufDumpFileName_.empty()) {
14948f512ceSopenharmony_ci        return DumpProtoFile();
15048f512ceSopenharmony_ci    }
15148f512ceSopenharmony_ci#endif
15248f512ceSopenharmony_ci
15348f512ceSopenharmony_ci    if (access(dumpFileName_.c_str(), F_OK) != 0) {
15448f512ceSopenharmony_ci        printf("Can not access data file %s\n", dumpFileName_.c_str());
15548f512ceSopenharmony_ci        return false;
15648f512ceSopenharmony_ci    }
15748f512ceSopenharmony_ci    // only one file should created
15848f512ceSopenharmony_ci    HLOG_ASSERT_MESSAGE(reader_ == nullptr, " perf file reader for %s\n", dumpFileName_.c_str());
15948f512ceSopenharmony_ci    reader_ = PerfFileReader::Instance(dumpFileName_);
16048f512ceSopenharmony_ci    if (reader_ == nullptr) {
16148f512ceSopenharmony_ci        HLOGE("HiperfFileReader::Instance(%s) return null", dumpFileName_.c_str());
16248f512ceSopenharmony_ci        return false;
16348f512ceSopenharmony_ci    }
16448f512ceSopenharmony_ci
16548f512ceSopenharmony_ci    // any way tell symbols this is not on device
16648f512ceSopenharmony_ci    SymbolsFile::onRecording_ = false;
16748f512ceSopenharmony_ci    // we need unwind it (for function name match) even not give us path
16848f512ceSopenharmony_ci    vr_.SetDisableUnwind(false);
16948f512ceSopenharmony_ci
17048f512ceSopenharmony_ci    if (!dumpSymbolsPaths_.empty()) {
17148f512ceSopenharmony_ci        // user give us path , we enable unwind
17248f512ceSopenharmony_ci        if (!vr_.SetSymbolsPaths(dumpSymbolsPaths_)) {
17348f512ceSopenharmony_ci            printf("Failed to set symbol path(%s)\n", VectorToString(dumpSymbolsPaths_).c_str());
17448f512ceSopenharmony_ci            return false;
17548f512ceSopenharmony_ci        }
17648f512ceSopenharmony_ci    }
17748f512ceSopenharmony_ci
17848f512ceSopenharmony_ci    if (dumpHeader_ || dumpAll_) {
17948f512ceSopenharmony_ci        DumpPrintFileHeader(indent_);
18048f512ceSopenharmony_ci        DumpAttrPortion(indent_);
18148f512ceSopenharmony_ci    }
18248f512ceSopenharmony_ci
18348f512ceSopenharmony_ci    if (dumpAll_ || dumpData_) {
18448f512ceSopenharmony_ci        // before load data section
18548f512ceSopenharmony_ci        SetHM();
18648f512ceSopenharmony_ci        DumpDataPortion(indent_);
18748f512ceSopenharmony_ci        DumpSpeReport();
18848f512ceSopenharmony_ci    }
18948f512ceSopenharmony_ci
19048f512ceSopenharmony_ci    if (dumpFeatures_ || dumpAll_) {
19148f512ceSopenharmony_ci        DumpFeaturePortion(indent_);
19248f512ceSopenharmony_ci    }
19348f512ceSopenharmony_ci
19448f512ceSopenharmony_ci    return true;
19548f512ceSopenharmony_ci}
19648f512ceSopenharmony_ci
19748f512ceSopenharmony_cibool SubCommandDump::DumpElfFile()
19848f512ceSopenharmony_ci{
19948f512ceSopenharmony_ci    printf("dump elf: '%s'\n", elfFileName_.c_str());
20048f512ceSopenharmony_ci    auto elf = SymbolsFile::CreateSymbolsFile(elfFileName_);
20148f512ceSopenharmony_ci    if (!elf->LoadSymbols(nullptr, "")) {
20248f512ceSopenharmony_ci        printf("load elf failed.\n");
20348f512ceSopenharmony_ci        return false;
20448f512ceSopenharmony_ci    } else {
20548f512ceSopenharmony_ci        printf("load elf succeed.\n");
20648f512ceSopenharmony_ci    }
20748f512ceSopenharmony_ci    return true;
20848f512ceSopenharmony_ci}
20948f512ceSopenharmony_ci#if defined(HAVE_PROTOBUF) && HAVE_PROTOBUF
21048f512ceSopenharmony_cibool SubCommandDump::DumpProtoFile()
21148f512ceSopenharmony_ci{
21248f512ceSopenharmony_ci    printf("dump protobuf file: '%s'\n", protobufDumpFileName_.c_str());
21348f512ceSopenharmony_ci    protobufInputFileReader_ = std::make_unique<ReportProtobufFileReader>();
21448f512ceSopenharmony_ci    if (!protobufInputFileReader_->Dump(protobufDumpFileName_)) {
21548f512ceSopenharmony_ci        printf("load proto failed.\n");
21648f512ceSopenharmony_ci        return false;
21748f512ceSopenharmony_ci    }
21848f512ceSopenharmony_ci    return true;
21948f512ceSopenharmony_ci}
22048f512ceSopenharmony_ci#endif
22148f512ceSopenharmony_ci
22248f512ceSopenharmony_civoid SubCommandDump::PrintHeaderInfo(const int &indent)
22348f512ceSopenharmony_ci{
22448f512ceSopenharmony_ci    const perf_file_header &header = reader_->GetHeader();
22548f512ceSopenharmony_ci    // magic
22648f512ceSopenharmony_ci    PRINT_INDENT(indent, "magic: ");
22748f512ceSopenharmony_ci    for (size_t i = 0; i < sizeof(header.magic); ++i) {
22848f512ceSopenharmony_ci        PRINT_INDENT(indent, "%c", header.magic[i]);
22948f512ceSopenharmony_ci    }
23048f512ceSopenharmony_ci    PRINT_INDENT(indent, "\n");
23148f512ceSopenharmony_ci    PRINT_INDENT(indent, "header_size: %" PRId64 "\n", header.size);
23248f512ceSopenharmony_ci    if (header.size != sizeof(header)) {
23348f512ceSopenharmony_ci        HLOGW("record file header size doesn't match");
23448f512ceSopenharmony_ci    }
23548f512ceSopenharmony_ci    PRINT_INDENT(indent, "attr_size: %" PRId64 "\n", header.attrSize);
23648f512ceSopenharmony_ci    if (header.attrSize != sizeof(perf_file_attr)) {
23748f512ceSopenharmony_ci        HLOGW("attr size doesn't match");
23848f512ceSopenharmony_ci    }
23948f512ceSopenharmony_ci    // attr
24048f512ceSopenharmony_ci    PRINT_INDENT(indent, "attrs[file section]: offset %" PRId64 ", size %" PRId64 "\n",
24148f512ceSopenharmony_ci                 header.attrs.offset, header.attrs.size);
24248f512ceSopenharmony_ci    // data
24348f512ceSopenharmony_ci    PRINT_INDENT(indent, "data[file section]: offset %" PRId64 ", size %" PRId64 "\n",
24448f512ceSopenharmony_ci                 header.data.offset, header.data.size);
24548f512ceSopenharmony_ci    PRINT_INDENT(indent, "event_types[file section]: offset %" PRId64 ", size %" PRId64 "\n",
24648f512ceSopenharmony_ci                 header.eventTypes.offset, header.eventTypes.size);
24748f512ceSopenharmony_ci    // feature
24848f512ceSopenharmony_ci    PRINT_INDENT(indent,
24948f512ceSopenharmony_ci                 "adds_features[]: 0x%" PRIX64 " 0x%" PRIX64 " 0x%" PRIX64 " 0x%" PRIX64 "\n",
25048f512ceSopenharmony_ci                 *(reinterpret_cast<const uint64_t *>(&header.features[0])),
25148f512ceSopenharmony_ci                 *(reinterpret_cast<const uint64_t *>(&header.features[8])),
25248f512ceSopenharmony_ci                 *(reinterpret_cast<const uint64_t *>(&header.features[16])),
25348f512ceSopenharmony_ci                 *(reinterpret_cast<const uint64_t *>(&header.features[24])));
25448f512ceSopenharmony_ci}
25548f512ceSopenharmony_ci
25648f512ceSopenharmony_civoid SubCommandDump::DumpPrintFileHeader(int indent)
25748f512ceSopenharmony_ci{
25848f512ceSopenharmony_ci    // print header
25948f512ceSopenharmony_ci    PrintHeaderInfo(indent);
26048f512ceSopenharmony_ci
26148f512ceSopenharmony_ci    // print feature
26248f512ceSopenharmony_ci    auto features = reader_->GetFeatures();
26348f512ceSopenharmony_ci    for (auto feature : features) {
26448f512ceSopenharmony_ci        PRINT_INDENT(indent, "feature: %s\n", PerfFileSection::GetFeatureName(feature).c_str());
26548f512ceSopenharmony_ci    }
26648f512ceSopenharmony_ci
26748f512ceSopenharmony_ci    // read here , because we need found symbols
26848f512ceSopenharmony_ci    reader_->ReadFeatureSection();
26948f512ceSopenharmony_ci
27048f512ceSopenharmony_ci    SetDeviceArch(GetArchTypeFromUname(reader_->GetFeatureString(FEATURE::ARCH)));
27148f512ceSopenharmony_ci
27248f512ceSopenharmony_ci    // found symbols in file
27348f512ceSopenharmony_ci    for (auto &featureSection : reader_->GetFeatureSections()) {
27448f512ceSopenharmony_ci        if (featureSection.get()->featureId_ == FEATURE::HIPERF_FILES_SYMBOL) {
27548f512ceSopenharmony_ci            const PerfFileSectionSymbolsFiles *sectionSymbolsFiles =
27648f512ceSopenharmony_ci                static_cast<const PerfFileSectionSymbolsFiles *>(featureSection.get());
27748f512ceSopenharmony_ci            vr_.UpdateFromPerfData(sectionSymbolsFiles->symbolFileStructs_);
27848f512ceSopenharmony_ci        } else if (featureSection.get()->featureId_ == FEATURE::HIPERF_FILES_UNISTACK_TABLE) {
27948f512ceSopenharmony_ci            const PerfFileSectionUniStackTable *sectionUniStackTable  =
28048f512ceSopenharmony_ci                static_cast<const PerfFileSectionUniStackTable *>(featureSection.get());
28148f512ceSopenharmony_ci            vr_.ImportUniqueStackNodes(sectionUniStackTable->uniStackTableInfos_);
28248f512ceSopenharmony_ci            vr_.SetDedupStack();
28348f512ceSopenharmony_ci        }
28448f512ceSopenharmony_ci    }
28548f512ceSopenharmony_ci}
28648f512ceSopenharmony_ci
28748f512ceSopenharmony_cistatic std::map<int, std::string> g_sampleTypeNames = {
28848f512ceSopenharmony_ci    {PERF_SAMPLE_IP, "ip"},
28948f512ceSopenharmony_ci    {PERF_SAMPLE_TID, "tid"},
29048f512ceSopenharmony_ci    {PERF_SAMPLE_TIME, "time"},
29148f512ceSopenharmony_ci    {PERF_SAMPLE_ADDR, "addr"},
29248f512ceSopenharmony_ci    {PERF_SAMPLE_READ, "read"},
29348f512ceSopenharmony_ci    {PERF_SAMPLE_CALLCHAIN, "callchain"},
29448f512ceSopenharmony_ci    {PERF_SAMPLE_ID, "id"},
29548f512ceSopenharmony_ci    {PERF_SAMPLE_CPU, "cpu"},
29648f512ceSopenharmony_ci    {PERF_SAMPLE_PERIOD, "period"},
29748f512ceSopenharmony_ci    {PERF_SAMPLE_STREAM_ID, "stream_id"},
29848f512ceSopenharmony_ci    {PERF_SAMPLE_RAW, "raw"},
29948f512ceSopenharmony_ci    {PERF_SAMPLE_BRANCH_STACK, "stack"},
30048f512ceSopenharmony_ci    {PERF_SAMPLE_REGS_USER, "regs_user"},
30148f512ceSopenharmony_ci    {PERF_SAMPLE_STACK_USER, "stack_user"},
30248f512ceSopenharmony_ci    {PERF_SAMPLE_WEIGHT, "weight"},
30348f512ceSopenharmony_ci    {PERF_SAMPLE_DATA_SRC, "data_src"},
30448f512ceSopenharmony_ci    {PERF_SAMPLE_IDENTIFIER, "identifier"},
30548f512ceSopenharmony_ci    {PERF_SAMPLE_TRANSACTION, "transaction"},
30648f512ceSopenharmony_ci    {PERF_SAMPLE_REGS_INTR, "reg_intr"},
30748f512ceSopenharmony_ci    {PERF_SAMPLE_SERVER_PID, "server_pid"},
30848f512ceSopenharmony_ci};
30948f512ceSopenharmony_ci
31048f512ceSopenharmony_civoid SubCommandDump::DumpSampleType(uint64_t sampleType, int indent)
31148f512ceSopenharmony_ci{
31248f512ceSopenharmony_ci    std::string names;
31348f512ceSopenharmony_ci    for (auto &pair : g_sampleTypeNames) {
31448f512ceSopenharmony_ci        if (sampleType & pair.first) {
31548f512ceSopenharmony_ci            if (!names.empty()) {
31648f512ceSopenharmony_ci                names.append(",");
31748f512ceSopenharmony_ci            }
31848f512ceSopenharmony_ci            names.append(pair.second);
31948f512ceSopenharmony_ci        }
32048f512ceSopenharmony_ci    }
32148f512ceSopenharmony_ci    PRINT_INDENT(indent + 1, "sample_type names: %s\n", names.c_str());
32248f512ceSopenharmony_ci}
32348f512ceSopenharmony_ci
32448f512ceSopenharmony_civoid SubCommandDump::DumpPrintEventAttr(const perf_event_attr &attr, int indent)
32548f512ceSopenharmony_ci{
32648f512ceSopenharmony_ci    PRINT_INDENT(indent, "event_attr: \n");
32748f512ceSopenharmony_ci
32848f512ceSopenharmony_ci    PRINT_INDENT(indent + 1, "type %u, size %u, config %llu\n", attr.type, attr.size, attr.config);
32948f512ceSopenharmony_ci
33048f512ceSopenharmony_ci    if (attr.freq != 0) {
33148f512ceSopenharmony_ci        PRINT_INDENT(indent + 1, "sample_freq %llu\n", attr.sample_freq);
33248f512ceSopenharmony_ci    } else {
33348f512ceSopenharmony_ci        PRINT_INDENT(indent + 1, "sample_period %llu\n", attr.sample_period);
33448f512ceSopenharmony_ci    }
33548f512ceSopenharmony_ci
33648f512ceSopenharmony_ci    PRINT_INDENT(indent + 1, "sample_type (0x%llx) \n", attr.sample_type);
33748f512ceSopenharmony_ci    DumpSampleType(attr.sample_type, indent);
33848f512ceSopenharmony_ci
33948f512ceSopenharmony_ci    PRINT_INDENT(indent + 1, "read_format (0x%llx) \n", attr.read_format);
34048f512ceSopenharmony_ci
34148f512ceSopenharmony_ci    PRINT_INDENT(indent + 1, "disabled %u, inherit %u, pinned %u, exclusive %u\n", attr.disabled,
34248f512ceSopenharmony_ci                 attr.inherit, attr.pinned, attr.exclusive);
34348f512ceSopenharmony_ci
34448f512ceSopenharmony_ci    PRINT_INDENT(indent + 1, "exclude_user %u, exclude_kernel %u, exclude_hv %u, exclude_idle %u\n",
34548f512ceSopenharmony_ci                 attr.exclude_user, attr.exclude_kernel, attr.exclude_hv, attr.exclude_idle);
34648f512ceSopenharmony_ci
34748f512ceSopenharmony_ci    PRINT_INDENT(indent + 1, "mmap %u, mmap2 %u, comm %u, comm_exec %u, freq %u\n", attr.mmap,
34848f512ceSopenharmony_ci                 attr.mmap2, attr.comm, attr.comm_exec, attr.freq);
34948f512ceSopenharmony_ci
35048f512ceSopenharmony_ci    PRINT_INDENT(indent + 1, "inherit_stat %u, enable_on_exec %u, task %u, use_clockid %u\n",
35148f512ceSopenharmony_ci                 attr.inherit_stat, attr.enable_on_exec, attr.task, attr.use_clockid);
35248f512ceSopenharmony_ci
35348f512ceSopenharmony_ci    PRINT_INDENT(indent + 1, "watermark %u, precise_ip %u, mmap_data %u, clockid %d\n", attr.watermark,
35448f512ceSopenharmony_ci                 attr.precise_ip, attr.mmap_data, attr.clockid);
35548f512ceSopenharmony_ci
35648f512ceSopenharmony_ci    PRINT_INDENT(indent + 1, "sample_id_all %u, exclude_host %u, exclude_guest %u\n", attr.sample_id_all,
35748f512ceSopenharmony_ci                 attr.exclude_host, attr.exclude_guest);
35848f512ceSopenharmony_ci    PRINT_INDENT(indent + 1, "branch_sample_type 0x%llx\n", attr.branch_sample_type);
35948f512ceSopenharmony_ci    PRINT_INDENT(indent + 1, "exclude_callchain_kernel %u, exclude_callchain_user %u\n",
36048f512ceSopenharmony_ci                 attr.exclude_callchain_kernel, attr.exclude_callchain_user);
36148f512ceSopenharmony_ci    PRINT_INDENT(indent + 1, "sample_regs_user 0x%llx\n", attr.sample_regs_user);
36248f512ceSopenharmony_ci    PRINT_INDENT(indent + 1, "sample_stack_user 0x%x\n", attr.sample_stack_user);
36348f512ceSopenharmony_ci}
36448f512ceSopenharmony_ci
36548f512ceSopenharmony_civoid SubCommandDump::DumpAttrPortion(int indent)
36648f512ceSopenharmony_ci{
36748f512ceSopenharmony_ci    attrIds_ = reader_->GetAttrSection();
36848f512ceSopenharmony_ci    for (size_t i = 0; i < attrIds_.size(); ++i) {
36948f512ceSopenharmony_ci        const AttrWithId &attr = attrIds_[i];
37048f512ceSopenharmony_ci        PRINT_INDENT(indent, "attr %zu:\n", i + 1);
37148f512ceSopenharmony_ci        DumpPrintEventAttr(attr.attr, indent_ + 1);
37248f512ceSopenharmony_ci        if (!attr.ids.empty()) {
37348f512ceSopenharmony_ci            PRINT_INDENT(indent, "  ids:");
37448f512ceSopenharmony_ci            for (const auto &id : attr.ids) {
37548f512ceSopenharmony_ci                PRINT_INDENT(indent, " %" PRId64, id);
37648f512ceSopenharmony_ci            }
37748f512ceSopenharmony_ci            PRINT_INDENT(indent, "\n");
37848f512ceSopenharmony_ci        }
37948f512ceSopenharmony_ci    }
38048f512ceSopenharmony_ci}
38148f512ceSopenharmony_ci
38248f512ceSopenharmony_civoid SubCommandDump::ExprotUserStack(const PerfRecordSample &recordSample)
38348f512ceSopenharmony_ci{
38448f512ceSopenharmony_ci    if (recordSample.data_.reg_nr > 0 and recordSample.data_.dyn_size > 0) {
38548f512ceSopenharmony_ci        // <pid>_<tid>_user_regs_<time>
38648f512ceSopenharmony_ci        std::string userRegs =
38748f512ceSopenharmony_ci            StringPrintf("hiperf_%d_%d_user_regs_%zu.dump", recordSample.data_.pid,
38848f512ceSopenharmony_ci                         recordSample.data_.tid, exportSampleIndex_);
38948f512ceSopenharmony_ci        std::string resolvedPath = CanonicalizeSpecPath(userRegs.c_str());
39048f512ceSopenharmony_ci        std::unique_ptr<FILE, decltype(&fclose)> fpUserRegs(fopen(resolvedPath.c_str(), "wb"), fclose);
39148f512ceSopenharmony_ci        fwrite(recordSample.data_.user_regs, sizeof(u64), recordSample.data_.reg_nr,
39248f512ceSopenharmony_ci               fpUserRegs.get());
39348f512ceSopenharmony_ci
39448f512ceSopenharmony_ci        std::string userData =
39548f512ceSopenharmony_ci            StringPrintf("hiperf_%d_%d_user_data_%zu.dump", recordSample.data_.pid,
39648f512ceSopenharmony_ci                         recordSample.data_.tid, exportSampleIndex_);
39748f512ceSopenharmony_ci        std::string resolvePath = CanonicalizeSpecPath(userData.c_str());
39848f512ceSopenharmony_ci        std::unique_ptr<FILE, decltype(&fclose)> fpUserData(fopen(resolvePath.c_str(), "wb"), fclose);
39948f512ceSopenharmony_ci        fwrite(recordSample.data_.stack_data, sizeof(u8), recordSample.data_.dyn_size,
40048f512ceSopenharmony_ci               fpUserData.get());
40148f512ceSopenharmony_ci    }
40248f512ceSopenharmony_ci}
40348f512ceSopenharmony_ci
40448f512ceSopenharmony_civoid SubCommandDump::ExprotUserData(std::unique_ptr<PerfEventRecord> &record)
40548f512ceSopenharmony_ci{
40648f512ceSopenharmony_ci    if (record->GetType() == PERF_RECORD_SAMPLE) {
40748f512ceSopenharmony_ci        if (currectSampleIndex_++ != exportSampleIndex_) {
40848f512ceSopenharmony_ci            return;
40948f512ceSopenharmony_ci        }
41048f512ceSopenharmony_ci        PerfRecordSample *recordSample = static_cast<PerfRecordSample *>(record.get());
41148f512ceSopenharmony_ci        ExprotUserStack(*recordSample);
41248f512ceSopenharmony_ci
41348f512ceSopenharmony_ci        std::string userData =
41448f512ceSopenharmony_ci            StringPrintf("hiperf_%d_%d_sample_record_%zu_%" PRIu64 ".dump", recordSample->data_.pid,
41548f512ceSopenharmony_ci                         recordSample->data_.tid, exportSampleIndex_, recordSample->data_.time);
41648f512ceSopenharmony_ci        std::string resolvedPath = CanonicalizeSpecPath(userData.c_str());
41748f512ceSopenharmony_ci        std::unique_ptr<FILE, decltype(&fclose)> fpUserData(fopen(resolvedPath.c_str(), "wb"), fclose);
41848f512ceSopenharmony_ci        static std::vector<u8> buf(RECORD_SIZE_LIMIT);
41948f512ceSopenharmony_ci        CHECK_TRUE(!recordSample->GetBinary(buf), NO_RETVAL, 1, "export user sample data failed");
42048f512ceSopenharmony_ci        fwrite(buf.data(), sizeof(u8), recordSample->GetSize(), fpUserData.get());
42148f512ceSopenharmony_ci
42248f512ceSopenharmony_ci        HLOGD("export user data index %d time %llu", exportSampleIndex_, recordSample->data_.time);
42348f512ceSopenharmony_ci    }
42448f512ceSopenharmony_ci}
42548f512ceSopenharmony_ci
42648f512ceSopenharmony_civoid SubCommandDump::DumpCallChain(int indent, std::unique_ptr<PerfRecordSample> &sample)
42748f512ceSopenharmony_ci{
42848f512ceSopenharmony_ci    PRINT_INDENT(indent, "\n callchain: %zu\n", sample->callFrames_.size());
42948f512ceSopenharmony_ci    if (sample->callFrames_.size() > 0) {
43048f512ceSopenharmony_ci        indent += indent + 1;
43148f512ceSopenharmony_ci        for (auto frameIt = sample->callFrames_.begin(); frameIt != sample->callFrames_.end();
43248f512ceSopenharmony_ci             frameIt++) {
43348f512ceSopenharmony_ci            PRINT_INDENT(indent, "%02zd:%s\n", std::distance(frameIt, sample->callFrames_.end()),
43448f512ceSopenharmony_ci                         frameIt->ToSymbolString().c_str());
43548f512ceSopenharmony_ci        }
43648f512ceSopenharmony_ci    }
43748f512ceSopenharmony_ci}
43848f512ceSopenharmony_ci
43948f512ceSopenharmony_civoid SubCommandDump::DumpDataPortion(int indent)
44048f512ceSopenharmony_ci{
44148f512ceSopenharmony_ci    int recordCount = 0;
44248f512ceSopenharmony_ci    auto recordcCallback = [&](std::unique_ptr<PerfEventRecord> record) {
44348f512ceSopenharmony_ci        CHECK_TRUE(record == nullptr, false, 0, ""); // return false in callback can stop the read process
44448f512ceSopenharmony_ci
44548f512ceSopenharmony_ci        // for UT
44648f512ceSopenharmony_ci        if (exportSampleIndex_ > 0) {
44748f512ceSopenharmony_ci            ExprotUserData(record);
44848f512ceSopenharmony_ci        }
44948f512ceSopenharmony_ci
45048f512ceSopenharmony_ci        // tell process tree what happend for rebuild symbols
45148f512ceSopenharmony_ci        vr_.UpdateFromRecord(*record);
45248f512ceSopenharmony_ci
45348f512ceSopenharmony_ci        recordCount++;
45448f512ceSopenharmony_ci        record->Dump(indent, outputFilename_, g_outputDump);
45548f512ceSopenharmony_ci
45648f512ceSopenharmony_ci        if (record->GetType() == PERF_RECORD_SAMPLE) {
45748f512ceSopenharmony_ci            std::unique_ptr<PerfRecordSample> sample(
45848f512ceSopenharmony_ci                static_cast<PerfRecordSample *>(record.release()));
45948f512ceSopenharmony_ci            DumpCallChain(indent, sample);
46048f512ceSopenharmony_ci        }
46148f512ceSopenharmony_ci
46248f512ceSopenharmony_ci        return true;
46348f512ceSopenharmony_ci    };
46448f512ceSopenharmony_ci
46548f512ceSopenharmony_ci    reader_->ReadDataSection(recordcCallback);
46648f512ceSopenharmony_ci
46748f512ceSopenharmony_ci    PRINT_INDENT(indent, "\n ======= there are %d records ======== \n", recordCount);
46848f512ceSopenharmony_ci}
46948f512ceSopenharmony_ci
47048f512ceSopenharmony_civoid SubCommandDump::PrintSymbolFile(const int &indent, const SymbolFileStruct &symbolFileStruct)
47148f512ceSopenharmony_ci{
47248f512ceSopenharmony_ci    PRINT_INDENT(indent + INDENT_TWO, "filePath:%s\n", symbolFileStruct.filePath_.c_str());
47348f512ceSopenharmony_ci    PRINT_INDENT(indent + INDENT_TWO, "symbolType:%u\n", symbolFileStruct.symbolType_);
47448f512ceSopenharmony_ci    PRINT_INDENT(indent + INDENT_TWO, "minExecAddr:0x%" PRIx64 "\n", symbolFileStruct.textExecVaddr_);
47548f512ceSopenharmony_ci    PRINT_INDENT(indent + INDENT_TWO, "minExecAddrFileOffset:0x%08" PRIx64 "\n",
47648f512ceSopenharmony_ci                symbolFileStruct.textExecVaddrFileOffset_);
47748f512ceSopenharmony_ci    if (!symbolFileStruct.buildId_.empty()) {
47848f512ceSopenharmony_ci        PRINT_INDENT(indent + INDENT_TWO, "buildId:'%s'\n", symbolFileStruct.buildId_.c_str());
47948f512ceSopenharmony_ci    }
48048f512ceSopenharmony_ci    PRINT_INDENT(indent + INDENT_TWO, "symbol number: %zu\n", symbolFileStruct.symbolStructs_.size());
48148f512ceSopenharmony_ci    int symbolid = 0;
48248f512ceSopenharmony_ci    for (auto &symbolStruct : symbolFileStruct.symbolStructs_) {
48348f512ceSopenharmony_ci        PRINT_INDENT(indent + 3, "%05d [0x%016" PRIx64 "@0x%08x]  %s\n", symbolid, symbolStruct.vaddr_,
48448f512ceSopenharmony_ci                     symbolStruct.len_, symbolStruct.symbolName_.c_str());
48548f512ceSopenharmony_ci        symbolid++;
48648f512ceSopenharmony_ci    }
48748f512ceSopenharmony_ci}
48848f512ceSopenharmony_ci
48948f512ceSopenharmony_civoid SubCommandDump::PrintFeatureEventdesc(int indent,
49048f512ceSopenharmony_ci                                           const PerfFileSectionEventDesc &sectionEventdesc)
49148f512ceSopenharmony_ci{
49248f512ceSopenharmony_ci    PRINT_INDENT(indent + INDENT_TWO, "Event descriptions: %zu\n", sectionEventdesc.eventDesces_.size());
49348f512ceSopenharmony_ci    for (size_t i = 0; i < sectionEventdesc.eventDesces_.size(); i++) {
49448f512ceSopenharmony_ci        const AttrWithId &desc = sectionEventdesc.eventDesces_[i];
49548f512ceSopenharmony_ci        PRINT_INDENT(indent + INDENT_TWO, "event name[%zu]: %s ids: %s\n", i, desc.name.c_str(),
49648f512ceSopenharmony_ci                     VectorToString(desc.ids).c_str());
49748f512ceSopenharmony_ci
49848f512ceSopenharmony_ci        // attr is duplicated the attrs section
49948f512ceSopenharmony_ci    }
50048f512ceSopenharmony_ci    PRINT_INDENT(indent + INDENT_TWO, "\n");
50148f512ceSopenharmony_ci}
50248f512ceSopenharmony_ci
50348f512ceSopenharmony_civoid SubCommandDump::DumpFeaturePortion(int indent)
50448f512ceSopenharmony_ci{
50548f512ceSopenharmony_ci    PRINT_INDENT(indent, "\n ==== features ====\n");
50648f512ceSopenharmony_ci    auto features = reader_->GetFeatures();
50748f512ceSopenharmony_ci    for (auto feature : features) {
50848f512ceSopenharmony_ci        PRINT_INDENT(indent + 1, "feature %d:%s\n", feature,
50948f512ceSopenharmony_ci                     PerfFileSection::GetFeatureName(feature).c_str());
51048f512ceSopenharmony_ci    }
51148f512ceSopenharmony_ci
51248f512ceSopenharmony_ci    const auto &featureSections = reader_->GetFeatureSections();
51348f512ceSopenharmony_ci    HLOGV("featureSections: %zu ", featureSections.size());
51448f512ceSopenharmony_ci
51548f512ceSopenharmony_ci    PRINT_INDENT(indent, "\n ==== feature sections ====\n");
51648f512ceSopenharmony_ci
51748f512ceSopenharmony_ci    for (auto &featureSection : featureSections) {
51848f512ceSopenharmony_ci        PRINT_INDENT(indent + 1, "feature %d:%s content: \n", featureSection.get()->featureId_,
51948f512ceSopenharmony_ci                     PerfFileSection::GetFeatureName(featureSection.get()->featureId_).c_str());
52048f512ceSopenharmony_ci        if (reader_->IsFeatrureStringSection(featureSection.get()->featureId_)) {
52148f512ceSopenharmony_ci            const PerfFileSectionString *sectionString =
52248f512ceSopenharmony_ci                static_cast<const PerfFileSectionString *>(featureSection.get());
52348f512ceSopenharmony_ci            PRINT_INDENT(indent + INDENT_TWO, "%s\n", sectionString->ToString().c_str());
52448f512ceSopenharmony_ci            continue;
52548f512ceSopenharmony_ci        } else if (featureSection.get()->featureId_ == FEATURE::EVENT_DESC) {
52648f512ceSopenharmony_ci            PrintFeatureEventdesc(
52748f512ceSopenharmony_ci                indent, *static_cast<const PerfFileSectionEventDesc *>(featureSection.get()));
52848f512ceSopenharmony_ci            continue;
52948f512ceSopenharmony_ci        } else if (featureSection.get()->featureId_ == FEATURE::HIPERF_FILES_SYMBOL) {
53048f512ceSopenharmony_ci            const PerfFileSectionSymbolsFiles *sectionSymbolsFiles =
53148f512ceSopenharmony_ci                static_cast<const PerfFileSectionSymbolsFiles *>(featureSection.get());
53248f512ceSopenharmony_ci            if (sectionSymbolsFiles != nullptr) {
53348f512ceSopenharmony_ci                PRINT_INDENT(indent + INDENT_TWO, "SymbolFiles:%zu\n",
53448f512ceSopenharmony_ci                             sectionSymbolsFiles->symbolFileStructs_.size());
53548f512ceSopenharmony_ci
53648f512ceSopenharmony_ci                int fileid = 0;
53748f512ceSopenharmony_ci                for (auto &symbolFileStruct : sectionSymbolsFiles->symbolFileStructs_) {
53848f512ceSopenharmony_ci                    PRINT_INDENT(indent + INDENT_TWO, "\n");
53948f512ceSopenharmony_ci                    PRINT_INDENT(indent + INDENT_TWO, "fileid:%d\n", fileid);
54048f512ceSopenharmony_ci                    fileid++;
54148f512ceSopenharmony_ci                    // symbol file info
54248f512ceSopenharmony_ci                    PrintSymbolFile(indent, symbolFileStruct);
54348f512ceSopenharmony_ci                }
54448f512ceSopenharmony_ci            } else {
54548f512ceSopenharmony_ci                PRINT_INDENT(indent + INDENT_TWO, "get SymbolFiles failed\n");
54648f512ceSopenharmony_ci            }
54748f512ceSopenharmony_ci            continue;
54848f512ceSopenharmony_ci        } else if (featureSection.get()->featureId_ == FEATURE::HIPERF_FILES_UNISTACK_TABLE) {
54948f512ceSopenharmony_ci            const PerfFileSectionUniStackTable *sectioniStackTable =
55048f512ceSopenharmony_ci                static_cast<PerfFileSectionUniStackTable *>(const_cast<PerfFileSection *>(featureSection.get()));
55148f512ceSopenharmony_ci            if (sectioniStackTable != nullptr) {
55248f512ceSopenharmony_ci                DumpUniqueStackTableNode(indent + 1, *sectioniStackTable);
55348f512ceSopenharmony_ci            } else {
55448f512ceSopenharmony_ci                PRINT_INDENT(indent + INDENT_TWO, "get StackTable failed\n");
55548f512ceSopenharmony_ci            }
55648f512ceSopenharmony_ci            continue;
55748f512ceSopenharmony_ci        } else {
55848f512ceSopenharmony_ci            PRINT_INDENT(indent + INDENT_TWO, "not support dump this feature(%d).\n", featureSection.get()->featureId_);
55948f512ceSopenharmony_ci        }
56048f512ceSopenharmony_ci    }
56148f512ceSopenharmony_ci}
56248f512ceSopenharmony_ci
56348f512ceSopenharmony_civoid SubCommandDump::DumpUniqueStackTableNode(int indent, const PerfFileSectionUniStackTable &uniStackTable)
56448f512ceSopenharmony_ci{
56548f512ceSopenharmony_ci    int tableid = 0;
56648f512ceSopenharmony_ci    PRINT_INDENT(indent + 1, "TableNums: %zu\n\n", uniStackTable.uniStackTableInfos_.size());
56748f512ceSopenharmony_ci    for (const auto& uniStackTableInfo : uniStackTable.uniStackTableInfos_) {
56848f512ceSopenharmony_ci        PRINT_INDENT(indent + INDENT_TWO, "tableid: %d\n", tableid);
56948f512ceSopenharmony_ci        PRINT_INDENT(indent + INDENT_TWO, "pid: %" PRIu32 "\n", uniStackTableInfo.pid);
57048f512ceSopenharmony_ci        PRINT_INDENT(indent + INDENT_TWO, "tableSize: %" PRIu32 "\n", uniStackTableInfo.tableSize);
57148f512ceSopenharmony_ci        PRINT_INDENT(indent + INDENT_TWO, "numNodes: %" PRIu32 "\n", uniStackTableInfo.numNodes);
57248f512ceSopenharmony_ci        PRINT_INDENT(indent + INDENT_TWO, "%-7s %-7s %-8s\n", "no", "index", "node");
57348f512ceSopenharmony_ci        for (size_t i = 0; i < uniStackTableInfo.nodes.size(); i++) {
57448f512ceSopenharmony_ci            UniStackNode node = uniStackTableInfo.nodes[i];
57548f512ceSopenharmony_ci            PRINT_INDENT(indent + INDENT_TWO, "%-7zu %-7" PRIu32 " 0x%-8" PRIx64 "\n", i, node.index, node.node.value);
57648f512ceSopenharmony_ci        }
57748f512ceSopenharmony_ci        tableid++;
57848f512ceSopenharmony_ci    }
57948f512ceSopenharmony_ci}
58048f512ceSopenharmony_ci
58148f512ceSopenharmony_cibool SubCommandDump::RegisterSubCommandDump()
58248f512ceSopenharmony_ci{
58348f512ceSopenharmony_ci    return SubCommand::RegisterSubCommand("dump", std::make_unique<SubCommandDump>());
58448f512ceSopenharmony_ci}
58548f512ceSopenharmony_ci
58648f512ceSopenharmony_civoid SubCommandDump::SetHM()
58748f512ceSopenharmony_ci{
58848f512ceSopenharmony_ci    std::string os = reader_->GetFeatureString(FEATURE::OSRELEASE);
58948f512ceSopenharmony_ci    isHM_ = os.find(HMKERNEL) != std::string::npos;
59048f512ceSopenharmony_ci    vr_.SetHM(isHM_);
59148f512ceSopenharmony_ci    HLOGD("Set isHM_: %d", isHM_);
59248f512ceSopenharmony_ci    if (isHM_) {
59348f512ceSopenharmony_ci        pid_t devhost = -1;
59448f512ceSopenharmony_ci        std::string str = reader_->GetFeatureString(FEATURE::HIPERF_HM_DEVHOST);
59548f512ceSopenharmony_ci        if (str != EMPTY_STRING) {
59648f512ceSopenharmony_ci            devhost = std::stoll(str);
59748f512ceSopenharmony_ci        }
59848f512ceSopenharmony_ci        vr_.SetDevhostPid(devhost);
59948f512ceSopenharmony_ci    }
60048f512ceSopenharmony_ci}
60148f512ceSopenharmony_ci
60248f512ceSopenharmony_civoid SubCommandDump::DumpSpeReport()
60348f512ceSopenharmony_ci{
60448f512ceSopenharmony_ci#if defined(is_ohos) && is_ohos
60548f512ceSopenharmony_ci    std::string cmdline = reader_->GetFeatureString(FEATURE::CMDLINE);
60648f512ceSopenharmony_ci    if (cmdline.find("-e arm_spe_0") != std::string::npos) {
60748f512ceSopenharmony_ci        HLOGD("dump spe report data");
60848f512ceSopenharmony_ci        UpdateHeating();
60948f512ceSopenharmony_ci        DumpSpeReportData(indent_, g_outputDump);
61048f512ceSopenharmony_ci    }
61148f512ceSopenharmony_ci#endif
61248f512ceSopenharmony_ci}
61348f512ceSopenharmony_ci
61448f512ceSopenharmony_ci} // namespace HiPerf
61548f512ceSopenharmony_ci} // namespace Developtools
61648f512ceSopenharmony_ci} // namespace OHOS
617