106f6ba60Sopenharmony_ci/*
206f6ba60Sopenharmony_ci * Copyright (c) Huawei Technologies Co., Ltd. 2021. All rights reserved.
306f6ba60Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
406f6ba60Sopenharmony_ci * you may not use this file except in compliance with the License.
506f6ba60Sopenharmony_ci * You may obtain a copy of the License at
606f6ba60Sopenharmony_ci *
706f6ba60Sopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
806f6ba60Sopenharmony_ci *
906f6ba60Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
1006f6ba60Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
1106f6ba60Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1206f6ba60Sopenharmony_ci * See the License for the specific language governing permissions and
1306f6ba60Sopenharmony_ci * limitations under the License.
1406f6ba60Sopenharmony_ci */
1506f6ba60Sopenharmony_ci#include "ftrace_fs_ops.h"
1606f6ba60Sopenharmony_ci
1706f6ba60Sopenharmony_ci#include <fcntl.h>
1806f6ba60Sopenharmony_ci#include <set>
1906f6ba60Sopenharmony_ci#include <sys/stat.h>
2006f6ba60Sopenharmony_ci#include <sys/types.h>
2106f6ba60Sopenharmony_ci#include <sys/utsname.h>
2206f6ba60Sopenharmony_ci#include <unistd.h>
2306f6ba60Sopenharmony_ci#include "common.h"
2406f6ba60Sopenharmony_ci#include "file_utils.h"
2506f6ba60Sopenharmony_ci#include "logging.h"
2606f6ba60Sopenharmony_ci
2706f6ba60Sopenharmony_ciFTRACE_NS_BEGIN
2806f6ba60Sopenharmony_ciFtraceFsOps& FtraceFsOps::GetInstance()
2906f6ba60Sopenharmony_ci{
3006f6ba60Sopenharmony_ci    static FtraceFsOps instance;
3106f6ba60Sopenharmony_ci    return instance;
3206f6ba60Sopenharmony_ci}
3306f6ba60Sopenharmony_ci
3406f6ba60Sopenharmony_ciFtraceFsOps::FtraceFsOps() : ftraceRoot_(GetFtraceRoot())
3506f6ba60Sopenharmony_ci{
3606f6ba60Sopenharmony_ci    PROFILER_LOG_INFO(LOG_CORE, "FtraceFsOps create!");
3706f6ba60Sopenharmony_ci}
3806f6ba60Sopenharmony_ci
3906f6ba60Sopenharmony_ciFtraceFsOps::~FtraceFsOps()
4006f6ba60Sopenharmony_ci{
4106f6ba60Sopenharmony_ci    PROFILER_LOG_INFO(LOG_CORE, "FtraceFsOps destroy!");
4206f6ba60Sopenharmony_ci}
4306f6ba60Sopenharmony_ci
4406f6ba60Sopenharmony_cistd::string FtraceFsOps::GetFtraceRoot()
4506f6ba60Sopenharmony_ci{
4606f6ba60Sopenharmony_ci    std::vector<std::string> testRootPath = {"/sys/kernel/tracing", "/sys/kernel/debug/tracing"};
4706f6ba60Sopenharmony_ci    for (auto iter = testRootPath.begin(); iter != testRootPath.end(); ++iter) {
4806f6ba60Sopenharmony_ci        auto path = *iter + "/events";
4906f6ba60Sopenharmony_ci        struct stat s;
5006f6ba60Sopenharmony_ci        lstat(path.c_str(), &s);
5106f6ba60Sopenharmony_ci        if (S_ISDIR(s.st_mode)) {
5206f6ba60Sopenharmony_ci            return *iter;
5306f6ba60Sopenharmony_ci        }
5406f6ba60Sopenharmony_ci    }
5506f6ba60Sopenharmony_ci    return "";
5606f6ba60Sopenharmony_ci}
5706f6ba60Sopenharmony_ci
5806f6ba60Sopenharmony_cibool FtraceFsOps::IsHmKernel()
5906f6ba60Sopenharmony_ci{
6006f6ba60Sopenharmony_ci    bool isHM = false;
6106f6ba60Sopenharmony_ci    utsname unameBuf;
6206f6ba60Sopenharmony_ci    if ((uname(&unameBuf)) == 0) {
6306f6ba60Sopenharmony_ci        std::string osRelease = unameBuf.release;
6406f6ba60Sopenharmony_ci        isHM = osRelease.find("HongMeng") != std::string::npos;
6506f6ba60Sopenharmony_ci    }
6606f6ba60Sopenharmony_ci    return isHM;
6706f6ba60Sopenharmony_ci}
6806f6ba60Sopenharmony_ci
6906f6ba60Sopenharmony_ciint FtraceFsOps::WriteTraceFile(const std::string& path, const std::string& content)
7006f6ba60Sopenharmony_ci{
7106f6ba60Sopenharmony_ci    bool ret = false;
7206f6ba60Sopenharmony_ci    if (access((ftraceRoot_ + path).c_str(), W_OK) == 0) {
7306f6ba60Sopenharmony_ci        if (FileUtils::WriteFile(ftraceRoot_ + path, content) > 0) {
7406f6ba60Sopenharmony_ci            ret = true;
7506f6ba60Sopenharmony_ci        }
7606f6ba60Sopenharmony_ci    }
7706f6ba60Sopenharmony_ci
7806f6ba60Sopenharmony_ci    return (int)ret;
7906f6ba60Sopenharmony_ci}
8006f6ba60Sopenharmony_ci
8106f6ba60Sopenharmony_ciint FtraceFsOps::WriteTraceFile(const std::string& path, const std::string& content, int flags)
8206f6ba60Sopenharmony_ci{
8306f6ba60Sopenharmony_ci    bool ret = false;
8406f6ba60Sopenharmony_ci    if (access((ftraceRoot_ + path).c_str(), W_OK) == 0) {
8506f6ba60Sopenharmony_ci        if (FileUtils::WriteFile(ftraceRoot_ + path, content, flags) > 0) {
8606f6ba60Sopenharmony_ci            ret = true;
8706f6ba60Sopenharmony_ci        }
8806f6ba60Sopenharmony_ci    }
8906f6ba60Sopenharmony_ci
9006f6ba60Sopenharmony_ci    return (int)ret;
9106f6ba60Sopenharmony_ci}
9206f6ba60Sopenharmony_ci
9306f6ba60Sopenharmony_cistd::string FtraceFsOps::ReadTraceFile(const std::string& path) const
9406f6ba60Sopenharmony_ci{
9506f6ba60Sopenharmony_ci    return FileUtils::ReadFile(ftraceRoot_ + path);
9606f6ba60Sopenharmony_ci}
9706f6ba60Sopenharmony_ci
9806f6ba60Sopenharmony_cistd::string FtraceFsOps::GetPrintkFormats() const
9906f6ba60Sopenharmony_ci{
10006f6ba60Sopenharmony_ci    return ReadTraceFile("/printk_formats");
10106f6ba60Sopenharmony_ci}
10206f6ba60Sopenharmony_ci
10306f6ba60Sopenharmony_cistd::string GetKptrRestrict()
10406f6ba60Sopenharmony_ci{
10506f6ba60Sopenharmony_ci    return FileUtils::ReadFile("/proc/sys/kernel/kptr_restrict");
10606f6ba60Sopenharmony_ci}
10706f6ba60Sopenharmony_ci
10806f6ba60Sopenharmony_cibool SetKptrRestrict(const std::string& value)
10906f6ba60Sopenharmony_ci{
11006f6ba60Sopenharmony_ci    return FileUtils::WriteFile("/proc/sys/kernel/kptr_restrict", value) > 0;
11106f6ba60Sopenharmony_ci}
11206f6ba60Sopenharmony_ci
11306f6ba60Sopenharmony_cistd::string FtraceFsOps::GetKernelSymbols() const
11406f6ba60Sopenharmony_ci{
11506f6ba60Sopenharmony_ci    if (COMMON::IsUserMode()) {
11606f6ba60Sopenharmony_ci        PROFILER_LOG_ERROR(LOG_CORE, "GetKernelSymbols failed, only root mode can access kernel symbols");
11706f6ba60Sopenharmony_ci        return "";
11806f6ba60Sopenharmony_ci    }
11906f6ba60Sopenharmony_ci    std::string restrictValue = GetKptrRestrict();
12006f6ba60Sopenharmony_ci    CHECK_TRUE(restrictValue.size() > 0, "", "read kptr_restrict failed!");
12106f6ba60Sopenharmony_ci
12206f6ba60Sopenharmony_ci    bool valueChanged = false;
12306f6ba60Sopenharmony_ci    if (std::stoi(restrictValue) == 0) {
12406f6ba60Sopenharmony_ci        SetKptrRestrict("1");
12506f6ba60Sopenharmony_ci        valueChanged = true;
12606f6ba60Sopenharmony_ci    }
12706f6ba60Sopenharmony_ci
12806f6ba60Sopenharmony_ci    std::string result = FileUtils::ReadFile("/proc/kallsyms");
12906f6ba60Sopenharmony_ci    if (valueChanged) {
13006f6ba60Sopenharmony_ci        SetKptrRestrict(restrictValue);
13106f6ba60Sopenharmony_ci    }
13206f6ba60Sopenharmony_ci    return result;
13306f6ba60Sopenharmony_ci}
13406f6ba60Sopenharmony_ci
13506f6ba60Sopenharmony_cibool FtraceFsOps::SetSavedCmdLinesSize(uint32_t size)
13606f6ba60Sopenharmony_ci{
13706f6ba60Sopenharmony_ci    std::string path = "/saved_cmdlines_size";
13806f6ba60Sopenharmony_ci    return WriteTraceFile(path, std::to_string(static_cast<int>(size))) > 0;
13906f6ba60Sopenharmony_ci}
14006f6ba60Sopenharmony_ci
14106f6ba60Sopenharmony_cistd::string FtraceFsOps::GetSavedCmdLines() const
14206f6ba60Sopenharmony_ci{
14306f6ba60Sopenharmony_ci    return ReadTraceFile("/saved_cmdlines");
14406f6ba60Sopenharmony_ci}
14506f6ba60Sopenharmony_ci
14606f6ba60Sopenharmony_cistd::string FtraceFsOps::GetSavedTgids() const
14706f6ba60Sopenharmony_ci{
14806f6ba60Sopenharmony_ci    return ReadTraceFile("/saved_tgids");
14906f6ba60Sopenharmony_ci}
15006f6ba60Sopenharmony_ci
15106f6ba60Sopenharmony_cistd::string FtraceFsOps::GetProcessComm(int pid)
15206f6ba60Sopenharmony_ci{
15306f6ba60Sopenharmony_ci    std::string path = "/proc/" + std::to_string(pid) + "/comm";
15406f6ba60Sopenharmony_ci    if (access(path.c_str(), R_OK) != 0) {
15506f6ba60Sopenharmony_ci        return "";
15606f6ba60Sopenharmony_ci    }
15706f6ba60Sopenharmony_ci    return FileUtils::ReadFile(path);
15806f6ba60Sopenharmony_ci}
15906f6ba60Sopenharmony_ci
16006f6ba60Sopenharmony_cistd::string FtraceFsOps::GetThreadComm(int pid, int tid)
16106f6ba60Sopenharmony_ci{
16206f6ba60Sopenharmony_ci    std::string path = "/proc/" + std::to_string(pid) + "/task/" + std::to_string(tid) + "/comm";
16306f6ba60Sopenharmony_ci    if (access(path.c_str(), R_OK) != 0) {
16406f6ba60Sopenharmony_ci        return "";
16506f6ba60Sopenharmony_ci    }
16606f6ba60Sopenharmony_ci    return FileUtils::ReadFile(path);
16706f6ba60Sopenharmony_ci}
16806f6ba60Sopenharmony_ci
16906f6ba60Sopenharmony_cistd::string FtraceFsOps::GetPerCpuStats(int cpu) const
17006f6ba60Sopenharmony_ci{
17106f6ba60Sopenharmony_ci    return ReadTraceFile("/per_cpu/cpu" + std::to_string(cpu) + "/stats");
17206f6ba60Sopenharmony_ci}
17306f6ba60Sopenharmony_ci
17406f6ba60Sopenharmony_cistd::string FtraceFsOps::GetRawTracePath(int cpu) const
17506f6ba60Sopenharmony_ci{
17606f6ba60Sopenharmony_ci    return ftraceRoot_ + "/per_cpu/cpu" + std::to_string(cpu) + "/trace_pipe_raw";
17706f6ba60Sopenharmony_ci}
17806f6ba60Sopenharmony_ci
17906f6ba60Sopenharmony_cistd::string FtraceFsOps::GetHmRawTracePath() const
18006f6ba60Sopenharmony_ci{
18106f6ba60Sopenharmony_ci    return ftraceRoot_ + "/trace_pipe_raw";
18206f6ba60Sopenharmony_ci}
18306f6ba60Sopenharmony_ci
18406f6ba60Sopenharmony_cistd::string FtraceFsOps::GetPageHeaderFormat() const
18506f6ba60Sopenharmony_ci{
18606f6ba60Sopenharmony_ci    return ReadTraceFile("/events/header_page");
18706f6ba60Sopenharmony_ci}
18806f6ba60Sopenharmony_ci
18906f6ba60Sopenharmony_cistd::string FtraceFsOps::GetEventDataFormat(const std::string& type, const std::string& name) const
19006f6ba60Sopenharmony_ci{
19106f6ba60Sopenharmony_ci    if (access((ftraceRoot_ + "/events/" + type + "/" + name + "/format").c_str(), R_OK) == 0) {
19206f6ba60Sopenharmony_ci        return FileUtils::ReadFile(ftraceRoot_ + "/events/" + type + "/" + name + "/format");
19306f6ba60Sopenharmony_ci    } else {
19406f6ba60Sopenharmony_ci        return "";
19506f6ba60Sopenharmony_ci    }
19606f6ba60Sopenharmony_ci}
19706f6ba60Sopenharmony_ci
19806f6ba60Sopenharmony_cibool FtraceFsOps::ClearTraceBuffer()
19906f6ba60Sopenharmony_ci{
20006f6ba60Sopenharmony_ci    char realPath[PATH_MAX + 1] = {0};
20106f6ba60Sopenharmony_ci
20206f6ba60Sopenharmony_ci    std::string path = ftraceRoot_ + "/trace";
20306f6ba60Sopenharmony_ci
20406f6ba60Sopenharmony_ci    CHECK_TRUE((path.length() < PATH_MAX) && (realpath(path.c_str(), realPath) != nullptr), false,
20506f6ba60Sopenharmony_ci               "%s:path is invalid: %s, errno=%d", __func__, path.c_str(), errno);
20606f6ba60Sopenharmony_ci    int fd = open(realPath, O_TRUNC | O_RDWR);
20706f6ba60Sopenharmony_ci    CHECK_TRUE(fd >= 0, false, "open %s failed!", realPath);
20806f6ba60Sopenharmony_ci    return close(fd) == 0;
20906f6ba60Sopenharmony_ci}
21006f6ba60Sopenharmony_ci
21106f6ba60Sopenharmony_cibool FtraceFsOps::SetRecordCmdOption(bool enable)
21206f6ba60Sopenharmony_ci{
21306f6ba60Sopenharmony_ci    std::string path = "/options/record-cmd";
21406f6ba60Sopenharmony_ci    return WriteTraceFile(path, std::to_string(static_cast<int>(enable))) > 0;
21506f6ba60Sopenharmony_ci}
21606f6ba60Sopenharmony_ci
21706f6ba60Sopenharmony_cibool FtraceFsOps::SetRecordTgidOption(bool enable)
21806f6ba60Sopenharmony_ci{
21906f6ba60Sopenharmony_ci    std::string path = "/options/record-tgid";
22006f6ba60Sopenharmony_ci    return WriteTraceFile(path, std::to_string(static_cast<int>(enable))) > 0;
22106f6ba60Sopenharmony_ci}
22206f6ba60Sopenharmony_ci
22306f6ba60Sopenharmony_cibool FtraceFsOps::SetBufferSizeKb(int sizeKb)
22406f6ba60Sopenharmony_ci{
22506f6ba60Sopenharmony_ci    std::string path = "/buffer_size_kb";
22606f6ba60Sopenharmony_ci    return WriteTraceFile(path, std::to_string(sizeKb)) > 0;
22706f6ba60Sopenharmony_ci}
22806f6ba60Sopenharmony_ci
22906f6ba60Sopenharmony_cibool FtraceFsOps::SetTraceClock(const std::string& clock)
23006f6ba60Sopenharmony_ci{
23106f6ba60Sopenharmony_ci    std::string path = "/trace_clock";
23206f6ba60Sopenharmony_ci    return WriteTraceFile(path, clock) > 0;
23306f6ba60Sopenharmony_ci}
23406f6ba60Sopenharmony_ci
23506f6ba60Sopenharmony_cistd::string FtraceFsOps::GetTraceClock()
23606f6ba60Sopenharmony_ci{
23706f6ba60Sopenharmony_ci    std::string path = ftraceRoot_ + "/trace_clock";
23806f6ba60Sopenharmony_ci
23906f6ba60Sopenharmony_ci    std::string value = FileUtils::ReadFile(path);
24006f6ba60Sopenharmony_ci    auto pos = value.find('[');
24106f6ba60Sopenharmony_ci    CHECK_TRUE(pos != std::string::npos, "", "find [ in %s failed!", path.c_str());
24206f6ba60Sopenharmony_ci    pos++;
24306f6ba60Sopenharmony_ci
24406f6ba60Sopenharmony_ci    auto rpos = value.find(']', pos);
24506f6ba60Sopenharmony_ci    CHECK_TRUE(rpos != std::string::npos, "", "find ] in %s failed!", path.c_str());
24606f6ba60Sopenharmony_ci    return value.substr(pos, rpos - pos);
24706f6ba60Sopenharmony_ci}
24806f6ba60Sopenharmony_ci
24906f6ba60Sopenharmony_cistatic void AddPlatformEvents(std::set<std::pair<std::string, std::string>> &eventSet,
25006f6ba60Sopenharmony_ci    const std::string &eventsPath)
25106f6ba60Sopenharmony_ci{
25206f6ba60Sopenharmony_ci    for (auto& type : FileUtils::ListDir(eventsPath)) {
25306f6ba60Sopenharmony_ci        struct stat st = {};
25406f6ba60Sopenharmony_ci        std::string typePath = eventsPath + "/" + type;
25506f6ba60Sopenharmony_ci        if (stat(typePath.c_str(), &st) != 0 || !S_ISDIR(st.st_mode)) {
25606f6ba60Sopenharmony_ci            continue;
25706f6ba60Sopenharmony_ci        }
25806f6ba60Sopenharmony_ci        for (auto& name : FileUtils::ListDir(typePath)) {
25906f6ba60Sopenharmony_ci            struct stat st = {};
26006f6ba60Sopenharmony_ci            std::string namePath = typePath + "/" + name;
26106f6ba60Sopenharmony_ci            if (stat(namePath.c_str(), &st) != 0 || !S_ISDIR(st.st_mode)) {
26206f6ba60Sopenharmony_ci                continue;
26306f6ba60Sopenharmony_ci            }
26406f6ba60Sopenharmony_ci            eventSet.insert(std::make_pair(type, name));
26506f6ba60Sopenharmony_ci        }
26606f6ba60Sopenharmony_ci    }
26706f6ba60Sopenharmony_ci}
26806f6ba60Sopenharmony_ci
26906f6ba60Sopenharmony_cistd::vector<std::pair<std::string, std::string>> FtraceFsOps::GetPlatformEvents()
27006f6ba60Sopenharmony_ci{
27106f6ba60Sopenharmony_ci    std::set<std::pair<std::string, std::string>> eventSet;
27206f6ba60Sopenharmony_ci    if (IsHmKernel()) {
27306f6ba60Sopenharmony_ci        AddPlatformEvents(eventSet, ftraceRoot_ + "/events");
27406f6ba60Sopenharmony_ci    }
27506f6ba60Sopenharmony_ci    AddPlatformEvents(eventSet, ftraceRoot_ + "/events");
27606f6ba60Sopenharmony_ci    PROFILER_LOG_INFO(LOG_CORE, "get platform event formats done, types: %zu!", eventSet.size());
27706f6ba60Sopenharmony_ci    return {eventSet.begin(), eventSet.end()};
27806f6ba60Sopenharmony_ci}
27906f6ba60Sopenharmony_ci
28006f6ba60Sopenharmony_cibool FtraceFsOps::AppendSetEvent(const std::string& type, const std::string& name)
28106f6ba60Sopenharmony_ci{
28206f6ba60Sopenharmony_ci    std::string path = "/set_event";
28306f6ba60Sopenharmony_ci    return WriteTraceFile(path, type + ":" + name + "\n", O_WRONLY | O_APPEND) > 0;
28406f6ba60Sopenharmony_ci}
28506f6ba60Sopenharmony_ci
28606f6ba60Sopenharmony_cibool FtraceFsOps::ClearSetEvent()
28706f6ba60Sopenharmony_ci{
28806f6ba60Sopenharmony_ci    return WriteTraceFile("/set_event", "\n", O_WRONLY | O_TRUNC) > 0;
28906f6ba60Sopenharmony_ci}
29006f6ba60Sopenharmony_ci
29106f6ba60Sopenharmony_cibool FtraceFsOps::EnableEvent(const std::string& type, const std::string& name)
29206f6ba60Sopenharmony_ci{
29306f6ba60Sopenharmony_ci    std::string enablePath = "/events/" + type + "/" + name + "/enable";
29406f6ba60Sopenharmony_ci    return WriteTraceFile(enablePath, "1") > 0;
29506f6ba60Sopenharmony_ci}
29606f6ba60Sopenharmony_ci
29706f6ba60Sopenharmony_cibool FtraceFsOps::DisableEvent(const std::string& type, const std::string& name)
29806f6ba60Sopenharmony_ci{
29906f6ba60Sopenharmony_ci    std::string enablePath = "/events/" + type + "/" + name + "/enable";
30006f6ba60Sopenharmony_ci    return WriteTraceFile(enablePath, "0") > 0;
30106f6ba60Sopenharmony_ci}
30206f6ba60Sopenharmony_ci
30306f6ba60Sopenharmony_cibool FtraceFsOps::DisableCategories(const std::string& categories)
30406f6ba60Sopenharmony_ci{
30506f6ba60Sopenharmony_ci    std::string enablePath = "/events/" + categories + "/enable";
30606f6ba60Sopenharmony_ci    return WriteTraceFile(enablePath, "0") > 0;
30706f6ba60Sopenharmony_ci}
30806f6ba60Sopenharmony_ci
30906f6ba60Sopenharmony_cibool FtraceFsOps::EnableTracing()
31006f6ba60Sopenharmony_ci{
31106f6ba60Sopenharmony_ci    std::string tracingOn = "/tracing_on";
31206f6ba60Sopenharmony_ci    return WriteTraceFile(tracingOn, "1") > 0;
31306f6ba60Sopenharmony_ci}
31406f6ba60Sopenharmony_ci
31506f6ba60Sopenharmony_cibool FtraceFsOps::DisableTracing()
31606f6ba60Sopenharmony_ci{
31706f6ba60Sopenharmony_ci    std::string tracingOn = "/tracing_on";
31806f6ba60Sopenharmony_ci    return WriteTraceFile(tracingOn, "0") > 0;
31906f6ba60Sopenharmony_ci}
32006f6ba60Sopenharmony_ciFTRACE_NS_END
321