• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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