• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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