2 * Copyright (C) 2016 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
25 #include <android-base/file.h>
26 #include <android-base/logging.h>
27 #include <android-base/stringprintf.h>
28 #include <android-base/strings.h>
30 #include "perf_event.h"
33 const char TRACING_INFO_MAGIC[10] = {23, 8, 68, 't', 'r',
34 'a', 'c', 'i', 'n', 'g'};
37 void AppendData(std::vector<char>& data, const T& s) {
38 const char* p = reinterpret_cast<const char*>(&s);
39 data.insert(data.end(), p, p + sizeof(T));
42 static void AppendData(std::vector<char>& data, const char* s) {
43 data.insert(data.end(), s, s + strlen(s) + 1);
47 void AppendData(std::vector<char>& data, const std::string& s) {
48 data.insert(data.end(), s.c_str(), s.c_str() + s.size() + 1);
52 void MoveFromBinaryFormat(std::string& data, const char*& p) {
60 static void AppendFile(std::vector<char>& data, const std::string& file,
61 uint32_t file_size_bytes = 8) {
62 if (file_size_bytes == 8) {
63 uint64_t file_size = file.size();
64 AppendData(data, file_size);
65 } else if (file_size_bytes == 4) {
66 uint32_t file_size = file.size();
67 AppendData(data, file_size);
69 data.insert(data.end(), file.begin(), file.end());
72 static void DetachFile(const char*& p, std::string& file,
73 uint32_t file_size_bytes = 8) {
74 uint64_t file_size = ConvertBytesToValue(p, file_size_bytes);
77 file.insert(file.end(), p, p + file_size);
89 bool RecordHeaderFiles();
90 void RecordFtraceFiles(const std::vector<TraceType>& trace_types);
91 bool RecordEventFiles(const std::vector<TraceType>& trace_types);
92 bool RecordKallsymsFile();
93 bool RecordPrintkFormatsFile();
94 std::vector<char> BinaryFormat() const;
95 void LoadFromBinary(const std::vector<char>& data);
96 void Dump(size_t indent) const;
97 std::vector<TracingFormat> LoadTracingFormatsFromEventFiles() const;
98 const std::string& GetKallsymsFile() const { return kallsyms_file; }
99 uint32_t GetPageSize() const { return page_size; }
105 uint8_t size_of_long;
107 std::string header_page_file;
108 std::string header_event_file;
110 std::vector<std::string> ftrace_format_files;
111 // pair of system, format_file_data.
112 std::vector<std::pair<std::string, std::string>> event_format_files;
114 std::string kallsyms_file;
115 std::string printk_formats_file;
118 TracingFile::TracingFile() {
119 memcpy(magic, TRACING_INFO_MAGIC, sizeof(TRACING_INFO_MAGIC));
122 size_of_long = static_cast<int>(sizeof(long));
123 page_size = static_cast<uint32_t>(::GetPageSize());
126 bool TracingFile::RecordHeaderFiles() {
127 if (!android::base::ReadFileToString(
128 "/sys/kernel/debug/tracing/events/header_page", &header_page_file)) {
130 << "failed to read /sys/kernel/debug/tracing/events/header_page";
133 if (!android::base::ReadFileToString(
134 "/sys/kernel/debug/tracing/events/header_event",
135 &header_event_file)) {
137 << "failed to read /sys/kernel/debug/tracing/events/header_event";
143 void TracingFile::RecordFtraceFiles(const std::vector<TraceType>& trace_types) {
144 for (const auto& type : trace_types) {
145 std::string format_path = android::base::StringPrintf(
146 "/sys/kernel/debug/tracing/events/ftrace/%s/format", type.name.c_str());
147 std::string format_data;
148 if (android::base::ReadFileToString(format_path, &format_data)) {
149 ftrace_format_files.push_back(std::move(format_data));
154 bool TracingFile::RecordEventFiles(const std::vector<TraceType>& trace_types) {
155 for (const auto& type : trace_types) {
156 std::string format_path = android::base::StringPrintf(
157 "/sys/kernel/debug/tracing/events/%s/%s/format", type.system.c_str(),
159 std::string format_data;
160 if (!android::base::ReadFileToString(format_path, &format_data)) {
161 PLOG(ERROR) << "failed to read " << format_path;
164 event_format_files.push_back(
165 std::make_pair(type.system, std::move(format_data)));
170 bool TracingFile::RecordPrintkFormatsFile() {
171 if (!android::base::ReadFileToString(
172 "/sys/kernel/debug/tracing/printk_formats", &printk_formats_file)) {
173 PLOG(ERROR) << "failed to read /sys/kernel/debug/tracing/printk_formats";
179 std::vector<char> TracingFile::BinaryFormat() const {
180 std::vector<char> ret;
181 ret.insert(ret.end(), magic, magic + sizeof(magic));
182 AppendData(ret, version);
183 ret.push_back(endian);
184 AppendData(ret, size_of_long);
185 AppendData(ret, page_size);
186 AppendData(ret, "header_page");
187 AppendFile(ret, header_page_file);
188 AppendData(ret, "header_event");
189 AppendFile(ret, header_event_file);
190 int count = static_cast<int>(ftrace_format_files.size());
191 AppendData(ret, count);
192 for (const auto& format : ftrace_format_files) {
193 AppendFile(ret, format);
195 count = static_cast<int>(event_format_files.size());
196 AppendData(ret, count);
197 for (const auto& pair : event_format_files) {
198 AppendData(ret, pair.first);
200 AppendFile(ret, pair.second);
202 AppendFile(ret, kallsyms_file, 4);
203 AppendFile(ret, printk_formats_file, 4);
207 void TracingFile::LoadFromBinary(const std::vector<char>& data) {
208 const char* p = data.data();
209 const char* end = data.data() + data.size();
210 CHECK(memcmp(p, magic, sizeof(magic)) == 0);
212 MoveFromBinaryFormat(version, p);
213 MoveFromBinaryFormat(endian, p);
214 MoveFromBinaryFormat(size_of_long, p);
215 MoveFromBinaryFormat(page_size, p);
216 std::string filename;
217 MoveFromBinaryFormat(filename, p);
218 CHECK_EQ(filename, "header_page");
219 DetachFile(p, header_page_file);
220 MoveFromBinaryFormat(filename, p);
221 CHECK_EQ(filename, "header_event");
222 DetachFile(p, header_event_file);
224 MoveFromBinaryFormat(count, p);
225 ftrace_format_files.resize(count);
226 for (uint32_t i = 0; i < count; ++i) {
227 DetachFile(p, ftrace_format_files[i]);
229 MoveFromBinaryFormat(count, p);
230 event_format_files.clear();
231 for (uint32_t i = 0; i < count; ++i) {
233 MoveFromBinaryFormat(system, p);
234 uint32_t count_in_system;
235 MoveFromBinaryFormat(count_in_system, p);
236 for (uint32_t i = 0; i < count_in_system; ++i) {
238 DetachFile(p, format);
239 event_format_files.push_back(std::make_pair(system, std::move(format)));
242 DetachFile(p, kallsyms_file, 4);
243 DetachFile(p, printk_formats_file, 4);
247 void TracingFile::Dump(size_t indent) const {
248 PrintIndented(indent, "tracing data:\n");
249 PrintIndented(indent + 1, "magic: ");
250 for (size_t i = 0; i < 3u; ++i) {
251 printf("0x%x ", magic[i]);
253 for (size_t i = 3; i < sizeof(magic); ++i) {
254 printf("%c", magic[i]);
257 PrintIndented(indent + 1, "version: %s\n", version.c_str());
258 PrintIndented(indent + 1, "endian: %d\n", endian);
259 PrintIndented(indent + 1, "header_page:\n%s\n\n", header_page_file.c_str());
260 PrintIndented(indent + 1, "header_event:\n%s\n\n", header_event_file.c_str());
261 for (size_t i = 0; i < ftrace_format_files.size(); ++i) {
262 PrintIndented(indent + 1, "ftrace format file %zu/%zu:\n%s\n\n", i + 1,
263 ftrace_format_files.size(), ftrace_format_files[i].c_str());
265 for (size_t i = 0; i < event_format_files.size(); ++i) {
266 PrintIndented(indent + 1, "event format file %zu/%zu %s:\n%s\n\n", i + 1,
267 event_format_files.size(),
268 event_format_files[i].first.c_str(),
269 event_format_files[i].second.c_str());
271 PrintIndented(indent + 1, "kallsyms:\n%s\n\n", kallsyms_file.c_str());
272 PrintIndented(indent + 1, "printk_formats:\n%s\n\n",
273 printk_formats_file.c_str());
276 enum class FormatParsingState {
283 // Parse lines like: field:char comm[16]; offset:8; size:16; signed:1;
284 static TracingField ParseTracingField(const std::string& s) {
289 for (size_t i = 0; i < s.size(); ++i) {
290 if (!isspace(s[i]) && (i == 0 || isspace(s[i - 1]))) {
292 } else if (s[i] == ':') {
293 name = s.substr(start, i - start);
295 } else if (s[i] == ';') {
296 value = s.substr(start, i - start);
297 if (name == "field") {
298 size_t pos = value.find_first_of('[');
299 if (pos == std::string::npos) {
301 field.elem_count = 1;
303 field.name = value.substr(0, pos);
305 static_cast<size_t>(strtoull(&value[pos + 1], nullptr, 10));
307 } else if (name == "offset") {
309 static_cast<size_t>(strtoull(value.c_str(), nullptr, 10));
310 } else if (name == "size") {
311 size_t size = static_cast<size_t>(strtoull(value.c_str(), nullptr, 10));
312 CHECK_EQ(size % field.elem_count, 0u);
313 field.elem_size = size / field.elem_count;
314 } else if (name == "signed") {
315 int is_signed = static_cast<int>(strtoull(value.c_str(), nullptr, 10));
316 field.is_signed = (is_signed == 1);
323 std::vector<TracingFormat> TracingFile::LoadTracingFormatsFromEventFiles()
325 std::vector<TracingFormat> formats;
326 for (const auto& pair : event_format_files) {
327 TracingFormat format;
328 format.system_name = pair.first;
329 std::vector<std::string> strs = android::base::Split(pair.second, "\n");
330 FormatParsingState state = FormatParsingState::READ_NAME;
331 for (const auto& s : strs) {
332 if (state == FormatParsingState::READ_NAME) {
333 size_t pos = s.find_first_of("name:");
334 if (pos != std::string::npos) {
335 format.name = android::base::Trim(s.substr(pos + strlen("name:")));
336 state = FormatParsingState::READ_ID;
338 } else if (state == FormatParsingState::READ_ID) {
339 size_t pos = s.find_first_of("ID:");
340 if (pos != std::string::npos) {
342 strtoull(s.substr(pos + strlen("ID:")).c_str(), nullptr, 10);
343 state = FormatParsingState::READ_FIELDS;
345 } else if (state == FormatParsingState::READ_FIELDS) {
346 size_t pos = s.find_first_of("field:");
347 if (pos != std::string::npos) {
348 TracingField field = ParseTracingField(s);
349 format.fields.push_back(field);
353 formats.push_back(format);
358 Tracing::Tracing(const std::vector<char>& data) {
359 tracing_file_ = new TracingFile;
360 tracing_file_->LoadFromBinary(data);
363 Tracing::~Tracing() { delete tracing_file_; }
365 void Tracing::Dump(size_t indent) { tracing_file_->Dump(indent); }
367 TracingFormat Tracing::GetTracingFormatHavingId(uint64_t trace_event_id) {
368 if (tracing_formats_.empty()) {
369 tracing_formats_ = tracing_file_->LoadTracingFormatsFromEventFiles();
371 for (const auto& format : tracing_formats_) {
372 if (format.id == trace_event_id) {
376 LOG(FATAL) << "no tracing format for id " << trace_event_id;
377 return TracingFormat();
380 std::string Tracing::GetTracingEventNameHavingId(uint64_t trace_event_id) {
381 if (tracing_formats_.empty()) {
382 tracing_formats_ = tracing_file_->LoadTracingFormatsFromEventFiles();
384 for (const auto& format : tracing_formats_) {
385 if (format.id == trace_event_id) {
386 return android::base::StringPrintf("%s:%s", format.system_name.c_str(),
387 format.name.c_str());
393 const std::string& Tracing::GetKallsyms() const {
394 return tracing_file_->GetKallsymsFile();
397 uint32_t Tracing::GetPageSize() const { return tracing_file_->GetPageSize(); }
399 bool GetTracingData(const std::vector<const EventType*>& event_types,
400 std::vector<char>* data) {
402 std::vector<TraceType> trace_types;
403 for (const auto& type : event_types) {
404 CHECK_EQ(PERF_TYPE_TRACEPOINT, type->type);
405 size_t pos = type->name.find(':');
406 TraceType trace_type;
407 trace_type.system = type->name.substr(0, pos);
408 trace_type.name = type->name.substr(pos + 1);
409 trace_types.push_back(trace_type);
411 TracingFile tracing_file;
412 if (!tracing_file.RecordHeaderFiles()) {
415 tracing_file.RecordFtraceFiles(trace_types);
416 if (!tracing_file.RecordEventFiles(trace_types)) {
419 // Don't record /proc/kallsyms here, as it will be contained in
420 // KernelSymbolRecord.
421 if (!tracing_file.RecordPrintkFormatsFile()) {
424 *data = tracing_file.BinaryFormat();