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