1/*
2 * Copyright (c) 2021-2023 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#include "hiperf_libreport.h"
16
17#include "debug_logger.h"
18#include "dfx_elf.h"
19#include "perf_file_reader.h"
20#include "subcommand_dump.h"
21#include "subcommand_report.h"
22#include "utilities.h"
23
24using namespace OHOS::Developtools::HiPerf;
25extern "C" {
26// this is a demo function
27const char *EchoLoopBack(const char *echo)
28{
29    HLOGD("EchoLoopBack:%s\n", echo);
30    return echo;
31}
32
33int SetDebug(bool enable)
34{
35#ifdef HIPERF_DEBUG
36    if (enable) {
37        DebugLogger::GetInstance()->SetLogLevel(LEVEL_VERBOSE);
38        DebugLogger::GetInstance()->Disable(false);
39    } else {
40        DebugLogger::GetInstance()->Disable(true);
41    }
42#endif
43    return 0;
44}
45
46int Report(const char *perfFile, const char *reportFile, const char *reportOptions)
47{
48    std::unique_ptr<SubCommandReport> report = std::make_unique<SubCommandReport>();
49    HLOGD("report the file %s to %s\n", perfFile, reportFile);
50    if (perfFile != nullptr and reportFile != nullptr) {
51        std::vector<std::string> args;
52        args.emplace_back("-i");
53        args.emplace_back(perfFile);
54        args.emplace_back("-o");
55        args.emplace_back(reportFile);
56        if (reportOptions != nullptr) {
57            std::vector<std::string> options = StringSplit(reportOptions);
58            for (std::string &option : options) {
59                args.emplace_back(option);
60            }
61        }
62        if (report->ParseOption(args)) {
63            return report->OnSubCommand(args) ? 0 : -1;
64        }
65    } else {
66        printf("path is nullptr\n");
67    }
68    return -1;
69}
70
71int ReportJson(const char *perfFile, const char *reportFile)
72{
73    return ReportUnwindJson(perfFile, reportFile, nullptr);
74}
75
76int ReportUnwindJson(const char *perfFile, const char *reportFile, const char *symbolsDir)
77{
78    std::unique_ptr<SubCommandReport> report = std::make_unique<SubCommandReport>();
79    HLOGD("report the file %s to json file %s symbols from %s\n", perfFile, reportFile, symbolsDir);
80    if (perfFile != nullptr and reportFile != nullptr) {
81        std::vector<std::string> args;
82        args.emplace_back("-i");
83        args.emplace_back(perfFile);
84        args.emplace_back("-o");
85        args.emplace_back(reportFile);
86        args.emplace_back("--json");
87        if (symbolsDir != nullptr) {
88            args.emplace_back("--symbol-dir");
89            args.emplace_back(symbolsDir);
90        }
91        if (report->ParseOption(args)) {
92            return report->OnSubCommand(args) ? 0 : -1;
93        }
94    }
95    return -1;
96}
97
98static std::unique_ptr<PerfFileReader> GetReader(const std::string &fileName)
99{
100    // check if file exist
101    if (access(fileName.c_str(), F_OK) != 0) {
102        // file not exists
103        printf("Can not access data file %s\n", fileName.c_str());
104        return nullptr;
105    }
106
107    auto reader = PerfFileReader::Instance(fileName);
108    if (reader == nullptr) {
109        printf("%s format not correct\n", fileName.c_str());
110        return nullptr;
111    } else {
112        return reader;
113    }
114}
115
116const char *ReportGetSymbolFiles(const char *perfFile)
117{
118    HLOGD("report the file %s for symbols \n", perfFile);
119    static std::string result; // static for hold the c_str buffer
120    result.clear();
121    if (perfFile == nullptr) {
122        return result.c_str();
123    }
124
125    auto reader = GetReader(perfFile);
126    if (reader == nullptr) {
127        return result.c_str();
128    }
129    // found symbols in file
130    reader->ReadFeatureSection();
131    for (auto &featureSection : reader->GetFeatureSections()) {
132        if (featureSection->featureId_ == FEATURE::HIPERF_FILES_SYMBOL) {
133            const PerfFileSectionSymbolsFiles *sectionSymbolsFiles =
134                static_cast<const PerfFileSectionSymbolsFiles *>(featureSection.get());
135            auto it = sectionSymbolsFiles->symbolFileStructs_.begin();
136            while (it != sectionSymbolsFiles->symbolFileStructs_.end()) {
137                HLOGD("%s buildId:%s\n", it->filePath_.c_str(), it->buildId_.c_str());
138                result.append("[");
139                result.append(it->filePath_.c_str());
140                result.append(",");
141                result.append(it->buildId_.c_str());
142                result.append("]");
143                result.append(",");
144                it++;
145            }
146            result[result.size() >= 1 ? result.size() - 1 : 0] = '\0';
147        }
148    }
149    return result.c_str();
150}
151
152const char *ReportGetBuildId(const char *elfPath)
153{
154    static std::string buildId; // static for hold the c_str buffer
155    buildId.clear();
156    std::string path(elfPath);
157    std::shared_ptr<DfxElf> elfFile = std::make_shared<DfxElf>(path);
158    buildId = elfFile->GetBuildId();
159    return buildId.c_str();
160}
161
162const char *ReportGetElfArch(const char *elfPath)
163{
164    std::string path(elfPath);
165    std::shared_ptr<DfxElf> elfFile = std::make_shared<DfxElf>(path);
166    const char *machineName = "unknown";
167    switch (elfFile->GetArchType()) {
168        case ArchType::ARCH_ARM:
169            machineName = "arm";
170            break;
171        case ArchType::ARCH_ARM64:
172            machineName = "arm64";
173            break;
174        case ArchType::ARCH_X86:
175            machineName = "x86";
176            break;
177        case ArchType::ARCH_X86_64:
178            machineName = "x86_64";
179            break;
180        default:
181            break;
182    }
183    HLOGD("elf '%s' mache type is %s \n", elfPath, machineName);
184    return machineName;
185}
186
187int Dump(const char *fileName)
188{
189    std::unique_ptr<SubCommandDump> dump = std::make_unique<SubCommandDump>();
190    HLOGD("dump the file %s\n", fileName);
191    if (fileName != nullptr) {
192        std::vector<std::string> args;
193        args.emplace_back(fileName);
194        if (dump->ParseOption(args)) {
195            return dump->OnSubCommand(args) ? 0 : -1;
196        }
197    }
198    return -1;
199}
200
201} // extern "C"
202