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