1 /*
2 * Copyright (C) 2024 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/etm_v4_decoder.h"
18
19 #include <cstdint>
20 #include <limits>
21
22 #include "perfetto/base/logging.h"
23 #include "perfetto/base/status.h"
24 #include "perfetto/ext/base/status_or.h"
25 #include "src/trace_processor/importers/etm/mapping_version.h"
26 #include "src/trace_processor/importers/etm/opencsd.h"
27 #include "src/trace_processor/importers/etm/target_memory_reader.h"
28 #include "src/trace_processor/util/status_macros.h"
29
30 namespace perfetto::trace_processor::etm {
31 namespace {
ClampToUint32(size_t size)32 uint32_t ClampToUint32(size_t size) {
33 if (size > std::numeric_limits<uint32_t>::max()) {
34 return std::numeric_limits<uint32_t>::max();
35 }
36 return static_cast<uint32_t>(size);
37 }
38 } // namespace
39
40 EtmV4Decoder::Delegate::~Delegate() = default;
41
42 // static
Create(Delegate * delegate,TargetMemoryReader * reader,const EtmV4Config & config)43 base::StatusOr<std::unique_ptr<EtmV4Decoder>> EtmV4Decoder::Create(
44 Delegate* delegate,
45 TargetMemoryReader* reader,
46 const EtmV4Config& config) {
47 std::unique_ptr<EtmV4Decoder> res(new EtmV4Decoder(delegate, reader));
48 RETURN_IF_ERROR(res->Init(config));
49 return std::move(res);
50 }
51
EtmV4Decoder(Delegate * delegate,TargetMemoryReader * reader)52 EtmV4Decoder::EtmV4Decoder(Delegate* delegate, TargetMemoryReader* reader)
53 : delegate_(delegate), memory_reader_(reader) {}
54
Init(const EtmV4Config & config)55 base::Status EtmV4Decoder::Init(const EtmV4Config& config) {
56 PERFETTO_CHECK(
57 packet_decoder_.getErrorLogAttachPt()->attach(&error_logger_) == OCSD_OK);
58 RETURN_IF_ERROR(
59 error_logger_.ToStatus(packet_decoder_.setProtocolConfig(&config)));
60 PERFETTO_CHECK(packet_decoder_.getInstrDecodeAttachPt()->attach(
61 &instruction_decoder_) == OCSD_OK);
62 PERFETTO_CHECK(packet_decoder_.getMemoryAccessAttachPt()->attach(
63 memory_reader_) == OCSD_OK);
64 PERFETTO_CHECK(packet_decoder_.getTraceElemOutAttachPt()->attach(this) ==
65 OCSD_OK);
66
67 PERFETTO_CHECK(packet_processor_.getErrorLogAttachPt()->attach(
68 &error_logger_) == OCSD_OK);
69 RETURN_IF_ERROR(
70 error_logger_.ToStatus(packet_processor_.setProtocolConfig(&config)));
71 PERFETTO_CHECK(packet_processor_.getPacketOutAttachPt()->attach(
72 &packet_decoder_) == OCSD_OK);
73
74 return base::OkStatus();
75 }
76
TraceElemIn(const ocsd_trc_index_t index_sop,const uint8_t trc_chan_id,const OcsdTraceElement & elem)77 ocsd_datapath_resp_t EtmV4Decoder::TraceElemIn(const ocsd_trc_index_t index_sop,
78 const uint8_t trc_chan_id,
79 const OcsdTraceElement& elem) {
80 const MappingVersion* content = nullptr;
81 if (elem.getType() == OCSD_GEN_TRC_ELEM_PE_CONTEXT) {
82 memory_reader_->SetPeContext(elem.getContext());
83 } else if (elem.getType() == OCSD_GEN_TRC_ELEM_INSTR_RANGE) {
84 content = memory_reader_->FindMapping(elem.st_addr);
85 PERFETTO_CHECK(content);
86 if (!content->Contains(elem.en_addr)) {
87 // Sometimes (very very rarely) we get huge instruction ranges that can
88 // span multiple adjacent mappings caused by runaway decoding.
89 // Some libraries get their code modified at load time (e.g. linux kernel
90 // does some in place changes to code for high efficiency). When loading
91 // loading the code for a file directly we do not have those modifications
92 // and thus me might get into runaway decoding.
93 PERFETTO_ELOG(
94 "Mapping does not contain full instruction range. st_addr=%" PRIu64
95 "en_addr=%" PRIu64,
96 elem.st_addr, elem.en_addr);
97 }
98 } else if (elem.getType() == OCSD_GEN_TRC_ELEM_ADDR_NACC) {
99 content = memory_reader_->FindMapping(elem.st_addr);
100 }
101 return delegate_->TraceElemIn(index_sop, trc_chan_id, elem, content);
102 }
103
Reset(ocsd_trc_index_t index)104 base::StatusOr<bool> EtmV4Decoder::Reset(ocsd_trc_index_t index) {
105 ocsd_datapath_resp_t resp =
106 packet_processor_.TraceDataIn(OCSD_OP_RESET, index, 0, nullptr, nullptr);
107 return error_logger_.ToErrorOrKeepGoing(resp);
108 }
109
Flush(ocsd_trc_index_t index)110 base::StatusOr<bool> EtmV4Decoder::Flush(ocsd_trc_index_t index) {
111 ocsd_datapath_resp_t resp =
112 packet_processor_.TraceDataIn(OCSD_OP_FLUSH, index, 0, nullptr, nullptr);
113 return error_logger_.ToErrorOrKeepGoing(resp);
114 }
115
Data(const ocsd_trc_index_t index,const size_t size,const uint8_t * data,uint32_t * num_bytes_processed)116 base::StatusOr<bool> EtmV4Decoder::Data(const ocsd_trc_index_t index,
117 const size_t size,
118 const uint8_t* data,
119 uint32_t* num_bytes_processed) {
120 ocsd_datapath_resp_t resp = packet_processor_.TraceDataIn(
121 OCSD_OP_DATA, index, ClampToUint32(size), data, num_bytes_processed);
122
123 return error_logger_.ToErrorOrKeepGoing(resp);
124 }
125
Eot(ocsd_trc_index_t index)126 base::StatusOr<bool> EtmV4Decoder::Eot(ocsd_trc_index_t index) {
127 ocsd_datapath_resp_t resp =
128 packet_processor_.TraceDataIn(OCSD_OP_EOT, index, 0, nullptr, nullptr);
129 return error_logger_.ToErrorOrKeepGoing(resp);
130 }
131
132 } // namespace perfetto::trace_processor::etm
133