• 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/importers/etm/element_cursor.h"
18 
19 #include <cstddef>
20 #include <cstdint>
21 #include <limits>
22 
23 #include "perfetto/base/logging.h"
24 #include "perfetto/base/status.h"
25 #include "src/trace_processor/importers/etm/etm_v4_decoder.h"
26 #include "src/trace_processor/importers/etm/mapping_version.h"
27 #include "src/trace_processor/importers/etm/sql_values.h"
28 #include "src/trace_processor/importers/etm/storage_handle.h"
29 #include "src/trace_processor/importers/etm/target_memory.h"
30 #include "src/trace_processor/importers/etm/target_memory_reader.h"
31 #include "src/trace_processor/importers/etm/types.h"
32 #include "src/trace_processor/storage/trace_storage.h"
33 #include "src/trace_processor/util/status_macros.h"
34 
35 namespace perfetto::trace_processor::etm {
36 
ElementCursor(TraceStorage * storage)37 ElementCursor::ElementCursor(TraceStorage* storage)
38     : storage_(storage),
39       reader_(
40           std::make_unique<TargetMemoryReader>(TargetMemory::Get(storage))) {}
41 
42 ElementCursor::~ElementCursor() = default;
43 
Filter(std::optional<tables::EtmV4TraceTable::Id> trace_id,ElementTypeMask type_mask)44 base::Status ElementCursor::Filter(
45     std::optional<tables::EtmV4TraceTable::Id> trace_id,
46     ElementTypeMask type_mask) {
47   trace_id_ = trace_id;
48   type_mask_ = type_mask;
49   if (!trace_id.has_value() || type_mask_.empty()) {
50     SetAtEof();
51     return base::OkStatus();
52   }
53   auto session = *storage_->etm_v4_session_table().FindById(
54       storage_->etm_v4_trace_table().FindById(*trace_id)->session_id());
55   RETURN_IF_ERROR(ResetDecoder(session.configuration_id()));
56 
57   reader_->SetTs(session.start_ts().value_or(0));
58   // We expect this to overflow to 0 in the Next() below
59   element_index_ = std::numeric_limits<uint32_t>::max();
60   const auto& data = StorageHandle(storage_).GetTrace(*trace_id);
61   data_start_ = data.data();
62   data_ = data_start_;
63   data_end_ = data.data() + data.size();
64 
65   if (Eof()) {
66     return base::OkStatus();
67   }
68   return Next();
69 }
70 
SetAtEof()71 void ElementCursor::SetAtEof() {
72   data_start_ = nullptr;
73   data_ = nullptr;
74   data_end_ = nullptr;
75   needs_flush_ = false;
76 }
77 
ResetDecoder(tables::EtmV4ConfigurationTable::Id config_id)78 base::Status ElementCursor::ResetDecoder(
79     tables::EtmV4ConfigurationTable::Id config_id) {
80   if (config_id == config_id_) {
81     ASSIGN_OR_RETURN(bool keep_going, decoder_->Reset(0));
82     PERFETTO_CHECK(keep_going);
83     needs_flush_ = false;
84     return base::OkStatus();
85   }
86   const EtmV4Config& config =
87       StorageHandle(storage_).GetEtmV4Config(config_id).etm_v4_config();
88 
89   ASSIGN_OR_RETURN(decoder_, EtmV4Decoder::Create(this, reader_.get(), config));
90   config_id_ = config_id;
91   needs_flush_ = false;
92   return base::OkStatus();
93 }
94 
95 // Keeps feeding data to the decoder until the next `OCSD_RESP_WAIT` response or
96 // the end of the stream. See `ElementCursor::TraceElemIn` to see how we handle
97 // the callbacks form the decoder.
98 // Note, if the decoder returns `OCSD_RESP_WAIT` the next decoding round must
99 // *not* provide new data but rather call flush!
Next()100 base::Status ElementCursor::Next() {
101   bool keep_going;
102   do {
103     if (needs_flush_) {
104       ASSIGN_OR_RETURN(keep_going, decoder_->Flush(index()));
105     } else {
106       uint32_t num_bytes_processed;
107       ASSIGN_OR_RETURN(
108           keep_going,
109           decoder_->Data(index(), static_cast<size_t>(data_end_ - data_), data_,
110                          &num_bytes_processed));
111       data_ += num_bytes_processed;
112     }
113     needs_flush_ = !keep_going;
114   } while (keep_going && data_ != data_end_);
115   return base::OkStatus();
116 }
117 
118 // This is the callback called by the open_csd library for each decoded element.
119 // The element filtering happens here, if we are interested in the element we
120 // return `OCSD_RESP_WAIT` to tell the library to stop processing, if we are an
121 // an uninteresting element (one that is being filtered out) we return
122 // `OCSD_RESP_CONT`so decoding continues.
TraceElemIn(const ocsd_trc_index_t,const uint8_t,const OcsdTraceElement & elem,const MappingVersion * mapping)123 ocsd_datapath_resp_t ElementCursor::TraceElemIn(const ocsd_trc_index_t,
124                                                 const uint8_t,
125                                                 const OcsdTraceElement& elem,
126                                                 const MappingVersion* mapping) {
127   ++element_index_;
128   if (!(type_mask_.matches(elem.getType()))) {
129     return OCSD_RESP_CONT;
130   }
131   element_ = &elem;
132   mapping_ = mapping;
133   return OCSD_RESP_WAIT;
134 }
135 
GetInstructionRange() const136 std::unique_ptr<InstructionRangeSqlValue> ElementCursor::GetInstructionRange()
137     const {
138   auto r = std::make_unique<InstructionRangeSqlValue>();
139   AddressRange range(element_->st_addr, element_->en_addr);
140   r->config_id = *config_id_;
141   r->isa = element_->isa;
142   r->st_addr = range.start();
143   // How did we get a range if there is no mapping.
144   PERFETTO_CHECK(mapping_);
145 
146   if (!mapping_->Contains(range) || !mapping_->data()) {
147     r->start = nullptr;
148     r->end = nullptr;
149   } else {
150     r->start = mapping_->data() + (range.start() - mapping_->start());
151     r->end = r->start + range.size();
152   }
153   return r;
154 }
155 
156 }  // namespace perfetto::trace_processor::etm
157