Fix for x86_64 build fail
[platform/upstream/connectedhomeip.git] / third_party / pigweed / repo / pw_cpu_exception_cortex_m / py / exception_analyzer_test.py
1 #!/usr/bin/env python3
2 # Copyright 2020 The Pigweed Authors
3 #
4 # Licensed under the Apache License, Version 2.0 (the "License"); you may not
5 # use this file except in compliance with the License. You may obtain a copy of
6 # the License at
7 #
8 #     https://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, WITHOUT
12 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 # License for the specific language governing permissions and limitations under
14 # the License.
15 """Tests dumped Cortex-M CPU state."""
16
17 import unittest
18 import os
19
20 from pw_protobuf_compiler import python_protos
21 from pw_cli import env
22 from pw_cpu_exception_cortex_m import exception_analyzer, cortex_m_constants
23
24 CPU_STATE_PROTO_PATH = os.path.join(
25     env.pigweed_environment().PW_ROOT,  #pylint: disable=no-member
26     'pw_cpu_exception_cortex_m',
27     'pw_cpu_exception_cortex_m_protos',
28     'cpu_state.proto')
29
30 cpu_state_pb2 = python_protos.compile_and_import_file(CPU_STATE_PROTO_PATH)
31
32 # pylint: disable=protected-access
33
34
35 class BasicFaultTest(unittest.TestCase):
36     """Test basic fault analysis functions."""
37     def test_empty_state(self):
38         """Ensure an empty CPU state proto doesn't indicate an active fault."""
39         cpu_state_proto = cpu_state_pb2.ArmV7mCpuState()
40         cpu_state_info = exception_analyzer.CortexMExceptionAnalyzer(
41             cpu_state_proto)
42         self.assertFalse(cpu_state_info.is_fault_active())
43
44     def test_cfsr_fault(self):
45         """Ensure a fault is active if CFSR bits are set."""
46         cpu_state_proto = cpu_state_pb2.ArmV7mCpuState()
47         cpu_state_proto.cfsr = (
48             cortex_m_constants.PW_CORTEX_M_CFSR_STKOF_MASK
49             | cortex_m_constants.PW_CORTEX_M_CFSR_MUNSTKERR_MASK)
50         cpu_state_info = exception_analyzer.CortexMExceptionAnalyzer(
51             cpu_state_proto)
52         self.assertTrue(cpu_state_info.is_fault_active())
53
54     def test_icsr_fault(self):
55         """Ensure a fault is active if ICSR says the handler is active."""
56         cpu_state_proto = cpu_state_pb2.ArmV7mCpuState()
57         cpu_state_proto.icsr = (
58             cortex_m_constants.PW_CORTEX_M_HARD_FAULT_ISR_NUM)
59         cpu_state_info = exception_analyzer.CortexMExceptionAnalyzer(
60             cpu_state_proto)
61         self.assertTrue(cpu_state_info.is_fault_active())
62
63     def test_cfsr_fields(self):
64         """Ensure correct fields are returned when CFSR bits are set."""
65         cpu_state_proto = cpu_state_pb2.ArmV7mCpuState()
66         cpu_state_proto.cfsr = (
67             cortex_m_constants.PW_CORTEX_M_CFSR_STKOF_MASK
68             | cortex_m_constants.PW_CORTEX_M_CFSR_MUNSTKERR_MASK)
69         cpu_state_info = exception_analyzer.CortexMExceptionAnalyzer(
70             cpu_state_proto)
71         active_fields = [
72             field.name for field in cpu_state_info.active_cfsr_fields()
73         ]
74         self.assertEqual(len(active_fields), 2)
75         self.assertIn('STKOF', active_fields)
76         self.assertIn('MUNSTKERR', active_fields)
77
78
79 class ExceptionCauseTest(unittest.TestCase):
80     """Test exception cause analysis."""
81     def test_empty_cpu_state(self):
82         """Ensure empty CPU state has no known cause."""
83         cpu_state_proto = cpu_state_pb2.ArmV7mCpuState()
84         cpu_state_info = exception_analyzer.CortexMExceptionAnalyzer(
85             cpu_state_proto)
86         self.assertEqual(cpu_state_info.exception_cause(), 'unknown exception')
87
88     def test_unknown_exception(self):
89         """Ensure CPU state with insufficient info has no known cause."""
90         cpu_state_proto = cpu_state_pb2.ArmV7mCpuState()
91         # Set CFSR to a valid value.
92         cpu_state_proto.cfsr = 0
93         cpu_state_info = exception_analyzer.CortexMExceptionAnalyzer(
94             cpu_state_proto)
95         self.assertEqual(cpu_state_info.exception_cause(), 'unknown exception')
96
97     def test_single_usage_fault(self):
98         """Ensure usage faults are properly identified."""
99         cpu_state_proto = cpu_state_pb2.ArmV7mCpuState()
100         cpu_state_proto.cfsr = cortex_m_constants.PW_CORTEX_M_CFSR_STKOF_MASK
101         cpu_state_info = exception_analyzer.CortexMExceptionAnalyzer(
102             cpu_state_proto)
103         self.assertEqual(cpu_state_info.exception_cause(),
104                          'usage fault [STKOF]')
105
106     def test_single_usage_fault_without_fields(self):
107         """Ensure disabling show_active_cfsr_fields hides field names."""
108         cpu_state_proto = cpu_state_pb2.ArmV7mCpuState()
109         cpu_state_proto.cfsr = cortex_m_constants.PW_CORTEX_M_CFSR_STKOF_MASK
110         cpu_state_info = exception_analyzer.CortexMExceptionAnalyzer(
111             cpu_state_proto)
112         self.assertEqual(cpu_state_info.exception_cause(False), 'usage fault')
113
114     def test_multiple_faults(self):
115         """Ensure multiple CFSR bits are identified and reported."""
116         cpu_state_proto = cpu_state_pb2.ArmV7mCpuState()
117         cpu_state_proto.cfsr = (
118             cortex_m_constants.PW_CORTEX_M_CFSR_STKOF_MASK
119             | cortex_m_constants.PW_CORTEX_M_CFSR_UNSTKERR_MASK)
120         cpu_state_info = exception_analyzer.CortexMExceptionAnalyzer(
121             cpu_state_proto)
122         self.assertEqual(cpu_state_info.exception_cause(),
123                          'usage fault, bus fault [UNSTKERR] [STKOF]')
124
125     def test_mmfar_missing(self):
126         """Ensure if mmfar is valid but missing it is handled safely."""
127         cpu_state_proto = cpu_state_pb2.ArmV7mCpuState()
128         cpu_state_proto.cfsr = (
129             cortex_m_constants.PW_CORTEX_M_CFSR_MUNSTKERR_MASK
130             | cortex_m_constants.PW_CORTEX_M_CFSR_MMARVALID_MASK)
131         cpu_state_info = exception_analyzer.CortexMExceptionAnalyzer(
132             cpu_state_proto)
133         self.assertEqual(cpu_state_info.exception_cause(False),
134                          'memory management fault at ???')
135
136     def test_mmfar_valid(self):
137         """Validate output format of valid MMFAR."""
138         cpu_state_proto = cpu_state_pb2.ArmV7mCpuState()
139         cpu_state_proto.cfsr = (
140             cortex_m_constants.PW_CORTEX_M_CFSR_MUNSTKERR_MASK
141             | cortex_m_constants.PW_CORTEX_M_CFSR_MMARVALID_MASK)
142         cpu_state_proto.mmfar = 0x722470e4
143         cpu_state_info = exception_analyzer.CortexMExceptionAnalyzer(
144             cpu_state_proto)
145         self.assertEqual(cpu_state_info.exception_cause(False),
146                          'memory management fault at 0x722470e4')
147
148     def test_imprecise_bus_fault(self):
149         """Check that imprecise bus faults are identified correctly."""
150         cpu_state_proto = cpu_state_pb2.ArmV7mCpuState()
151         cpu_state_proto.cfsr = (
152             cortex_m_constants.PW_CORTEX_M_CFSR_IMPRECISERR_MASK
153             | cortex_m_constants.PW_CORTEX_M_CFSR_IBUSERR_MASK)
154         cpu_state_info = exception_analyzer.CortexMExceptionAnalyzer(
155             cpu_state_proto)
156         self.assertEqual(cpu_state_info.exception_cause(False),
157                          'imprecise bus fault')
158
159
160 class TextDumpTest(unittest.TestCase):
161     """Test larger state dumps."""
162     def test_registers(self):
163         """Validate output of general register dumps."""
164         cpu_state_proto = cpu_state_pb2.ArmV7mCpuState()
165         cpu_state_proto.pc = 0xdfadd966
166         cpu_state_proto.mmfar = 0xaf2ea98a
167         cpu_state_proto.r0 = 0xf3b235b1
168         cpu_state_info = exception_analyzer.CortexMExceptionAnalyzer(
169             cpu_state_proto)
170         expected_dump = '\n'.join((
171             'pc         0xdfadd966',
172             'mmfar      0xaf2ea98a',
173             'r0         0xf3b235b1',
174         ))
175         self.assertEqual(cpu_state_info.dump_registers(), expected_dump)
176
177     def test_dump_no_cfsr(self):
178         """Validate basic CPU state dump."""
179         cpu_state_proto = cpu_state_pb2.ArmV7mCpuState()
180         cpu_state_proto.pc = 0xd2603058
181         cpu_state_proto.mmfar = 0x8e4eb9a2
182         cpu_state_proto.r0 = 0xdb5e7168
183         cpu_state_info = exception_analyzer.CortexMExceptionAnalyzer(
184             cpu_state_proto)
185         expected_dump = '\n'.join((
186             'Exception caused by a unknown exception.',
187             '',
188             'No active Crash Fault Status Register (CFSR) fields.',
189             '',
190             'All registers:',
191             'pc         0xd2603058',
192             'mmfar      0x8e4eb9a2',
193             'r0         0xdb5e7168',
194         ))
195         self.assertEqual(str(cpu_state_info), expected_dump)
196
197     def test_dump_with_cfsr(self):
198         """Validate CPU state dump with CFSR bits set is formatted correctly."""
199         cpu_state_proto = cpu_state_pb2.ArmV7mCpuState()
200         cpu_state_proto.cfsr = (
201             cortex_m_constants.PW_CORTEX_M_CFSR_PRECISERR_MASK
202             | cortex_m_constants.PW_CORTEX_M_CFSR_BFARVALID_MASK)
203         cpu_state_proto.pc = 0xd2603058
204         cpu_state_proto.bfar = 0xdeadbeef
205         cpu_state_proto.mmfar = 0x8e4eb9a2
206         cpu_state_proto.r0 = 0xdb5e7168
207         cpu_state_info = exception_analyzer.CortexMExceptionAnalyzer(
208             cpu_state_proto)
209         expected_dump = '\n'.join((
210             'Exception caused by a bus fault at 0xdeadbeef.',
211             '',
212             'Active Crash Fault Status Register (CFSR) fields:',
213             'PRECISERR   Precise bus fault.',
214             'BFARVALID   BFAR is valid.',
215             '',
216             'All registers:',
217             'pc         0xd2603058',
218             'cfsr       0x00008200',
219             'mmfar      0x8e4eb9a2',
220             'bfar       0xdeadbeef',
221             'r0         0xdb5e7168',
222         ))
223         self.assertEqual(str(cpu_state_info), expected_dump)
224
225
226 if __name__ == '__main__':
227     unittest.main()