1 /*
2 * Copyright (C) 2022 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 #ifndef SRC_TRACE_PROCESSOR_PRELUDE_FUNCTIONS_UTILS_H_
18 #define SRC_TRACE_PROCESSOR_PRELUDE_FUNCTIONS_UTILS_H_
19
20 #include <sqlite3.h>
21 #include <unordered_map>
22
23 #include "perfetto/ext/base/base64.h"
24 #include "perfetto/ext/base/file_utils.h"
25 #include "perfetto/ext/trace_processor/demangle.h"
26 #include "protos/perfetto/common/builtin_clock.pbzero.h"
27 #include "src/trace_processor/export_json.h"
28 #include "src/trace_processor/importers/common/clock_tracker.h"
29 #include "src/trace_processor/prelude/functions/create_function_internal.h"
30 #include "src/trace_processor/prelude/functions/sql_function.h"
31 #include "src/trace_processor/sqlite/sqlite_utils.h"
32 #include "src/trace_processor/util/status_macros.h"
33
34 namespace perfetto {
35 namespace trace_processor {
36
37 struct ExportJson : public SqlFunction {
38 using Context = TraceStorage;
39 static base::Status Run(TraceStorage* storage,
40 size_t /*argc*/,
41 sqlite3_value** argv,
42 SqlValue& /*out*/,
43 Destructors&);
44 };
45
Run(TraceStorage * storage,size_t,sqlite3_value ** argv,SqlValue &,Destructors &)46 base::Status ExportJson::Run(TraceStorage* storage,
47 size_t /*argc*/,
48 sqlite3_value** argv,
49 SqlValue& /*out*/,
50 Destructors&) {
51 base::ScopedFstream output;
52 if (sqlite3_value_type(argv[0]) == SQLITE_INTEGER) {
53 // Assume input is an FD.
54 output.reset(fdopen(sqlite3_value_int(argv[0]), "w"));
55 if (!output) {
56 return base::ErrStatus(
57 "EXPORT_JSON: Couldn't open output file from given FD");
58 }
59 } else {
60 const char* filename =
61 reinterpret_cast<const char*>(sqlite3_value_text(argv[0]));
62 output = base::OpenFstream(filename, "w");
63 if (!output) {
64 return base::ErrStatus("EXPORT_JSON: Couldn't open output file");
65 }
66 }
67 return json::ExportJson(storage, output.get());
68 }
69
70 struct Hash : public SqlFunction {
71 static base::Status Run(void*,
72 size_t argc,
73 sqlite3_value** argv,
74 SqlValue& out,
75 Destructors&);
76 };
77
Run(void *,size_t argc,sqlite3_value ** argv,SqlValue & out,Destructors &)78 base::Status Hash::Run(void*,
79 size_t argc,
80 sqlite3_value** argv,
81 SqlValue& out,
82 Destructors&) {
83 base::Hasher hash;
84 for (size_t i = 0; i < argc; ++i) {
85 sqlite3_value* value = argv[i];
86 int type = sqlite3_value_type(value);
87 switch (type) {
88 case SQLITE_INTEGER:
89 hash.Update(sqlite3_value_int64(value));
90 break;
91 case SQLITE_TEXT: {
92 const char* ptr =
93 reinterpret_cast<const char*>(sqlite3_value_text(value));
94 hash.Update(ptr, strlen(ptr));
95 break;
96 }
97 default:
98 return base::ErrStatus("HASH: arg %zu has unknown type %d", i, type);
99 }
100 }
101 out = SqlValue::Long(static_cast<int64_t>(hash.digest()));
102 return base::OkStatus();
103 }
104
105 struct Base64Encode : public SqlFunction {
106 static base::Status Run(void*,
107 size_t argc,
108 sqlite3_value** argv,
109 SqlValue& out,
110 Destructors&);
111 };
112
Run(void *,size_t argc,sqlite3_value ** argv,SqlValue & out,Destructors & destructors)113 base::Status Base64Encode::Run(void*,
114 size_t argc,
115 sqlite3_value** argv,
116 SqlValue& out,
117 Destructors& destructors) {
118 if (argc != 1)
119 return base::ErrStatus("Unsupported number of arg passed to Base64Encode");
120
121 sqlite3_value* value = argv[0];
122 if (sqlite3_value_type(value) != SQLITE_BLOB)
123 return base::ErrStatus("Base64Encode only supports bytes argument");
124
125 size_t byte_count = static_cast<size_t>(sqlite3_value_bytes(value));
126 std::string res = base::Base64Encode(sqlite3_value_blob(value), byte_count);
127
128 std::unique_ptr<char, base::FreeDeleter> s(
129 static_cast<char*>(malloc(res.size() + 1)));
130 memcpy(s.get(), res.c_str(), res.size() + 1);
131
132 out = SqlValue::String(s.release());
133 destructors.string_destructor = free;
134
135 return base::OkStatus();
136 }
137
138 struct Demangle : public SqlFunction {
139 static base::Status Run(void*,
140 size_t argc,
141 sqlite3_value** argv,
142 SqlValue& out,
143 Destructors& destructors);
144 };
145
Run(void *,size_t argc,sqlite3_value ** argv,SqlValue & out,Destructors & destructors)146 base::Status Demangle::Run(void*,
147 size_t argc,
148 sqlite3_value** argv,
149 SqlValue& out,
150 Destructors& destructors) {
151 if (argc != 1)
152 return base::ErrStatus("Unsupported number of arg passed to DEMANGLE");
153 sqlite3_value* value = argv[0];
154 if (sqlite3_value_type(value) == SQLITE_NULL)
155 return base::OkStatus();
156
157 if (sqlite3_value_type(value) != SQLITE_TEXT)
158 return base::ErrStatus("Unsupported type of arg passed to DEMANGLE");
159
160 const char* mangled =
161 reinterpret_cast<const char*>(sqlite3_value_text(value));
162
163 std::unique_ptr<char, base::FreeDeleter> demangled =
164 demangle::Demangle(mangled);
165 if (!demangled)
166 return base::OkStatus();
167
168 destructors.string_destructor = free;
169 out = SqlValue::String(demangled.release());
170 return base::OkStatus();
171 }
172
173 struct WriteFile : public SqlFunction {
174 using Context = TraceStorage;
175 static base::Status Run(TraceStorage* storage,
176 size_t,
177 sqlite3_value** argv,
178 SqlValue&,
179 Destructors&);
180 };
181
Run(TraceStorage *,size_t argc,sqlite3_value ** argv,SqlValue & out,Destructors &)182 base::Status WriteFile::Run(TraceStorage*,
183 size_t argc,
184 sqlite3_value** argv,
185 SqlValue& out,
186 Destructors&) {
187 if (argc != 2) {
188 return base::ErrStatus("WRITE_FILE: expected %d args but got %zu", 2, argc);
189 }
190
191 base::Status status =
192 sqlite_utils::TypeCheckSqliteValue(argv[0], SqlValue::kString);
193 if (!status.ok()) {
194 return base::ErrStatus("WRITE_FILE: argument 1, filename; %s",
195 status.c_message());
196 }
197
198 status = sqlite_utils::TypeCheckSqliteValue(argv[1], SqlValue::kBytes);
199 if (!status.ok()) {
200 return base::ErrStatus("WRITE_FILE: argument 2, content; %s",
201 status.c_message());
202 }
203
204 const std::string filename =
205 reinterpret_cast<const char*>(sqlite3_value_text(argv[0]));
206
207 base::ScopedFstream file = base::OpenFstream(filename.c_str(), "wb");
208 if (!file) {
209 return base::ErrStatus("WRITE_FILE: Couldn't open output file %s (%s)",
210 filename.c_str(), strerror(errno));
211 }
212
213 int int_len = sqlite3_value_bytes(argv[1]);
214 PERFETTO_CHECK(int_len >= 0);
215 size_t len = (static_cast<size_t>(int_len));
216 // Make sure to call last as sqlite3_value_bytes can invalidate pointer
217 // returned.
218 const void* data = sqlite3_value_text(argv[1]);
219 if (fwrite(data, 1, len, file.get()) != len || fflush(file.get()) != 0) {
220 return base::ErrStatus("WRITE_FILE: Failed to write to file %s (%s)",
221 filename.c_str(), strerror(errno));
222 }
223
224 out = SqlValue::Long(int_len);
225
226 return util::OkStatus();
227 }
228
229 struct ExtractArg : public SqlFunction {
230 using Context = TraceStorage;
231 static base::Status Run(TraceStorage* storage,
232 size_t argc,
233 sqlite3_value** argv,
234 SqlValue& out,
235 Destructors& destructors);
236 };
237
Run(TraceStorage * storage,size_t argc,sqlite3_value ** argv,SqlValue & out,Destructors & destructors)238 base::Status ExtractArg::Run(TraceStorage* storage,
239 size_t argc,
240 sqlite3_value** argv,
241 SqlValue& out,
242 Destructors& destructors) {
243 if (argc != 2)
244 return base::ErrStatus("EXTRACT_ARG: 2 args required");
245
246 // If the arg set id is null, just return null as the result.
247 if (sqlite3_value_type(argv[0]) == SQLITE_NULL)
248 return base::OkStatus();
249
250 if (sqlite3_value_type(argv[0]) != SQLITE_INTEGER)
251 return base::ErrStatus("EXTRACT_ARG: 1st argument should be arg set id");
252
253 if (sqlite3_value_type(argv[1]) != SQLITE_TEXT)
254 return base::ErrStatus("EXTRACT_ARG: 2nd argument should be key");
255
256 uint32_t arg_set_id = static_cast<uint32_t>(sqlite3_value_int(argv[0]));
257 const char* key = reinterpret_cast<const char*>(sqlite3_value_text(argv[1]));
258
259 std::optional<Variadic> opt_value;
260 RETURN_IF_ERROR(storage->ExtractArg(arg_set_id, key, &opt_value));
261
262 if (!opt_value)
263 return base::OkStatus();
264
265 // This function always returns static strings (i.e. scoped to lifetime
266 // of the TraceStorage thread pool) so prevent SQLite from making copies.
267 destructors.string_destructor = sqlite_utils::kSqliteStatic;
268
269 switch (opt_value->type) {
270 case Variadic::kNull:
271 return base::OkStatus();
272 case Variadic::kInt:
273 out = SqlValue::Long(opt_value->int_value);
274 return base::OkStatus();
275 case Variadic::kUint:
276 out = SqlValue::Long(static_cast<int64_t>(opt_value->uint_value));
277 return base::OkStatus();
278 case Variadic::kString:
279 out =
280 SqlValue::String(storage->GetString(opt_value->string_value).data());
281 return base::OkStatus();
282 case Variadic::kReal:
283 out = SqlValue::Double(opt_value->real_value);
284 return base::OkStatus();
285 case Variadic::kBool:
286 out = SqlValue::Long(opt_value->bool_value);
287 return base::OkStatus();
288 case Variadic::kPointer:
289 out = SqlValue::Long(static_cast<int64_t>(opt_value->pointer_value));
290 return base::OkStatus();
291 case Variadic::kJson:
292 out = SqlValue::String(storage->GetString(opt_value->json_value).data());
293 return base::OkStatus();
294 }
295 PERFETTO_FATAL("For GCC");
296 }
297
298 struct SourceGeq : public SqlFunction {
RunSourceGeq299 static base::Status Run(void*,
300 size_t,
301 sqlite3_value**,
302 SqlValue&,
303 Destructors&) {
304 return base::ErrStatus(
305 "SOURCE_GEQ should not be called from the global scope");
306 }
307 };
308
309 struct Glob : public SqlFunction {
RunGlob310 static base::Status Run(void*,
311 size_t,
312 sqlite3_value** argv,
313 SqlValue& out,
314 Destructors&) {
315 const char* pattern =
316 reinterpret_cast<const char*>(sqlite3_value_text(argv[0]));
317 const char* text =
318 reinterpret_cast<const char*>(sqlite3_value_text(argv[1]));
319 if (pattern && text) {
320 out = SqlValue::Long(sqlite3_strglob(pattern, text) == 0);
321 }
322 return base::OkStatus();
323 }
324 };
325
326 } // namespace trace_processor
327 } // namespace perfetto
328
329 #endif // SRC_TRACE_PROCESSOR_PRELUDE_FUNCTIONS_UTILS_H_
330