1 /*
2  * Copyright (c) Huawei Technologies Co., Ltd. 2021. All rights reserved.
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 "ftrace_fs_ops.h"
16 
17 #include <fcntl.h>
18 #include <set>
19 #include <sys/stat.h>
20 #include <sys/types.h>
21 #include <sys/utsname.h>
22 #include <unistd.h>
23 #include "common.h"
24 #include "file_utils.h"
25 #include "logging.h"
26 
27 FTRACE_NS_BEGIN
GetInstance()28 FtraceFsOps& FtraceFsOps::GetInstance()
29 {
30     static FtraceFsOps instance;
31     return instance;
32 }
33 
FtraceFsOps()34 FtraceFsOps::FtraceFsOps() : ftraceRoot_(GetFtraceRoot())
35 {
36     PROFILER_LOG_INFO(LOG_CORE, "FtraceFsOps create!");
37 }
38 
~FtraceFsOps()39 FtraceFsOps::~FtraceFsOps()
40 {
41     PROFILER_LOG_INFO(LOG_CORE, "FtraceFsOps destroy!");
42 }
43 
GetFtraceRoot()44 std::string FtraceFsOps::GetFtraceRoot()
45 {
46     std::vector<std::string> testRootPath = {"/sys/kernel/tracing", "/sys/kernel/debug/tracing"};
47     for (auto iter = testRootPath.begin(); iter != testRootPath.end(); ++iter) {
48         auto path = *iter + "/events";
49         struct stat s;
50         lstat(path.c_str(), &s);
51         if (S_ISDIR(s.st_mode)) {
52             return *iter;
53         }
54     }
55     return "";
56 }
57 
IsHmKernel()58 bool FtraceFsOps::IsHmKernel()
59 {
60     bool isHM = false;
61     utsname unameBuf;
62     if ((uname(&unameBuf)) == 0) {
63         std::string osRelease = unameBuf.release;
64         isHM = osRelease.find("HongMeng") != std::string::npos;
65     }
66     return isHM;
67 }
68 
WriteTraceFile(const std::string& path, const std::string& content)69 int FtraceFsOps::WriteTraceFile(const std::string& path, const std::string& content)
70 {
71     bool ret = false;
72     if (access((ftraceRoot_ + path).c_str(), W_OK) == 0) {
73         if (FileUtils::WriteFile(ftraceRoot_ + path, content) > 0) {
74             ret = true;
75         }
76     }
77 
78     return (int)ret;
79 }
80 
WriteTraceFile(const std::string& path, const std::string& content, int flags)81 int FtraceFsOps::WriteTraceFile(const std::string& path, const std::string& content, int flags)
82 {
83     bool ret = false;
84     if (access((ftraceRoot_ + path).c_str(), W_OK) == 0) {
85         if (FileUtils::WriteFile(ftraceRoot_ + path, content, flags) > 0) {
86             ret = true;
87         }
88     }
89 
90     return (int)ret;
91 }
92 
ReadTraceFile(const std::string& path) const93 std::string FtraceFsOps::ReadTraceFile(const std::string& path) const
94 {
95     return FileUtils::ReadFile(ftraceRoot_ + path);
96 }
97 
GetPrintkFormats() const98 std::string FtraceFsOps::GetPrintkFormats() const
99 {
100     return ReadTraceFile("/printk_formats");
101 }
102 
GetKptrRestrict()103 std::string GetKptrRestrict()
104 {
105     return FileUtils::ReadFile("/proc/sys/kernel/kptr_restrict");
106 }
107 
SetKptrRestrict(const std::string& value)108 bool SetKptrRestrict(const std::string& value)
109 {
110     return FileUtils::WriteFile("/proc/sys/kernel/kptr_restrict", value) > 0;
111 }
112 
GetKernelSymbols() const113 std::string FtraceFsOps::GetKernelSymbols() const
114 {
115     if (COMMON::IsUserMode()) {
116         PROFILER_LOG_ERROR(LOG_CORE, "GetKernelSymbols failed, only root mode can access kernel symbols");
117         return "";
118     }
119     std::string restrictValue = GetKptrRestrict();
120     CHECK_TRUE(restrictValue.size() > 0, "", "read kptr_restrict failed!");
121 
122     bool valueChanged = false;
123     if (std::stoi(restrictValue) == 0) {
124         SetKptrRestrict("1");
125         valueChanged = true;
126     }
127 
128     std::string result = FileUtils::ReadFile("/proc/kallsyms");
129     if (valueChanged) {
130         SetKptrRestrict(restrictValue);
131     }
132     return result;
133 }
134 
SetSavedCmdLinesSize(uint32_t size)135 bool FtraceFsOps::SetSavedCmdLinesSize(uint32_t size)
136 {
137     std::string path = "/saved_cmdlines_size";
138     return WriteTraceFile(path, std::to_string(static_cast<int>(size))) > 0;
139 }
140 
GetSavedCmdLines() const141 std::string FtraceFsOps::GetSavedCmdLines() const
142 {
143     return ReadTraceFile("/saved_cmdlines");
144 }
145 
GetSavedTgids() const146 std::string FtraceFsOps::GetSavedTgids() const
147 {
148     return ReadTraceFile("/saved_tgids");
149 }
150 
GetProcessComm(int pid)151 std::string FtraceFsOps::GetProcessComm(int pid)
152 {
153     std::string path = "/proc/" + std::to_string(pid) + "/comm";
154     if (access(path.c_str(), R_OK) != 0) {
155         return "";
156     }
157     return FileUtils::ReadFile(path);
158 }
159 
GetThreadComm(int pid, int tid)160 std::string FtraceFsOps::GetThreadComm(int pid, int tid)
161 {
162     std::string path = "/proc/" + std::to_string(pid) + "/task/" + std::to_string(tid) + "/comm";
163     if (access(path.c_str(), R_OK) != 0) {
164         return "";
165     }
166     return FileUtils::ReadFile(path);
167 }
168 
GetPerCpuStats(int cpu) const169 std::string FtraceFsOps::GetPerCpuStats(int cpu) const
170 {
171     return ReadTraceFile("/per_cpu/cpu" + std::to_string(cpu) + "/stats");
172 }
173 
GetRawTracePath(int cpu) const174 std::string FtraceFsOps::GetRawTracePath(int cpu) const
175 {
176     return ftraceRoot_ + "/per_cpu/cpu" + std::to_string(cpu) + "/trace_pipe_raw";
177 }
178 
GetHmRawTracePath() const179 std::string FtraceFsOps::GetHmRawTracePath() const
180 {
181     return ftraceRoot_ + "/trace_pipe_raw";
182 }
183 
GetPageHeaderFormat() const184 std::string FtraceFsOps::GetPageHeaderFormat() const
185 {
186     return ReadTraceFile("/events/header_page");
187 }
188 
GetEventDataFormat(const std::string& type, const std::string& name) const189 std::string FtraceFsOps::GetEventDataFormat(const std::string& type, const std::string& name) const
190 {
191     if (access((ftraceRoot_ + "/events/" + type + "/" + name + "/format").c_str(), R_OK) == 0) {
192         return FileUtils::ReadFile(ftraceRoot_ + "/events/" + type + "/" + name + "/format");
193     } else {
194         return "";
195     }
196 }
197 
ClearTraceBuffer()198 bool FtraceFsOps::ClearTraceBuffer()
199 {
200     char realPath[PATH_MAX + 1] = {0};
201 
202     std::string path = ftraceRoot_ + "/trace";
203 
204     CHECK_TRUE((path.length() < PATH_MAX) && (realpath(path.c_str(), realPath) != nullptr), false,
205                "%s:path is invalid: %s, errno=%d", __func__, path.c_str(), errno);
206     int fd = open(realPath, O_TRUNC | O_RDWR);
207     CHECK_TRUE(fd >= 0, false, "open %s failed!", realPath);
208     return close(fd) == 0;
209 }
210 
SetRecordCmdOption(bool enable)211 bool FtraceFsOps::SetRecordCmdOption(bool enable)
212 {
213     std::string path = "/options/record-cmd";
214     return WriteTraceFile(path, std::to_string(static_cast<int>(enable))) > 0;
215 }
216 
SetRecordTgidOption(bool enable)217 bool FtraceFsOps::SetRecordTgidOption(bool enable)
218 {
219     std::string path = "/options/record-tgid";
220     return WriteTraceFile(path, std::to_string(static_cast<int>(enable))) > 0;
221 }
222 
SetBufferSizeKb(int sizeKb)223 bool FtraceFsOps::SetBufferSizeKb(int sizeKb)
224 {
225     std::string path = "/buffer_size_kb";
226     return WriteTraceFile(path, std::to_string(sizeKb)) > 0;
227 }
228 
SetTraceClock(const std::string& clock)229 bool FtraceFsOps::SetTraceClock(const std::string& clock)
230 {
231     std::string path = "/trace_clock";
232     return WriteTraceFile(path, clock) > 0;
233 }
234 
GetTraceClock()235 std::string FtraceFsOps::GetTraceClock()
236 {
237     std::string path = ftraceRoot_ + "/trace_clock";
238 
239     std::string value = FileUtils::ReadFile(path);
240     auto pos = value.find('[');
241     CHECK_TRUE(pos != std::string::npos, "", "find [ in %s failed!", path.c_str());
242     pos++;
243 
244     auto rpos = value.find(']', pos);
245     CHECK_TRUE(rpos != std::string::npos, "", "find ] in %s failed!", path.c_str());
246     return value.substr(pos, rpos - pos);
247 }
248 
AddPlatformEvents(std::set<std::pair<std::string, std::string>> &eventSet, const std::string &eventsPath)249 static void AddPlatformEvents(std::set<std::pair<std::string, std::string>> &eventSet,
250     const std::string &eventsPath)
251 {
252     for (auto& type : FileUtils::ListDir(eventsPath)) {
253         struct stat st = {};
254         std::string typePath = eventsPath + "/" + type;
255         if (stat(typePath.c_str(), &st) != 0 || !S_ISDIR(st.st_mode)) {
256             continue;
257         }
258         for (auto& name : FileUtils::ListDir(typePath)) {
259             struct stat st = {};
260             std::string namePath = typePath + "/" + name;
261             if (stat(namePath.c_str(), &st) != 0 || !S_ISDIR(st.st_mode)) {
262                 continue;
263             }
264             eventSet.insert(std::make_pair(type, name));
265         }
266     }
267 }
268 
GetPlatformEvents()269 std::vector<std::pair<std::string, std::string>> FtraceFsOps::GetPlatformEvents()
270 {
271     std::set<std::pair<std::string, std::string>> eventSet;
272     if (IsHmKernel()) {
273         AddPlatformEvents(eventSet, ftraceRoot_ + "/events");
274     }
275     AddPlatformEvents(eventSet, ftraceRoot_ + "/events");
276     PROFILER_LOG_INFO(LOG_CORE, "get platform event formats done, types: %zu!", eventSet.size());
277     return {eventSet.begin(), eventSet.end()};
278 }
279 
AppendSetEvent(const std::string& type, const std::string& name)280 bool FtraceFsOps::AppendSetEvent(const std::string& type, const std::string& name)
281 {
282     std::string path = "/set_event";
283     return WriteTraceFile(path, type + ":" + name + "\n", O_WRONLY | O_APPEND) > 0;
284 }
285 
ClearSetEvent()286 bool FtraceFsOps::ClearSetEvent()
287 {
288     return WriteTraceFile("/set_event", "\n", O_WRONLY | O_TRUNC) > 0;
289 }
290 
EnableEvent(const std::string& type, const std::string& name)291 bool FtraceFsOps::EnableEvent(const std::string& type, const std::string& name)
292 {
293     std::string enablePath = "/events/" + type + "/" + name + "/enable";
294     return WriteTraceFile(enablePath, "1") > 0;
295 }
296 
DisableEvent(const std::string& type, const std::string& name)297 bool FtraceFsOps::DisableEvent(const std::string& type, const std::string& name)
298 {
299     std::string enablePath = "/events/" + type + "/" + name + "/enable";
300     return WriteTraceFile(enablePath, "0") > 0;
301 }
302 
DisableCategories(const std::string& categories)303 bool FtraceFsOps::DisableCategories(const std::string& categories)
304 {
305     std::string enablePath = "/events/" + categories + "/enable";
306     return WriteTraceFile(enablePath, "0") > 0;
307 }
308 
EnableTracing()309 bool FtraceFsOps::EnableTracing()
310 {
311     std::string tracingOn = "/tracing_on";
312     return WriteTraceFile(tracingOn, "1") > 0;
313 }
314 
DisableTracing()315 bool FtraceFsOps::DisableTracing()
316 {
317     std::string tracingOn = "/tracing_on";
318     return WriteTraceFile(tracingOn, "0") > 0;
319 }
320 FTRACE_NS_END
321