xref: /aosp_15_r20/external/perfetto/src/trace_processor/perfetto_sql/intrinsics/functions/utils.h (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
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