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