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 {
MakeOFStream(const std::string & filename)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
MakeVerifyStream(const std::string & filename)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
main(int argc,char ** argv)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