• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
GetTgidFromStatus(int pid) const167 int FtraceFsOps::GetTgidFromStatus(int pid) const
168 {
169     std::string statusPath = "/proc/" + std::to_string(pid) + "/status";
170     std::ifstream statusFile(statusPath);
171     if (!statusFile.is_open()) {
172         return -1;
173     }
174     std::string line;
175     while (std::getline(statusFile, line)) {
176         if (line.find("Tgid:") == 0) {
177             std::istringstream iss(line);
178             std::string key;
179             int tgid = 0;
180             if (iss >> key >> tgid) {
181                 return tgid;
182             }
183             break;
184         }
185     }
186     return -1;
187 }
188 
GetProcessComm(int pid)189 std::string FtraceFsOps::GetProcessComm(int pid)
190 {
191     std::string path = "/proc/" + std::to_string(pid) + "/comm";
192     if (access(path.c_str(), R_OK) != 0) {
193         return "";
194     }
195     return FileUtils::ReadFile(path);
196 }
197 
GetThreadComm(int pid,int tid)198 std::string FtraceFsOps::GetThreadComm(int pid, int tid)
199 {
200     std::string path = "/proc/" + std::to_string(pid) + "/task/" + std::to_string(tid) + "/comm";
201     if (access(path.c_str(), R_OK) != 0) {
202         return "";
203     }
204     return FileUtils::ReadFile(path);
205 }
206 
GetPerCpuStats(int cpu) const207 std::string FtraceFsOps::GetPerCpuStats(int cpu) const
208 {
209     return ReadTraceFile("/per_cpu/cpu" + std::to_string(cpu) + "/stats");
210 }
211 
GetRawTracePath(int cpu) const212 std::string FtraceFsOps::GetRawTracePath(int cpu) const
213 {
214     return ftraceRoot_ + "/per_cpu/cpu" + std::to_string(cpu) + "/trace_pipe_raw";
215 }
216 
GetHmRawTracePath() const217 std::string FtraceFsOps::GetHmRawTracePath() const
218 {
219     return ftraceRoot_ + "/trace_pipe_raw";
220 }
221 
GetPageHeaderFormat() const222 std::string FtraceFsOps::GetPageHeaderFormat() const
223 {
224     return ReadTraceFile("/events/header_page");
225 }
226 
GetEventDataFormat(const std::string & type,const std::string & name) const227 std::string FtraceFsOps::GetEventDataFormat(const std::string& type, const std::string& name) const
228 {
229     return FileUtils::ReadFile(ftraceRoot_ + "/events/" + type + "/" + name + "/format");
230 }
231 
ClearTraceBuffer()232 bool FtraceFsOps::ClearTraceBuffer()
233 {
234     char realPath[PATH_MAX + 1] = {0};
235 
236     std::string path = ftraceRoot_ + "/trace";
237 
238     CHECK_TRUE((path.length() < PATH_MAX) && (realpath(path.c_str(), realPath) != nullptr), false,
239                "%s:path is invalid: %s, errno=%d", __func__, path.c_str(), errno);
240     int fd = open(realPath, O_TRUNC | O_RDWR);
241     CHECK_TRUE(fd >= 0, false, "open %s failed!", realPath);
242     return close(fd) == 0;
243 }
244 
SetRecordCmdOption(bool enable)245 bool FtraceFsOps::SetRecordCmdOption(bool enable)
246 {
247     std::string path = "/options/record-cmd";
248     return WriteTraceFile(path, std::to_string(static_cast<int>(enable))) > 0;
249 }
250 
SetRecordTgidOption(bool enable)251 bool FtraceFsOps::SetRecordTgidOption(bool enable)
252 {
253     std::string path = "/options/record-tgid";
254     return WriteTraceFile(path, std::to_string(static_cast<int>(enable))) > 0;
255 }
256 
SetBufferSizeKb(int sizeKb)257 bool FtraceFsOps::SetBufferSizeKb(int sizeKb)
258 {
259     std::string path = "/buffer_size_kb";
260     return WriteTraceFile(path, std::to_string(sizeKb)) > 0;
261 }
262 
SetTraceClock(const std::string & clock)263 bool FtraceFsOps::SetTraceClock(const std::string& clock)
264 {
265     std::string path = "/trace_clock";
266     return WriteTraceFile(path, clock) > 0;
267 }
268 
GetTraceClock()269 std::string FtraceFsOps::GetTraceClock()
270 {
271     std::string path = ftraceRoot_ + "/trace_clock";
272 
273     std::string value = FileUtils::ReadFile(path);
274     auto pos = value.find('[');
275     CHECK_TRUE(pos != std::string::npos, "", "find [ in %s failed!", path.c_str());
276     pos++;
277 
278     auto rpos = value.find(']', pos);
279     CHECK_TRUE(rpos != std::string::npos, "", "find ] in %s failed!", path.c_str());
280     return value.substr(pos, rpos - pos);
281 }
282 
AddPlatformEvents(std::set<std::pair<std::string,std::string>> & eventSet,const std::string & eventsPath)283 static void AddPlatformEvents(std::set<std::pair<std::string, std::string>> &eventSet,
284     const std::string &eventsPath)
285 {
286     for (auto& type : FileUtils::ListDir(eventsPath)) {
287         struct stat st = {};
288         std::string typePath = eventsPath + "/" + type;
289         if (stat(typePath.c_str(), &st) != 0 || !S_ISDIR(st.st_mode)) {
290             continue;
291         }
292         for (auto& name : FileUtils::ListDir(typePath)) {
293             struct stat st = {};
294             std::string namePath = typePath + "/" + name;
295             if (stat(namePath.c_str(), &st) != 0 || !S_ISDIR(st.st_mode)) {
296                 continue;
297             }
298             eventSet.insert(std::make_pair(type, name));
299         }
300     }
301 }
302 
GetPlatformEvents()303 std::vector<std::pair<std::string, std::string>> FtraceFsOps::GetPlatformEvents()
304 {
305     std::set<std::pair<std::string, std::string>> eventSet;
306     if (IsHmKernel()) {
307         AddPlatformEvents(eventSet, ftraceRoot_ + "/events");
308     }
309     AddPlatformEvents(eventSet, ftraceRoot_ + "/events");
310     PROFILER_LOG_INFO(LOG_CORE, "get platform event formats done, types: %zu!", eventSet.size());
311     return {eventSet.begin(), eventSet.end()};
312 }
313 
AppendSetEvent(const std::string & type,const std::string & name)314 bool FtraceFsOps::AppendSetEvent(const std::string& type, const std::string& name)
315 {
316     std::string path = "/set_event";
317     return WriteTraceFile(path, type + ":" + name + "\n", O_WRONLY | O_APPEND) > 0;
318 }
319 
ClearSetEvent()320 bool FtraceFsOps::ClearSetEvent()
321 {
322     return WriteTraceFile("/set_event", "\n", O_WRONLY | O_TRUNC) > 0;
323 }
324 
EnableEvent(const std::string & type,const std::string & name)325 bool FtraceFsOps::EnableEvent(const std::string& type, const std::string& name)
326 {
327     std::string enablePath = "/events/" + type + "/" + name + "/enable";
328     return WriteTraceFile(enablePath, "1") > 0;
329 }
330 
DisableEvent(const std::string & type,const std::string & name)331 bool FtraceFsOps::DisableEvent(const std::string& type, const std::string& name)
332 {
333     std::string enablePath = "/events/" + type + "/" + name + "/enable";
334     return WriteTraceFile(enablePath, "0") > 0;
335 }
336 
DisableCategories(const std::string & categories)337 bool FtraceFsOps::DisableCategories(const std::string& categories)
338 {
339     std::string enablePath = "/events/" + categories + "/enable";
340     return WriteTraceFile(enablePath, "0") > 0;
341 }
342 
EnableTracing()343 bool FtraceFsOps::EnableTracing()
344 {
345     std::string tracingOn = "/tracing_on";
346     return WriteTraceFile(tracingOn, "1") > 0;
347 }
348 
DisableTracing()349 bool FtraceFsOps::DisableTracing()
350 {
351     std::string tracingOn = "/tracing_on";
352     return WriteTraceFile(tracingOn, "0") > 0;
353 }
354 FTRACE_NS_END
355