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