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