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