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