1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "src/traced/probes/ftrace/ftrace_procfs.h"
18 
19 #include <string.h>
20 #include <sys/stat.h>
21 #include <sys/types.h>
22 #include <unistd.h>
23 
24 #include <fstream>
25 #include <sstream>
26 #include <string>
27 
28 #include "perfetto/base/logging.h"
29 #include "perfetto/ext/base/file_utils.h"
30 #include "perfetto/ext/base/string_splitter.h"
31 #include "perfetto/ext/base/string_utils.h"
32 #include "perfetto/ext/base/utils.h"
33 
34 namespace perfetto {
35 
36 // Reading /trace produces human readable trace output.
37 // Writing to this file clears all trace buffers for all CPUS.
38 
39 // Writing to /trace_marker file injects an event into the trace buffer.
40 
41 // Reading /tracing_on returns 1/0 if tracing is enabled/disabled.
42 // Writing 1/0 to this file enables/disables tracing.
43 // Disabling tracing with this file prevents further writes but
44 // does not clear the buffer.
45 
46 namespace {
47 
KernelLogWrite(const char * s)48 void KernelLogWrite(const char* s) {
49   PERFETTO_DCHECK(*s && s[strlen(s) - 1] == '\n');
50   if (FtraceProcfs::g_kmesg_fd != -1)
51     base::ignore_result(base::WriteAll(FtraceProcfs::g_kmesg_fd, s, strlen(s)));
52 }
53 
WriteFileInternal(const std::string & path,const std::string & str,int flags)54 bool WriteFileInternal(const std::string& path,
55                        const std::string& str,
56                        int flags) {
57   base::ScopedFile fd = base::OpenFile(path, flags);
58   if (!fd)
59     return false;
60   ssize_t written = base::WriteAll(fd.get(), str.c_str(), str.length());
61   ssize_t length = static_cast<ssize_t>(str.length());
62   // This should either fail or write fully.
63   PERFETTO_CHECK(written == length || written == -1);
64   return written == length;
65 }
66 
67 }  // namespace
68 
69 // static
70 int FtraceProcfs::g_kmesg_fd = -1;  // Set by ProbesMain() in probes.cc .
71 
72 const char* const FtraceProcfs::kTracingPaths[] = {
73     "/sys/kernel/tracing/",
74     "/sys/kernel/debug/tracing/",
75     nullptr,
76 };
77 
78 // static
CreateGuessingMountPoint(const std::string & instance_path)79 std::unique_ptr<FtraceProcfs> FtraceProcfs::CreateGuessingMountPoint(
80     const std::string& instance_path) {
81   std::unique_ptr<FtraceProcfs> ftrace_procfs;
82   size_t index = 0;
83   while (!ftrace_procfs && kTracingPaths[index]) {
84     std::string path = kTracingPaths[index++];
85     if (!instance_path.empty())
86       path += instance_path;
87 
88     ftrace_procfs = Create(path);
89   }
90   return ftrace_procfs;
91 }
92 
93 // static
Create(const std::string & root)94 std::unique_ptr<FtraceProcfs> FtraceProcfs::Create(const std::string& root) {
95   if (!CheckRootPath(root)) {
96     return nullptr;
97   }
98   return std::unique_ptr<FtraceProcfs>(new FtraceProcfs(root));
99 }
100 
FtraceProcfs(const std::string & root)101 FtraceProcfs::FtraceProcfs(const std::string& root) : root_(root) {}
102 FtraceProcfs::~FtraceProcfs() = default;
103 
EnableEvent(const std::string & group,const std::string & name)104 bool FtraceProcfs::EnableEvent(const std::string& group,
105                                const std::string& name) {
106   std::string path = root_ + "events/" + group + "/" + name + "/enable";
107   if (WriteToFile(path, "1"))
108     return true;
109   path = root_ + "set_event";
110   return AppendToFile(path, group + ":" + name);
111 }
112 
DisableEvent(const std::string & group,const std::string & name)113 bool FtraceProcfs::DisableEvent(const std::string& group,
114                                 const std::string& name) {
115   std::string path = root_ + "events/" + group + "/" + name + "/enable";
116   if (WriteToFile(path, "0"))
117     return true;
118   path = root_ + "set_event";
119   return AppendToFile(path, "!" + group + ":" + name);
120 }
121 
DisableAllEvents()122 bool FtraceProcfs::DisableAllEvents() {
123   std::string path = root_ + "events/enable";
124   return WriteToFile(path, "0");
125 }
126 
ReadEventFormat(const std::string & group,const std::string & name) const127 std::string FtraceProcfs::ReadEventFormat(const std::string& group,
128                                           const std::string& name) const {
129   std::string path = root_ + "events/" + group + "/" + name + "/format";
130   return ReadFileIntoString(path);
131 }
132 
ReadPrintkFormats() const133 std::string FtraceProcfs::ReadPrintkFormats() const {
134   std::string path = root_ + "printk_formats";
135   return ReadFileIntoString(path);
136 }
137 
ReadEnabledEvents()138 std::vector<std::string> FtraceProcfs::ReadEnabledEvents() {
139   std::string path = root_ + "set_event";
140   std::string s = ReadFileIntoString(path);
141   base::StringSplitter ss(s, '\n');
142   std::vector<std::string> events;
143   while (ss.Next()) {
144     std::string event = ss.cur_token();
145     if (event.empty())
146       continue;
147     events.push_back(base::StripChars(event, ":", '/'));
148   }
149   return events;
150 }
151 
ReadPageHeaderFormat() const152 std::string FtraceProcfs::ReadPageHeaderFormat() const {
153   std::string path = root_ + "events/header_page";
154   return ReadFileIntoString(path);
155 }
156 
ReadCpuStats(size_t cpu) const157 std::string FtraceProcfs::ReadCpuStats(size_t cpu) const {
158   std::string path = root_ + "per_cpu/cpu" + std::to_string(cpu) + "/stats";
159   return ReadFileIntoString(path);
160 }
161 
NumberOfCpus() const162 size_t FtraceProcfs::NumberOfCpus() const {
163   static size_t num_cpus = static_cast<size_t>(sysconf(_SC_NPROCESSORS_CONF));
164   return num_cpus;
165 }
166 
ClearTrace()167 void FtraceProcfs::ClearTrace() {
168   std::string path = root_ + "trace";
169   PERFETTO_CHECK(ClearFile(path));  // Could not clear.
170 
171   // Truncating the trace file leads to tracing_reset_online_cpus being called
172   // in the kernel.
173   //
174   // In case some of the CPUs were not online, their buffer needs to be
175   // cleared manually.
176   //
177   // We cannot use PERFETTO_CHECK as we might get a permission denied error
178   // on Android. The permissions to these files are configured in
179   // platform/framework/native/cmds/atrace/atrace.rc.
180   for (size_t cpu = 0; cpu < NumberOfCpus(); cpu++) {
181     ClearPerCpuTrace(cpu);
182   }
183 }
184 
ClearPerCpuTrace(size_t cpu)185 void FtraceProcfs::ClearPerCpuTrace(size_t cpu) {
186   if (!ClearFile(root_ + "per_cpu/cpu" + std::to_string(cpu) + "/trace"))
187     PERFETTO_ELOG("Failed to clear buffer for CPU %zd", cpu);
188 }
189 
WriteTraceMarker(const std::string & str)190 bool FtraceProcfs::WriteTraceMarker(const std::string& str) {
191   std::string path = root_ + "trace_marker";
192   return WriteToFile(path, str);
193 }
194 
SetCpuBufferSizeInPages(size_t pages)195 bool FtraceProcfs::SetCpuBufferSizeInPages(size_t pages) {
196   if (pages * base::kPageSize > 1 * 1024 * 1024 * 1024) {
197     PERFETTO_ELOG("Tried to set the per CPU buffer size to more than 1gb.");
198     return false;
199   }
200   std::string path = root_ + "buffer_size_kb";
201   return WriteNumberToFile(path, pages * (base::kPageSize / 1024ul));
202 }
203 
EnableTracing()204 bool FtraceProcfs::EnableTracing() {
205   KernelLogWrite("perfetto: enabled ftrace\n");
206   PERFETTO_LOG("enabled ftrace in %s", root_.c_str());
207   std::string path = root_ + "tracing_on";
208   return WriteToFile(path, "1");
209 }
210 
DisableTracing()211 bool FtraceProcfs::DisableTracing() {
212   KernelLogWrite("perfetto: disabled ftrace\n");
213   PERFETTO_LOG("disabled ftrace in %s", root_.c_str());
214   std::string path = root_ + "tracing_on";
215   return WriteToFile(path, "0");
216 }
217 
SetTracingOn(bool enable)218 bool FtraceProcfs::SetTracingOn(bool enable) {
219   return enable ? EnableTracing() : DisableTracing();
220 }
221 
IsTracingEnabled()222 bool FtraceProcfs::IsTracingEnabled() {
223   std::string path = root_ + "tracing_on";
224   char tracing_on = ReadOneCharFromFile(path);
225   if (tracing_on == '\0')
226     PERFETTO_PLOG("Failed to read %s", path.c_str());
227   return tracing_on == '1';
228 }
229 
SetClock(const std::string & clock_name)230 bool FtraceProcfs::SetClock(const std::string& clock_name) {
231   std::string path = root_ + "trace_clock";
232   return WriteToFile(path, clock_name);
233 }
234 
GetClock()235 std::string FtraceProcfs::GetClock() {
236   std::string path = root_ + "trace_clock";
237   std::string s = ReadFileIntoString(path);
238 
239   size_t start = s.find('[');
240   if (start == std::string::npos)
241     return "";
242 
243   size_t end = s.find(']', start);
244   if (end == std::string::npos)
245     return "";
246 
247   return s.substr(start + 1, end - start - 1);
248 }
249 
AvailableClocks()250 std::set<std::string> FtraceProcfs::AvailableClocks() {
251   std::string path = root_ + "trace_clock";
252   std::string s = ReadFileIntoString(path);
253   std::set<std::string> names;
254 
255   size_t start = 0;
256   size_t end = 0;
257 
258   for (;;) {
259     end = s.find(' ', start);
260     if (end == std::string::npos)
261       end = s.size();
262     while (end > start && s[end - 1] == '\n')
263       end--;
264     if (start == end)
265       break;
266 
267     std::string name = s.substr(start, end - start);
268 
269     if (name[0] == '[')
270       name = name.substr(1, name.size() - 2);
271 
272     names.insert(name);
273 
274     if (end == s.size())
275       break;
276 
277     start = end + 1;
278   }
279 
280   return names;
281 }
282 
WriteNumberToFile(const std::string & path,size_t value)283 bool FtraceProcfs::WriteNumberToFile(const std::string& path, size_t value) {
284   // 2^65 requires 20 digits to write.
285   char buf[21];
286   int res = snprintf(buf, 21, "%zu", value);
287   if (res < 0 || res >= 21)
288     return false;
289   return WriteToFile(path, std::string(buf));
290 }
291 
WriteToFile(const std::string & path,const std::string & str)292 bool FtraceProcfs::WriteToFile(const std::string& path,
293                                const std::string& str) {
294   return WriteFileInternal(path, str, O_WRONLY);
295 }
296 
AppendToFile(const std::string & path,const std::string & str)297 bool FtraceProcfs::AppendToFile(const std::string& path,
298                                 const std::string& str) {
299   return WriteFileInternal(path, str, O_WRONLY | O_APPEND);
300 }
301 
OpenPipeForCpu(size_t cpu)302 base::ScopedFile FtraceProcfs::OpenPipeForCpu(size_t cpu) {
303   std::string path =
304       root_ + "per_cpu/cpu" + std::to_string(cpu) + "/trace_pipe_raw";
305   return base::OpenFile(path, O_RDONLY | O_NONBLOCK);
306 }
307 
ReadOneCharFromFile(const std::string & path)308 char FtraceProcfs::ReadOneCharFromFile(const std::string& path) {
309   base::ScopedFile fd = base::OpenFile(path, O_RDONLY);
310   PERFETTO_CHECK(fd);
311   char result = '\0';
312   ssize_t bytes = PERFETTO_EINTR(read(fd.get(), &result, 1));
313   PERFETTO_CHECK(bytes == 1 || bytes == -1);
314   return result;
315 }
316 
ClearFile(const std::string & path)317 bool FtraceProcfs::ClearFile(const std::string& path) {
318   base::ScopedFile fd = base::OpenFile(path, O_WRONLY | O_TRUNC);
319   return !!fd;
320 }
321 
ReadFileIntoString(const std::string & path) const322 std::string FtraceProcfs::ReadFileIntoString(const std::string& path) const {
323   // You can't seek or stat the procfs files on Android.
324   // The vast majority (884/886) of format files are under 4k.
325   std::string str;
326   str.reserve(4096);
327   if (!base::ReadFile(path, &str))
328     return "";
329   return str;
330 }
331 
GetEventNamesForGroup(const std::string & path) const332 const std::set<std::string> FtraceProcfs::GetEventNamesForGroup(
333     const std::string& path) const {
334   std::set<std::string> names;
335   std::string full_path = root_ + path;
336   base::ScopedDir dir(opendir(full_path.c_str()));
337   if (!dir) {
338     PERFETTO_DLOG("Unable to read events from %s", full_path.c_str());
339     return names;
340   }
341   struct dirent* ent;
342   while ((ent = readdir(*dir)) != nullptr) {
343     if (strncmp(ent->d_name, ".", 1) == 0 ||
344         strncmp(ent->d_name, "..", 2) == 0) {
345       continue;
346     }
347     // Check ent is a directory.
348     struct stat statbuf;
349     std::string dir_path = full_path + "/" + ent->d_name;
350     if (stat(dir_path.c_str(), &statbuf) == 0) {
351       if (S_ISDIR(statbuf.st_mode)) {
352         names.insert(ent->d_name);
353       }
354     }
355   }
356   return names;
357 }
358 
ReadEventId(const std::string & group,const std::string & name) const359 uint32_t FtraceProcfs::ReadEventId(const std::string& group,
360                                    const std::string& name) const {
361   std::string path = root_ + "events/" + group + "/" + name + "/id";
362 
363   std::string str;
364   if (!base::ReadFile(path, &str))
365     return 0;
366 
367   if (str.size() && str[str.size() - 1] == '\n')
368     str.resize(str.size() - 1);
369 
370   base::Optional<uint32_t> id = base::StringToUInt32(str);
371   if (!id)
372     return 0;
373   return *id;
374 }
375 
376 // static
CheckRootPath(const std::string & root)377 bool FtraceProcfs::CheckRootPath(const std::string& root) {
378   base::ScopedFile fd = base::OpenFile(root + "trace", O_RDONLY);
379   return static_cast<bool>(fd);
380 }
381 
382 }  // namespace perfetto
383