• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 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 "src/trace_processor/perfetto_sql/intrinsics/operators/etm_decode_trace_vtable.h"
18 
19 #include <sqlite3.h>
20 #include <cstdint>
21 #include <cstring>
22 #include <memory>
23 #include <optional>
24 #include <string>
25 
26 #include "perfetto/base/logging.h"
27 #include "perfetto/base/status.h"
28 #include "perfetto/ext/base/status_or.h"
29 #include "src/trace_processor/importers/etm/element_cursor.h"
30 #include "src/trace_processor/importers/etm/mapping_version.h"
31 #include "src/trace_processor/importers/etm/opencsd.h"
32 #include "src/trace_processor/importers/etm/sql_values.h"
33 #include "src/trace_processor/importers/etm/util.h"
34 #include "src/trace_processor/sqlite/bindings/sqlite_result.h"
35 #include "src/trace_processor/sqlite/sqlite_utils.h"
36 #include "src/trace_processor/storage/trace_storage.h"
37 #include "src/trace_processor/util/status_macros.h"
38 
39 namespace perfetto::trace_processor::etm {
40 namespace {
41 
ToElementType(sqlite3_value * value)42 base::StatusOr<ocsd_gen_trc_elem_t> ToElementType(sqlite3_value* value) {
43   SqlValue element_type = sqlite::utils::SqliteValueToSqlValue(value);
44   if (element_type.type != SqlValue::kString) {
45     return base::ErrStatus(
46         "Invalid data type for element_type. Expected STRING");
47   }
48   std::optional<ocsd_gen_trc_elem_t> type = FromString(element_type.AsString());
49   if (!type) {
50     return base::ErrStatus("Invalid element_type value: %s",
51                            element_type.AsString());
52   }
53   return *type;
54 }
55 
GetEtmV4TraceId(const TraceStorage * storage,sqlite3_value * argv)56 base::StatusOr<tables::EtmV4TraceTable::Id> GetEtmV4TraceId(
57     const TraceStorage* storage,
58     sqlite3_value* argv) {
59   SqlValue in_id = sqlite::utils::SqliteValueToSqlValue(argv);
60   if (in_id.type != SqlValue::kLong) {
61     return base::ErrStatus("trace_id must be LONG");
62   }
63 
64   if (in_id.AsLong() < 0 ||
65       in_id.AsLong() >= storage->etm_v4_trace_table().row_count()) {
66     return base::ErrStatus("Invalid trace_id value: %" PRIu32,
67                            storage->etm_v4_trace_table().row_count());
68   }
69 
70   return tables::EtmV4TraceTable::Id(static_cast<uint32_t>(in_id.AsLong()));
71 }
72 
73 static constexpr char kSchema[] = R"(
74     CREATE TABLE x(
75       trace_id INTEGER HIDDEN,
76       trace_index INTEGER,
77       element_index INTEGER,
78       element_type TEXT,
79       timestamp INTEGER,
80       cycle_count INTEGER,
81       exception_level INTEGER,
82       context_id INTEGER,
83       isa TEXT,
84       start_address INTEGER,
85       end_address INTEGER,
86       mapping_id INTEGER,
87       instruction_range BLOB HIDDEN
88     )
89   )";
90 
91 enum class ColumnIndex {
92   kTraceId,
93   kTraceIndex,
94   kElementIndex,
95   kElementType,
96   kTimestamp,
97   kCycleCount,
98   kExceptionLevel,
99   kContextId,
100   kIsa,
101   kStartAddress,
102   kEndAddress,
103   kMappingId,
104   kInstructionRange
105 };
106 
107 constexpr char kTraceIdEqArg = 't';
108 constexpr char kElementTypeEqArg = 'e';
109 constexpr char kElementTypeInArg = 'E';
110 
111 }  // namespace
112 
113 class EtmDecodeTraceVtable::Cursor
114     : public sqlite::Module<EtmDecodeTraceVtable>::Cursor {
115  public:
Cursor(Vtab * vtab)116   explicit Cursor(Vtab* vtab) : cursor_(vtab->storage) {}
117 
118   base::Status Filter(int idxNum,
119                       const char* idxStr,
120                       int argc,
121                       sqlite3_value** argv);
Next()122   base::Status Next() { return cursor_.Next(); }
Eof()123   bool Eof() { return cursor_.Eof(); }
124   int Column(sqlite3_context* ctx, int raw_n);
125 
126  private:
127   base::StatusOr<ElementTypeMask> GetTypeMask(sqlite3_value* argv,
128                                               bool is_inlist);
129   ElementCursor cursor_;
130 };
131 
GetTypeMask(sqlite3_value * argv,bool is_inlist)132 base::StatusOr<ElementTypeMask> EtmDecodeTraceVtable::Cursor::GetTypeMask(
133     sqlite3_value* argv,
134     bool is_inlist) {
135   ElementTypeMask mask;
136   if (!is_inlist) {
137     ASSIGN_OR_RETURN(ocsd_gen_trc_elem_t type, ToElementType(argv));
138     mask.set_bit(type);
139     return mask;
140   }
141   int rc;
142   sqlite3_value* type_value;
143   for (rc = sqlite3_vtab_in_first(argv, &type_value); rc == SQLITE_OK;
144        rc = sqlite3_vtab_in_next(argv, &type_value)) {
145     ASSIGN_OR_RETURN(ocsd_gen_trc_elem_t type, ToElementType(argv));
146     mask.set_bit(type);
147   }
148   if (rc != SQLITE_OK || rc != SQLITE_DONE) {
149     return base::ErrStatus("Error");
150   }
151   return mask;
152 }
153 
Filter(int,const char * idxStr,int argc,sqlite3_value ** argv)154 base::Status EtmDecodeTraceVtable::Cursor::Filter(int,
155                                                   const char* idxStr,
156                                                   int argc,
157                                                   sqlite3_value** argv) {
158   std::optional<tables::EtmV4TraceTable::Id> id;
159   ElementTypeMask type_mask;
160   type_mask.set_all();
161   if (argc != static_cast<int>(strlen(idxStr))) {
162     return base::ErrStatus("Invalid idxStr");
163   }
164   for (; *idxStr != 0; ++idxStr, ++argv) {
165     switch (*idxStr) {
166       case kTraceIdEqArg: {
167         ASSIGN_OR_RETURN(id, GetEtmV4TraceId(cursor_.storage(), *argv));
168         break;
169       }
170       case kElementTypeEqArg: {
171         ASSIGN_OR_RETURN(ElementTypeMask tmp, GetTypeMask(*argv, false));
172         type_mask &= tmp;
173         break;
174       }
175       case kElementTypeInArg: {
176         ASSIGN_OR_RETURN(ElementTypeMask tmp, GetTypeMask(*argv, true));
177         type_mask &= tmp;
178         break;
179       }
180       default:
181         return base::ErrStatus("Invalid idxStr");
182     }
183   }
184 
185   // Given the BestIndex impl this should not happen!
186   PERFETTO_CHECK(id);
187 
188   return cursor_.Filter(id, type_mask);
189 }
190 
Column(sqlite3_context * ctx,int raw_n)191 int EtmDecodeTraceVtable::Cursor::Column(sqlite3_context* ctx, int raw_n) {
192   switch (static_cast<ColumnIndex>(raw_n)) {
193     case ColumnIndex::kTraceId:
194       sqlite::result::Long(ctx, cursor_.trace_id().value);
195       break;
196     case ColumnIndex::kTraceIndex:
197       sqlite::result::Long(ctx, static_cast<int64_t>(cursor_.index()));
198       break;
199     case ColumnIndex::kElementIndex:
200       sqlite::result::Long(ctx, cursor_.element_index());
201       break;
202     case ColumnIndex::kElementType:
203       sqlite::result::StaticString(ctx, ToString(cursor_.element().getType()));
204       break;
205     case ColumnIndex::kTimestamp:
206       if (cursor_.element().getType() == OCSD_GEN_TRC_ELEM_TIMESTAMP ||
207           cursor_.element().has_ts) {
208         sqlite::result::Long(ctx,
209                              static_cast<int64_t>(cursor_.element().timestamp));
210       }
211       break;
212     case ColumnIndex::kCycleCount:
213       if (cursor_.element().has_cc) {
214         sqlite::result::Long(ctx, cursor_.element().cycle_count);
215       }
216       break;
217     case ColumnIndex::kExceptionLevel:
218       if (cursor_.element().context.el_valid) {
219         sqlite::result::Long(ctx, cursor_.element().context.exception_level);
220       }
221       break;
222     case ColumnIndex::kContextId:
223       if (cursor_.element().context.ctxt_id_valid) {
224         sqlite::result::Long(ctx, cursor_.element().context.context_id);
225       }
226       break;
227     case ColumnIndex::kIsa:
228       sqlite::result::StaticString(ctx, ToString(cursor_.element().isa));
229       break;
230     case ColumnIndex::kStartAddress:
231       sqlite::result::Long(ctx,
232                            static_cast<int64_t>(cursor_.element().st_addr));
233       break;
234     case ColumnIndex::kEndAddress:
235       sqlite::result::Long(ctx,
236                            static_cast<int64_t>(cursor_.element().en_addr));
237       break;
238     case ColumnIndex::kMappingId:
239       if (cursor_.mapping()) {
240         sqlite::result::Long(ctx, cursor_.mapping()->id().value);
241       }
242       break;
243     case ColumnIndex::kInstructionRange:
244       if (cursor_.has_instruction_range()) {
245         sqlite::result::UniquePointer(ctx, cursor_.GetInstructionRange(),
246                                       InstructionRangeSqlValue::kPtrType);
247       }
248       break;
249   }
250 
251   return SQLITE_OK;
252 }
253 
Connect(sqlite3 * db,void * ctx,int,const char * const *,sqlite3_vtab ** vtab,char **)254 int EtmDecodeTraceVtable::Connect(sqlite3* db,
255                                   void* ctx,
256                                   int,
257                                   const char* const*,
258                                   sqlite3_vtab** vtab,
259                                   char**) {
260   if (int ret = sqlite3_declare_vtab(db, kSchema); ret != SQLITE_OK) {
261     return ret;
262   }
263   std::unique_ptr<Vtab> res = std::make_unique<Vtab>(GetContext(ctx));
264   *vtab = res.release();
265   return SQLITE_OK;
266 }
267 
Disconnect(sqlite3_vtab * vtab)268 int EtmDecodeTraceVtable::Disconnect(sqlite3_vtab* vtab) {
269   delete GetVtab(vtab);
270   return SQLITE_OK;
271 }
272 
BestIndex(sqlite3_vtab * tab,sqlite3_index_info * info)273 int EtmDecodeTraceVtable::BestIndex(sqlite3_vtab* tab,
274                                     sqlite3_index_info* info) {
275   bool seen_id_eq = false;
276   int argv_index = 1;
277   std::string idx_str;
278   for (int i = 0; i < info->nConstraint; ++i) {
279     auto& in = info->aConstraint[i];
280     auto& out = info->aConstraintUsage[i];
281 
282     if (in.iColumn == static_cast<int>(ColumnIndex::kTraceId)) {
283       if (!in.usable) {
284         return SQLITE_CONSTRAINT;
285       }
286       if (in.op != SQLITE_INDEX_CONSTRAINT_EQ) {
287         return sqlite::utils::SetError(
288             tab, "trace_id only supports equality constraints");
289       }
290       seen_id_eq = true;
291 
292       idx_str += kTraceIdEqArg;
293       out.argvIndex = argv_index++;
294       out.omit = true;
295       continue;
296     }
297     if (in.usable &&
298         in.iColumn == static_cast<int>(ColumnIndex::kElementType)) {
299       if (in.op != SQLITE_INDEX_CONSTRAINT_EQ) {
300         continue;
301       }
302 
303       if (sqlite3_vtab_in(info, i, 1)) {
304         idx_str += kElementTypeInArg;
305       } else {
306         idx_str += kElementTypeEqArg;
307       }
308 
309       out.argvIndex = argv_index++;
310       out.omit = true;
311       continue;
312     }
313   }
314   if (!seen_id_eq) {
315     return sqlite::utils::SetError(tab, "Constraint required on trace_id");
316   }
317 
318   info->idxStr = sqlite3_mprintf("%s", idx_str.c_str());
319   info->needToFreeIdxStr = true;
320 
321   return SQLITE_OK;
322 }
323 
Open(sqlite3_vtab * sql_vtab,sqlite3_vtab_cursor ** cursor)324 int EtmDecodeTraceVtable::Open(sqlite3_vtab* sql_vtab,
325                                sqlite3_vtab_cursor** cursor) {
326   *cursor = new Cursor(GetVtab(sql_vtab));
327   return SQLITE_OK;
328 }
329 
Close(sqlite3_vtab_cursor * cursor)330 int EtmDecodeTraceVtable::Close(sqlite3_vtab_cursor* cursor) {
331   delete GetCursor(cursor);
332   return SQLITE_OK;
333 }
334 
Filter(sqlite3_vtab_cursor * cur,int idxNum,const char * idxStr,int argc,sqlite3_value ** argv)335 int EtmDecodeTraceVtable::Filter(sqlite3_vtab_cursor* cur,
336                                  int idxNum,
337                                  const char* idxStr,
338                                  int argc,
339                                  sqlite3_value** argv) {
340   auto status = GetCursor(cur)->Filter(idxNum, idxStr, argc, argv);
341   if (!status.ok()) {
342     return sqlite::utils::SetError(cur->pVtab, status);
343   }
344   return SQLITE_OK;
345 }
346 
Next(sqlite3_vtab_cursor * cur)347 int EtmDecodeTraceVtable::Next(sqlite3_vtab_cursor* cur) {
348   auto status = GetCursor(cur)->Next();
349   if (!status.ok()) {
350     return sqlite::utils::SetError(cur->pVtab, status);
351   }
352   return SQLITE_OK;
353 }
354 
Eof(sqlite3_vtab_cursor * cur)355 int EtmDecodeTraceVtable::Eof(sqlite3_vtab_cursor* cur) {
356   return GetCursor(cur)->Eof();
357 }
358 
Column(sqlite3_vtab_cursor * cur,sqlite3_context * ctx,int raw_n)359 int EtmDecodeTraceVtable::Column(sqlite3_vtab_cursor* cur,
360                                  sqlite3_context* ctx,
361                                  int raw_n) {
362   return GetCursor(cur)->Column(ctx, raw_n);
363 }
364 
Rowid(sqlite3_vtab_cursor *,sqlite_int64 *)365 int EtmDecodeTraceVtable::Rowid(sqlite3_vtab_cursor*, sqlite_int64*) {
366   return SQLITE_ERROR;
367 }
368 
369 }  // namespace perfetto::trace_processor::etm
370