• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env python3
2#
3# Copyright (C) 2024 The Android Open Source Project
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9#      http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16#
17
18"""etm_types.py: ctypes based structures to handle ocsd_generic_trace_elem from OpenCSD.
19
20   Please refer to the documentation of OpenCSD to see the fields available and their meaning:
21   https://github.com/Linaro/OpenCSD/blob/master/decoder/docs/prog_guide/prog_guide_generic_pkts.md
22
23"""
24
25import ctypes as ct
26from enum import Enum, auto
27import sys
28
29# On 32 bit machines, ocsd_vaddr_t is 32 bit only.
30VADDR_TYPE = ct.c_uint64 if sys.maxsize > 2**32 else ct.c_uint32
31
32
33class SecLevel(Enum):
34    """ocsd_sec_level in OpenCSD."""
35    SECURE = 0
36    NONSECURE = 1
37    ROOT = 2
38    REALM = 3
39
40
41class ExLevel(Enum):
42    """ocsd_ex_level in OpenCSD."""
43    UNKNOWN = -1
44    EL0 = 0
45    EL1 = 1
46    EL2 = 2
47    EL3 = 3
48
49
50class PeContext(ct.Structure):
51    """ocsd_pe_context in OpenCSD."""
52    _fields_ = [("_security_level", ct.c_int),
53                ("_exception_level", ct.c_int),
54                ("context_id", ct.c_uint32),
55                ("vmid", ct.c_uint32),
56                ("bits64", ct.c_uint32, 1),
57                ("ctxt_id_valid", ct.c_uint32, 1),
58                ("vmid_valid", ct.c_uint32, 1),
59                ("el_valid", ct.c_uint32, 1)]
60
61    @property
62    def security_level(self) -> SecLevel:
63        return SecLevel(self._security_level)
64
65    @property
66    def exception_level(self) -> ExLevel:
67        return ExLevel(self._exception_level)
68
69
70class TraceEvent(ct.Structure):
71    """trace_event_t in OpenCSD."""
72    _fields_ = [("ev_type", ct.c_uint16),
73                ("ev_number", ct.c_uint16)]
74
75
76class TraceOnReason(Enum):
77    """trace_on_reason_t in OpenCSD."""
78    NORMAL = 0
79    OVERFLOW = 1
80    EX_DEBUG = 2
81
82
83class _SwtInfoInnerStruct(ct.Structure):
84    _fields_ = [("swt_payload_pkt_bitsize", ct.c_uint32, 8),
85                ("swt_payload_num_packets", ct.c_uint32, 8),
86                ("swt_marker_packet", ct.c_uint32, 1),
87                ("swt_has_timestamp", ct.c_uint32, 1),
88                ("swt_marker_first", ct.c_uint32, 1),
89                ("swt_master_err", ct.c_uint32, 1),
90                ("swt_global_err", ct.c_uint32, 1),
91                ("swt_trigger_event", ct.c_uint32, 1),
92                ("swt_frequency", ct.c_uint32, 1),
93                ("swt_id_valid", ct.c_uint32, 1)]
94
95
96class _SwtInfoInnerUnion(ct.Union):
97    _anonymous_ = ("_s",)
98    _fields_ = [("_s", _SwtInfoInnerStruct),
99                ("swt_flag_bits", ct.c_uint32)]
100
101
102class SwtInfo(ct.Structure):
103    """ocsd_swt_info_t in OpenCSD."""
104    _anonymous_ = ("_u",)
105    _fields_ = [("swt_master_id", ct.c_uint16),
106                ("swt_channel_id", ct.c_uint16),
107                ("_u", _SwtInfoInnerUnion)]
108
109
110class UnsyncInfo(Enum):
111    """unsync_info_t in OpenCSD."""
112    UNSYNC_UNKNOWN = 0
113    UNSYNC_INIT_DECODER = 1
114    UNSYNC_RESET_DECODER = 2
115    UNSYNC_OVERFLOW = 3
116    UNSYNC_DISCARD = 4
117    UNSYNC_BAD_PACKET = 5
118    UNSYNC_EOT = 6
119
120
121class TraceSyncMarker(Enum):
122    """trace_sync_marker_t in OpenCSD."""
123    ELEM_MARKER_TS = 0
124
125
126class TraceMarkerPayload(ct.Structure):
127    """trace_marker_payload_t in OpenCSD."""
128    _fields_ = [("_type", ct.c_int),
129                ("value", ct.c_uint32)]
130
131    @property
132    def type(self) -> TraceSyncMarker:
133        return TraceSyncMarker(self._type)
134
135
136class TraceMemtrans(Enum):
137    """trace_memtrans_t in OpenCSD."""
138    MEM_TRANS_TRACE_INIT = 0
139    MEM_TRANS_START = 1
140    MEM_TRANS_COMMIT = 2
141    MEM_TRANS_FAIL = 3
142
143
144class TraceSwIte(ct.Structure):
145    """trace_sw_ite_t in OpenCSD."""
146    _fields_ = [("el", ct.c_uint8),
147                ("value", ct.c_uint64)]
148
149
150class _ElementFlags(ct.Structure):
151    _fields_ = [("last_instr_exec", ct.c_uint32, 1),
152                ("last_instr_sz", ct.c_uint32, 3),
153                ("has_cc", ct.c_uint32, 1),
154                ("cpu_freq_change", ct.c_uint32, 1),
155                ("excep_ret_addr", ct.c_uint32, 1),
156                ("excep_data_marker", ct.c_uint32, 1),
157                ("extended_data", ct.c_uint32, 1),
158                ("has_ts", ct.c_uint32, 1),
159                ("last_instr_cond", ct.c_uint32, 1),
160                ("excep_ret_addr_br_tgt", ct.c_uint32, 1),
161                ("excep_M_tail_chain", ct.c_uint32, 1)]
162
163
164class _ElementFlagsUnion(ct.Union):
165    _anonymous_ = ("_s",)
166    _fields_ = [("_s", _ElementFlags),
167                ("flag_bits", ct.c_uint32)]
168
169
170class _Payload(ct.Union):
171    _fields_ = [("exception_number", ct.c_uint32),
172                ("trace_event", TraceEvent),
173                ("_trace_on_reason", ct.c_int),
174                ("sw_trace_info", SwtInfo),
175                ("num_instr_range", ct.c_uint32),
176                ("_unsync_eot_info", ct.c_int),
177                ("sync_marker", TraceMarkerPayload),
178                ("_mem_trans", ct.c_int),
179                ("sw_ite", TraceSwIte)]
180
181
182class ElemType(Enum):
183    """ocsd_gen_trc_elem_t in OpenCSD."""
184    UNKNOWN = 0
185    NO_SYNC = 1
186    TRACE_ON = 2
187    EO_TRACE = 3
188    PE_CONTEXT = 4
189    INSTR_RANGE = 5
190    I_RANGE_NOPATH = 6
191    ADDR_NACC = 7
192    ADDR_UNKNOWN = 8
193    EXCEPTION = 9
194    EXCEPTION_RET = 10
195    TIMESTAMP = 11
196    CYCLE_COUNT = 12
197    EVENT = 13
198    SWTRACE = 14
199    SYNC_MARKER = 15
200    MEMTRANS = 16
201    INSTRUMENTATION = 17
202    CUSTOM = 18
203
204
205class IsaType(Enum):
206    """ocsd_isa in OpenCSD."""
207    ARM = 0
208    THUMB2 = 1
209    AARCH64 = 2
210    TEE = 3
211    JAZELLE = 4
212    CUSTOM = 5
213    UNKNOWN = 6
214
215
216class InstrType(Enum):
217    """ocsd_instr_type in OpenCSD."""
218    OTHER = 0
219    BR = 1
220    BR_INDIRECT = 2
221    ISB = 3
222    DSB_DMB = 4
223    WFI_WFE = 5
224    TSTART = 6
225
226
227class InstrSubtype(Enum):
228    """ocsd_instr_subtype in OpenCSD."""
229    NONE = 0
230    BR_LINK = 1
231    V8_RET = 2
232    V8_ERET = 3
233    V7_IMPLIED_RET = 4
234
235
236class GenericTraceElement(ct.Structure):
237    """ocsd_generic_trace_elem in OpenCSD."""
238    _anonymous_ = ("_payload", "_flags")
239    _fields_ = [("_elem_type", ct.c_int),
240                ("_isa", ct.c_int),
241                ("st_addr", VADDR_TYPE),
242                ("en_addr", VADDR_TYPE),
243                ("context", PeContext),
244                ("timestamp", ct.c_uint64),
245                ("cycle_count", ct.c_uint32),
246                ("_last_i_type", ct.c_int),
247                ("_last_i_subtype", ct.c_int),
248                ("_flags", _ElementFlagsUnion),
249                ("_payload", _Payload),
250                ("ptr_extended_data", ct.c_void_p)]
251
252    @property
253    def elem_type(self) -> ElemType:
254        return ElemType(self._elem_type)
255
256    @property
257    def isa(self) -> IsaType:
258        return IsaType(self._isa)
259
260    @property
261    def last_i_type(self) -> InstrType:
262        return InstrType(self._last_i_type)
263
264    @property
265    def last_i_subtype(self) -> InstrSubtype:
266        return InstrSubtype(self._last_i_subtype)
267
268    @property
269    def trace_on_reason(self) -> TraceOnReason:
270        # This is from the anonymous structure that is called _Payload in _fields_.
271        return TraceOnReason(self._trace_on_reason)
272
273    @property
274    def unsync_eot_info(self) -> UnsyncInfo:
275        # This is from the anonymous structure that is called _Payload in _fields_.
276        return UnsyncInfo(self._unsync_eot_info)
277
278    @property
279    def mem_trans(self) -> TraceMemtrans:
280        # This is from the anonymous structure that is called _Payload in _fields_.
281        return TraceMemtrans(self._mem_trans)
282
283    def exception_type(self) -> str:
284        """Return the exception type indicated by exception_number."""
285        # The values are taken from the Arm Architecture Reference Manual for A-profile, "D5.3.30
286        # Exception 64-bit Address IS0 Packet". The reasons for generating them are listed in
287        # "D4.4.4 Exceptions to Exception element encoding".
288        names = ["PE Reset", "Debug halt", "Call", "Trap", "System Error", "Unknown",
289                 "Inst debug", "Data debug", "Unknown", "Unknown",
290                 "Alignment", "Inst Fault", "Data Fault", "Unknown",
291                 "IRQ", "FIQ",
292                 "Implementation defined 0", "Implementation defined 1",
293                 "Implementation defined 2", "Implementation defined 3",
294                 "Implementation defined 4", "Implementation defined 5",
295                 "Implementation defined 6", "Implementation defined 7",
296                 "Reserved"]
297        if self.exception_number < len(names):
298            return names[self.exception_number]
299
300        return "Reserved"
301