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 "perfetto/ftrace_reader/format_parser.h" 18 19 #include <string.h> 20 21 #include <iosfwd> 22 #include <iostream> 23 #include <memory> 24 #include <regex> 25 #include <string> 26 #include <vector> 27 28 #include "perfetto/base/string_splitter.h" 29 #include "perfetto/base/utils.h" 30 31 namespace perfetto { 32 namespace { 33 34 #define MAX_FIELD_LENGTH 127 35 #define STRINGIFY(x) STRINGIFY2(x) 36 #define STRINGIFY2(x) #x 37 38 const char* kCommonFieldPrefix = "common_"; 39 40 bool IsCommonFieldName(const std::string& name) { 41 return name.compare(0, strlen(kCommonFieldPrefix), kCommonFieldPrefix) == 0; 42 } 43 44 bool IsCIdentifier(const std::string& s) { 45 for (const char c : s) { 46 if (!(std::isalnum(c) || c == '_')) 47 return false; 48 } 49 return !s.empty() && !std::isdigit(s[0]); 50 } 51 52 } // namespace 53 54 // For example: 55 // "int foo" -> "foo" 56 // "u8 foo[(int)sizeof(struct blah)]" -> "foo" 57 // "char[] foo[16]" -> "foo" 58 // "something_went_wrong" -> "" 59 // "" -> "" 60 std::string GetNameFromTypeAndName(const std::string& type_and_name) { 61 size_t right = type_and_name.size(); 62 if (right == 0) 63 return ""; 64 65 if (type_and_name[type_and_name.size() - 1] == ']') { 66 right = type_and_name.rfind('['); 67 if (right == std::string::npos) 68 return ""; 69 } 70 71 size_t left = type_and_name.rfind(' ', right); 72 if (left == std::string::npos) 73 return ""; 74 left++; 75 76 std::string result = type_and_name.substr(left, right - left); 77 if (!IsCIdentifier(result)) 78 return ""; 79 80 return result; 81 } 82 83 bool ParseFtraceEvent(const std::string& input, FtraceEvent* output) { 84 char buffer[MAX_FIELD_LENGTH + 1]; 85 86 bool has_id = false; 87 bool has_name = false; 88 89 uint32_t id = 0; 90 std::string name; 91 std::vector<FtraceEvent::Field> common_fields; 92 std::vector<FtraceEvent::Field> fields; 93 94 for (base::StringSplitter ss(input, '\n'); ss.Next();) { 95 const char* line = ss.cur_token(); 96 if (!has_id && sscanf(line, "ID: %d", &id) == 1) { 97 has_id = true; 98 continue; 99 } 100 101 if (!has_name && 102 sscanf(line, "name: %" STRINGIFY(MAX_FIELD_LENGTH) "s", buffer) == 1) { 103 name = std::string(buffer); 104 has_name = true; 105 continue; 106 } 107 108 if (strcmp("format:", line) == 0) { 109 continue; 110 } 111 112 uint16_t offset = 0; 113 uint16_t size = 0; 114 int is_signed = 0; 115 if (sscanf(line, 116 "\tfield:%" STRINGIFY(MAX_FIELD_LENGTH) "[^;];\toffset: " 117 "%hu;\tsize: " 118 "%hu;\tsigned: %d;", 119 buffer, &offset, &size, &is_signed) == 4) { 120 std::string type_and_name(buffer); 121 122 FtraceEvent::Field field{type_and_name, offset, size, is_signed == 1}; 123 124 if (IsCommonFieldName(GetNameFromTypeAndName(type_and_name))) { 125 common_fields.push_back(field); 126 } else { 127 fields.push_back(field); 128 } 129 130 continue; 131 } 132 133 if (strncmp(line, "print fmt:", 10) == 0) { 134 break; 135 } 136 137 if (output) 138 fprintf(stderr, "Cannot parse line: \"%s\"\n", line); 139 return false; 140 } 141 142 if (!has_id || !has_name || fields.empty()) { 143 if (output) 144 fprintf(stderr, "Could not parse format file: %s.\n", 145 !has_id ? "no ID found" 146 : !has_name ? "no name found" : "no fields found"); 147 return false; 148 } 149 150 if (!output) 151 return true; 152 153 output->id = id; 154 output->name = name; 155 output->fields = std::move(fields); 156 output->common_fields = std::move(common_fields); 157 158 return true; 159 } 160 161 ::std::ostream& operator<<(::std::ostream& os, 162 const FtraceEvent::Field& field) { 163 PrintTo(field, &os); 164 return os; 165 } 166 167 // Allow gtest to pretty print FtraceEvent::Field. 168 void PrintTo(const FtraceEvent::Field& field, ::std::ostream* os) { 169 *os << "FtraceEvent::Field(" << field.type_and_name << ", " << field.offset 170 << ", " << field.size << ", " << field.is_signed << ")"; 171 } 172 173 } // namespace perfetto 174