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 <getopt.h> 18 #include <sys/stat.h> 19 #include <fstream> 20 #include <map> 21 #include <memory> 22 #include <regex> 23 #include <set> 24 #include <sstream> 25 #include <string> 26 27 #include <google/protobuf/descriptor.h> 28 #include <google/protobuf/descriptor.pb.h> 29 30 #include "perfetto/base/file_utils.h" 31 #include "perfetto/base/logging.h" 32 #include "src/traced/probes/ftrace/format_parser.h" 33 #include "tools/ftrace_proto_gen/ftrace_descriptor_gen.h" 34 #include "tools/ftrace_proto_gen/ftrace_proto_gen.h" 35 36 namespace { 37 inline std::unique_ptr<std::ostream> MakeOFStream(const std::string& filename) { 38 return std::unique_ptr<std::ostream>(new std::ofstream(filename)); 39 } 40 41 inline std::unique_ptr<std::ostream> MakeVerifyStream( 42 const std::string& filename) { 43 return std::unique_ptr<std::ostream>(new perfetto::VerifyStream(filename)); 44 } 45 } // namespace 46 47 int main(int argc, char** argv) { 48 static struct option long_options[] = { 49 {"whitelist_path", required_argument, nullptr, 'w'}, 50 {"output_dir", required_argument, nullptr, 'o'}, 51 {"proto_descriptor", required_argument, nullptr, 'd'}, 52 {"update_build_files", no_argument, nullptr, 'b'}, 53 {"check_only", no_argument, nullptr, 'c'}, 54 }; 55 56 int option_index; 57 int c; 58 59 std::string whitelist_path; 60 std::string output_dir; 61 std::string proto_descriptor; 62 bool update_build_files = false; 63 64 std::unique_ptr<std::ostream> (*ostream_factory)(const std::string&) = 65 &MakeOFStream; 66 67 while ((c = getopt_long(argc, argv, "", long_options, &option_index)) != -1) { 68 switch (c) { 69 case 'w': 70 whitelist_path = optarg; 71 break; 72 case 'o': 73 output_dir = optarg; 74 break; 75 case 'd': 76 proto_descriptor = optarg; 77 break; 78 case 'b': 79 update_build_files = true; 80 break; 81 case 'c': 82 ostream_factory = &MakeVerifyStream; 83 } 84 } 85 86 PERFETTO_CHECK(!whitelist_path.empty()); 87 PERFETTO_CHECK(!output_dir.empty()); 88 PERFETTO_CHECK(!proto_descriptor.empty()); 89 90 if (optind >= argc) { 91 fprintf(stderr, 92 "Usage: ./%s -w whitelist_dir -o output_dir -d proto_descriptor " 93 "[--check_only] input_dir...\n", 94 argv[0]); 95 return 1; 96 } 97 98 std::vector<perfetto::FtraceEventName> whitelist = 99 perfetto::ReadWhitelist(whitelist_path); 100 std::vector<std::string> events_info; 101 102 google::protobuf::DescriptorPool descriptor_pool; 103 descriptor_pool.AllowUnknownDependencies(); 104 { 105 google::protobuf::FileDescriptorSet file_descriptor_set; 106 std::string descriptor_bytes; 107 if (!perfetto::base::ReadFile(proto_descriptor, &descriptor_bytes)) { 108 fprintf(stderr, "Failed to open %s\n", proto_descriptor.c_str()); 109 return 1; 110 } 111 file_descriptor_set.ParseFromString(descriptor_bytes); 112 113 for (const auto& d : file_descriptor_set.file()) { 114 PERFETTO_CHECK(descriptor_pool.BuildFile(d)); 115 } 116 } 117 118 std::set<std::string> groups; 119 std::multimap<std::string, const perfetto::FtraceEventName*> group_to_event; 120 std::set<std::string> new_events; 121 for (const auto& event : whitelist) { 122 if (!event.valid()) 123 continue; 124 groups.emplace(event.group()); 125 group_to_event.emplace(event.group(), &event); 126 struct stat buf; 127 if (stat( 128 ("protos/perfetto/trace/ftrace/" + event.name() + ".proto").c_str(), 129 &buf) == -1) { 130 new_events.insert(event.name()); 131 } 132 } 133 134 { 135 std::unique_ptr<std::ostream> out = 136 ostream_factory(output_dir + "/ftrace_event.proto"); 137 perfetto::GenerateFtraceEventProto(whitelist, groups, out.get()); 138 } 139 140 if (!new_events.empty()) { 141 perfetto::PrintEventFormatterMain(new_events); 142 perfetto::PrintEventFormatterUsingStatements(new_events); 143 perfetto::PrintEventFormatterFunctions(new_events); 144 printf( 145 "\nAdd output to ParseInode in " 146 "tools/ftrace_proto_gen/ftrace_inode_handler.cc\n"); 147 } 148 149 for (const std::string& group : groups) { 150 std::string proto_file_name = group + ".proto"; 151 std::string output_path = output_dir + std::string("/") + proto_file_name; 152 std::unique_ptr<std::ostream> fout = ostream_factory(output_path); 153 if (!fout) { 154 fprintf(stderr, "Failed to open %s\n", output_path.c_str()); 155 return 1; 156 } 157 *fout << perfetto::ProtoHeader(); 158 159 auto range = group_to_event.equal_range(group); 160 for (auto it = range.first; it != range.second; ++it) { 161 const auto& event = *it->second; 162 if (!event.valid()) 163 continue; 164 165 std::string proto_name = perfetto::EventNameToProtoName(event.name()); 166 perfetto::Proto proto; 167 proto.name = proto_name; 168 proto.event_name = event.name(); 169 const google::protobuf::Descriptor* d = 170 descriptor_pool.FindMessageTypeByName("perfetto.protos." + 171 proto_name); 172 if (d) 173 proto = perfetto::Proto(event.name(), *d); 174 else 175 PERFETTO_LOG("Did not find %s", proto_name.c_str()); 176 for (int i = optind; i < argc; ++i) { 177 std::string input_dir = argv[i]; 178 std::string input_path = input_dir + event.group() + "/" + 179 event.name() + std::string("/format"); 180 181 std::string contents; 182 if (!perfetto::base::ReadFile(input_path, &contents)) { 183 continue; 184 } 185 186 perfetto::FtraceEvent format; 187 if (!perfetto::ParseFtraceEvent(contents, &format)) { 188 fprintf(stderr, "Could not parse file %s.\n", input_path.c_str()); 189 return 1; 190 } 191 192 perfetto::Proto event_proto; 193 if (!perfetto::GenerateProto(format, &event_proto)) { 194 fprintf(stderr, "Could not generate proto for file %s\n", 195 input_path.c_str()); 196 return 1; 197 } 198 proto.MergeFrom(event_proto); 199 } 200 201 if (!new_events.empty()) 202 PrintInodeHandlerMain(proto.name, proto); 203 204 uint32_t i = 0; 205 for (; it->second != &whitelist[i]; i++) 206 ; 207 208 // The first id used for events in FtraceEvent proto is 3. 209 uint32_t proto_field = i + 3; 210 211 // The generic event has field id 327 so any event with a id higher 212 // than that has to be incremented by 1. 213 if (proto_field >= 327) 214 proto_field++; 215 216 events_info.push_back( 217 perfetto::SingleEventInfo(proto, event.group(), proto_field)); 218 219 *fout << proto.ToString(); 220 PERFETTO_CHECK(!fout->fail()); 221 } 222 } 223 224 { 225 std::unique_ptr<std::ostream> out = 226 ostream_factory("src/trace_processor/ftrace_descriptors.cc"); 227 perfetto::GenerateFtraceDescriptors(descriptor_pool, out.get()); 228 PERFETTO_CHECK(!out->fail()); 229 } 230 231 { 232 std::unique_ptr<std::ostream> out = 233 ostream_factory("src/traced/probes/ftrace/event_info.cc"); 234 perfetto::GenerateEventInfo(events_info, out.get()); 235 PERFETTO_CHECK(!out->fail()); 236 } 237 238 if (update_build_files) { 239 std::unique_ptr<std::ostream> f = 240 ostream_factory(output_dir + "/all_protos.gni"); 241 242 *f << R"(# Copyright (C) 2018 The Android Open Source Project 243 # 244 # Licensed under the Apache License, Version 2.0 (the "License"); 245 # you may not use this file except in compliance with the License. 246 # You may obtain a copy of the License at 247 # 248 # http://www.apache.org/licenses/LICENSE-2.0 249 # 250 # Unless required by applicable law or agreed to in writing, software 251 # distributed under the License is distributed on an "AS IS" BASIS, 252 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 253 # See the License for the specific language governing permissions and 254 # limitations under the License. 255 256 # Autogenerated by ftrace_proto_gen. 257 258 ftrace_proto_names = [ 259 "ftrace_event.proto", 260 "ftrace_event_bundle.proto", 261 "ftrace_stats.proto", 262 "test_bundle_wrapper.proto", 263 "generic.proto", 264 )"; 265 for (const std::string& group : groups) { 266 *f << " \"" << group << ".proto\",\n"; 267 } 268 *f << "]\n"; 269 PERFETTO_CHECK(!f->fail()); 270 } 271 } 272