1# Copyright 2024 The Pigweed Authors 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); you may not 4# use this file except in compliance with the License. You may obtain a copy of 5# the License at 6# 7# https://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12# License for the specific language governing permissions and limitations under 13# the License. 14"""Tools to analyze RISCV CPU state context captured during an exception.""" 15 16from typing import Optional 17 18from pw_cpu_exception_risc_v_protos import cpu_state_pb2 19import pw_symbolizer 20 21# These registers are symbolized when dumped. 22_SYMBOLIZED_REGISTERS = ( 23 'mepc', 24 'ra', 25) 26 27 28class RiscvExceptionAnalyzer: 29 """This class provides helper functions to dump a RiscvCpuState proto.""" 30 31 def __init__( 32 self, cpu_state, symbolizer: Optional[pw_symbolizer.Symbolizer] = None 33 ): 34 self._cpu_state = cpu_state 35 self._symbolizer = symbolizer 36 37 def dump_registers(self) -> str: 38 """Dumps all captured CPU registers as a multi-line string.""" 39 registers = [] 40 for field in self._cpu_state.DESCRIPTOR.fields: 41 if self._cpu_state.HasField(field.name): 42 register_value = getattr(self._cpu_state, field.name) 43 register_str = f'{field.name:<10} 0x{register_value:08x}' 44 if ( 45 self._symbolizer is not None 46 and field.name in _SYMBOLIZED_REGISTERS 47 ): 48 symbol = self._symbolizer.symbolize(register_value) 49 if symbol.name: 50 register_str += f' {symbol}' 51 registers.append(register_str) 52 return '\n'.join(registers) 53 54 def __str__(self): 55 dump = [] 56 dump.extend( 57 ( 58 'All registers:', 59 self.dump_registers(), 60 ) 61 ) 62 return '\n'.join(dump) 63 64 65def process_snapshot( 66 serialized_snapshot: bytes, 67 symbolizer: Optional[pw_symbolizer.Symbolizer] = None, 68) -> str: 69 """Returns the stringified result of a SnapshotCpuStateOverlay message run 70 though a RiscvExceptionAnalyzer. 71 """ 72 snapshot = cpu_state_pb2.SnapshotCpuStateOverlay() 73 snapshot.ParseFromString(serialized_snapshot) 74 75 if snapshot.HasField('riscv_cpu_state'): 76 state_analyzer = RiscvExceptionAnalyzer( 77 snapshot.riscv_cpu_state, symbolizer 78 ) 79 return f'{state_analyzer}\n' 80 81 return '' 82