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_iterate_range_vtable.h"
18 #include <opencsd/ocsd_if_types.h>
19
20 #include <cstring>
21 #include <memory>
22
23 #include "perfetto/base/logging.h"
24 #include "src/trace_processor/importers/etm/opencsd.h"
25 #include "src/trace_processor/importers/etm/sql_values.h"
26 #include "src/trace_processor/importers/etm/storage_handle.h"
27 #include "src/trace_processor/importers/etm/types.h"
28 #include "src/trace_processor/importers/etm/util.h"
29 #include "src/trace_processor/sqlite/bindings/sqlite_module.h"
30 #include "src/trace_processor/sqlite/bindings/sqlite_result.h"
31 #include "src/trace_processor/sqlite/bindings/sqlite_value.h"
32 #include "src/trace_processor/sqlite/sqlite_utils.h"
33 #include "src/trace_processor/storage/trace_storage.h"
34
35 namespace perfetto::trace_processor::etm {
36 namespace {
37
38 static constexpr char kSchema[] = R"(
39 CREATE TABLE x(
40 instruction_index INTEGER,
41 address INTEGER,
42 opcode INTEGER,
43 type TEXT,
44 branch_address INTEGER,
45 is_conditional INTEGER,
46 is_link INTEGER,
47 sub_type TEXT,
48 instruction_range BLOB HIDDEN
49 )
50 )";
51
52 enum class ColumnIndex {
53 kInstructionIndex,
54 kAddress,
55 kOpcode,
56 kType,
57 kBranchAddress,
58 kIsConditional,
59 kIsLink,
60 kSubType,
61 kInstructionRange
62 };
63
64 constexpr char kInstructionRangeEqArg = 'r';
65
66 class IntructionCursor : public sqlite::Module<EtmIterateRangeVtable>::Cursor {
67 public:
IntructionCursor(TraceStorage * storage)68 explicit IntructionCursor(TraceStorage* storage) : storage_(storage) {}
Filter(int,const char * idxStr,int argc,sqlite3_value ** argv)69 int Filter(int, const char* idxStr, int argc, sqlite3_value** argv) {
70 std::optional<const InstructionRangeSqlValue*> range;
71 if (argc != static_cast<int>(strlen(idxStr))) {
72 return sqlite::utils::SetError(pVtab, "Invalid idxStr");
73 }
74 for (; *idxStr != 0; ++idxStr, ++argv) {
75 switch (*idxStr) {
76 case kInstructionRangeEqArg: {
77 range = sqlite::value::Pointer<InstructionRangeSqlValue>(
78 *argv, InstructionRangeSqlValue::kPtrType);
79 break;
80 }
81 default:
82 return sqlite::utils::SetError(pVtab, "Invalid idxStr");
83 }
84 }
85
86 if (!range.has_value()) {
87 return sqlite::utils::SetError(pVtab, "Invalid idxStr, no range");
88 }
89
90 Reset(*range);
91 return SQLITE_OK;
92 }
93
Next()94 void Next() {
95 ++instruction_index_;
96 ptr_ += instr_info_.instr_size;
97 if (ptr_ == end_) {
98 return;
99 }
100
101 instr_info_.instr_addr += instr_info_.instr_size;
102 instr_info_.isa = instr_info_.next_isa;
103 FeedDecoder();
104 }
105
Eof()106 bool Eof() { return ptr_ == end_; }
107
Column(sqlite3_context * ctx,int raw_n)108 int Column(sqlite3_context* ctx, int raw_n) {
109 switch (static_cast<ColumnIndex>(raw_n)) {
110 case ColumnIndex::kInstructionIndex:
111 sqlite::result::Long(ctx, instruction_index_);
112 break;
113 case ColumnIndex::kAddress:
114 sqlite::result::Long(ctx, static_cast<int64_t>(instr_info_.instr_addr));
115 break;
116 case ColumnIndex::kOpcode:
117 sqlite::result::Long(ctx, instr_info_.opcode);
118 break;
119 case ColumnIndex::kType:
120 sqlite::result::StaticString(ctx, ToString(instr_info_.type));
121 break;
122 case ColumnIndex::kBranchAddress:
123 if (instr_info_.type == OCSD_INSTR_BR ||
124 instr_info_.type == OCSD_INSTR_BR_INDIRECT) {
125 sqlite::result::Long(ctx,
126 static_cast<int64_t>(instr_info_.branch_addr));
127 }
128 break;
129 case ColumnIndex::kIsConditional:
130 sqlite::result::Long(ctx, instr_info_.is_conditional);
131 break;
132 case ColumnIndex::kIsLink:
133 sqlite::result::Long(ctx, instr_info_.is_link);
134 break;
135 case ColumnIndex::kSubType:
136 sqlite::result::StaticString(ctx, ToString(instr_info_.sub_type));
137 break;
138 case ColumnIndex::kInstructionRange:
139 break;
140 }
141
142 return SQLITE_OK;
143 }
144
145 private:
FeedDecoder()146 void FeedDecoder() {
147 PERFETTO_CHECK(static_cast<size_t>(end_ - ptr_) >=
148 sizeof(instr_info_.opcode));
149 memcpy(&instr_info_.opcode, ptr_, sizeof(instr_info_.opcode));
150 inst_decoder_.DecodeInstruction(&instr_info_);
151 }
152
Reset(const InstructionRangeSqlValue * range)153 void Reset(const InstructionRangeSqlValue* range) {
154 if (!range) {
155 ptr_ = nullptr;
156 end_ = nullptr;
157 return;
158 }
159 const auto& config =
160 StorageHandle(storage_).GetEtmV4Config(range->config_id);
161 instr_info_.pe_type.arch = config.etm_v4_config().archVersion();
162 instr_info_.pe_type.profile = config.etm_v4_config().coreProfile();
163 instr_info_.dsb_dmb_waypoints = 0; // Not used in ETM
164 instr_info_.wfi_wfe_branch = config.etm_v4_config().wfiwfeBranch();
165 instr_info_.isa = range->isa;
166 instr_info_.instr_addr = range->st_addr;
167
168 ptr_ = range->start;
169 end_ = range->end;
170 instruction_index_ = 0;
171 FeedDecoder();
172 }
173
174 TraceStorage* storage_;
175 const uint8_t* ptr_ = nullptr;
176 const uint8_t* end_ = nullptr;
177 ocsd_instr_info instr_info_;
178 TrcIDecode inst_decoder_;
179 uint32_t instruction_index_ = 0;
180 };
181
GetInstructionCursor(sqlite3_vtab_cursor * cursor)182 IntructionCursor* GetInstructionCursor(sqlite3_vtab_cursor* cursor) {
183 return static_cast<IntructionCursor*>(cursor);
184 }
185
186 } // namespace
187
Connect(sqlite3 * db,void * ctx,int,const char * const *,sqlite3_vtab ** vtab,char **)188 int EtmIterateRangeVtable::Connect(sqlite3* db,
189 void* ctx,
190 int,
191 const char* const*,
192 sqlite3_vtab** vtab,
193 char**) {
194 if (int ret = sqlite3_declare_vtab(db, kSchema); ret != SQLITE_OK) {
195 return ret;
196 }
197 std::unique_ptr<Vtab> res = std::make_unique<Vtab>();
198 res->storage = GetContext(ctx);
199 *vtab = res.release();
200 return SQLITE_OK;
201 }
202
Disconnect(sqlite3_vtab * vtab)203 int EtmIterateRangeVtable::Disconnect(sqlite3_vtab* vtab) {
204 delete GetVtab(vtab);
205 return SQLITE_OK;
206 }
207
BestIndex(sqlite3_vtab * tab,sqlite3_index_info * info)208 int EtmIterateRangeVtable::BestIndex(sqlite3_vtab* tab,
209 sqlite3_index_info* info) {
210 bool seen_range = false;
211 int argv_index = 1;
212 std::string idx_str;
213 for (int i = 0; i < info->nConstraint; ++i) {
214 auto& in = info->aConstraint[i];
215 auto& out = info->aConstraintUsage[i];
216
217 if (in.iColumn == static_cast<int>(ColumnIndex::kInstructionRange)) {
218 if (!in.usable) {
219 return SQLITE_CONSTRAINT;
220 }
221 if (in.op != SQLITE_INDEX_CONSTRAINT_EQ) {
222 return sqlite::utils::SetError(
223 tab, "instruction_range only supports equality constraints");
224 }
225 idx_str += kInstructionRangeEqArg;
226 out.argvIndex = argv_index++;
227 out.omit = true;
228 seen_range = true;
229 continue;
230 }
231 }
232
233 if (!seen_range) {
234 return sqlite::utils::SetError(tab,
235 "Constraint required on instruction_range");
236 }
237
238 info->idxStr = sqlite3_mprintf("%s", idx_str.c_str());
239 info->needToFreeIdxStr = true;
240
241 if (info->nOrderBy == 1 &&
242 info->aOrderBy[0].iColumn ==
243 static_cast<int>(ColumnIndex::kInstructionIndex) &&
244 !info->aOrderBy[0].desc) {
245 info->orderByConsumed = true;
246 }
247
248 return SQLITE_OK;
249 }
250
Open(sqlite3_vtab * vtab,sqlite3_vtab_cursor ** cursor)251 int EtmIterateRangeVtable::Open(sqlite3_vtab* vtab,
252 sqlite3_vtab_cursor** cursor) {
253 *cursor = new IntructionCursor(GetVtab(vtab)->storage);
254 return SQLITE_OK;
255 }
256
Close(sqlite3_vtab_cursor * cursor)257 int EtmIterateRangeVtable::Close(sqlite3_vtab_cursor* cursor) {
258 delete GetInstructionCursor(cursor);
259 return SQLITE_OK;
260 }
261
Filter(sqlite3_vtab_cursor * cur,int idxNum,const char * idxStr,int argc,sqlite3_value ** argv)262 int EtmIterateRangeVtable::Filter(sqlite3_vtab_cursor* cur,
263 int idxNum,
264 const char* idxStr,
265 int argc,
266 sqlite3_value** argv) {
267 GetInstructionCursor(cur)->Filter(idxNum, idxStr, argc, argv);
268 return SQLITE_OK;
269 }
270
Next(sqlite3_vtab_cursor * cur)271 int EtmIterateRangeVtable::Next(sqlite3_vtab_cursor* cur) {
272 GetInstructionCursor(cur)->Next();
273 return SQLITE_OK;
274 }
275
Eof(sqlite3_vtab_cursor * cur)276 int EtmIterateRangeVtable::Eof(sqlite3_vtab_cursor* cur) {
277 return GetInstructionCursor(cur)->Eof();
278 }
279
Column(sqlite3_vtab_cursor * cur,sqlite3_context * ctx,int raw_n)280 int EtmIterateRangeVtable::Column(sqlite3_vtab_cursor* cur,
281 sqlite3_context* ctx,
282 int raw_n) {
283 return GetInstructionCursor(cur)->Column(ctx, raw_n);
284 }
285
Rowid(sqlite3_vtab_cursor *,sqlite_int64 *)286 int EtmIterateRangeVtable::Rowid(sqlite3_vtab_cursor*, sqlite_int64*) {
287 return SQLITE_ERROR;
288 }
289
290 } // namespace perfetto::trace_processor::etm
291