• 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_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