xref: /aosp_15_r20/external/pigweed/pw_cpu_exception_cortex_m/support.cc (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1 // Copyright 2019 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 
15 #include "pw_cpu_exception/support.h"
16 
17 #include <cinttypes>
18 #include <cstdint>
19 
20 #include "pw_cpu_exception_cortex_m/cpu_state.h"
21 #include "pw_cpu_exception_cortex_m/util.h"
22 #include "pw_cpu_exception_cortex_m_private/config.h"
23 #include "pw_cpu_exception_cortex_m_private/cortex_m_constants.h"
24 #include "pw_log/log.h"
25 #include "pw_preprocessor/arch.h"
26 #include "pw_span/span.h"
27 #include "pw_string/string_builder.h"
28 
29 namespace pw::cpu_exception {
30 
RawFaultingCpuState(const pw_cpu_exception_State & cpu_state)31 span<const uint8_t> RawFaultingCpuState(
32     const pw_cpu_exception_State& cpu_state) {
33   return span(reinterpret_cast<const uint8_t*>(&cpu_state), sizeof(cpu_state));
34 }
35 
36 // Using this function adds approximately 100 bytes to binary size.
ToString(const pw_cpu_exception_State & cpu_state,const span<char> & dest)37 void ToString(const pw_cpu_exception_State& cpu_state, const span<char>& dest) {
38   StringBuilder builder(dest);
39   const cortex_m::ExceptionRegisters& base = cpu_state.base;
40   const cortex_m::ExtraRegisters& extended = cpu_state.extended;
41 
42 #define _PW_FORMAT_REGISTER(state_section, name) \
43   builder.Format("%s=0x%08" PRIx32 "\n", #name, state_section.name)
44 
45   // Other registers.
46   if (base.pc != cortex_m::kUndefinedPcLrOrPsrRegValue) {
47     _PW_FORMAT_REGISTER(base, pc);
48   }
49   if (base.lr != cortex_m::kUndefinedPcLrOrPsrRegValue) {
50     _PW_FORMAT_REGISTER(base, lr);
51   }
52   if (base.psr != cortex_m::kUndefinedPcLrOrPsrRegValue) {
53     _PW_FORMAT_REGISTER(base, psr);
54   }
55   _PW_FORMAT_REGISTER(extended, msp);
56   _PW_FORMAT_REGISTER(extended, psp);
57   _PW_FORMAT_REGISTER(extended, exc_return);
58 #if _PW_ARCH_ARM_V8M_MAINLINE || _PW_ARCH_ARM_V8_1M_MAINLINE
59   _PW_FORMAT_REGISTER(extended, msplim);
60   _PW_FORMAT_REGISTER(extended, psplim);
61 #endif  // _PW_ARCH_ARM_V8M_MAINLINE || _PW_ARCH_ARM_V8_1M_MAINLINE
62 #if !_PW_ARCH_ARM_V6M
63   _PW_FORMAT_REGISTER(extended, cfsr);
64   _PW_FORMAT_REGISTER(extended, mmfar);
65   _PW_FORMAT_REGISTER(extended, bfar);
66 #endif  // !_PW_ARCH_ARM_V6M
67   _PW_FORMAT_REGISTER(extended, icsr);
68 #if !_PW_ARCH_ARM_V6M
69   _PW_FORMAT_REGISTER(extended, hfsr);
70 #endif  // !_PW_ARCH_ARM_V6M
71   _PW_FORMAT_REGISTER(extended, shcsr);
72   _PW_FORMAT_REGISTER(extended, control);
73 
74   // General purpose registers.
75   _PW_FORMAT_REGISTER(base, r0);
76   _PW_FORMAT_REGISTER(base, r1);
77   _PW_FORMAT_REGISTER(base, r2);
78   _PW_FORMAT_REGISTER(base, r3);
79   _PW_FORMAT_REGISTER(extended, r4);
80   _PW_FORMAT_REGISTER(extended, r5);
81   _PW_FORMAT_REGISTER(extended, r6);
82   _PW_FORMAT_REGISTER(extended, r7);
83   _PW_FORMAT_REGISTER(extended, r8);
84   _PW_FORMAT_REGISTER(extended, r9);
85   _PW_FORMAT_REGISTER(extended, r10);
86   _PW_FORMAT_REGISTER(extended, r11);
87   _PW_FORMAT_REGISTER(base, r12);
88 
89 #undef _PW_FORMAT_REGISTER
90 }
91 
92 // Using this function adds approximately 100 bytes to binary size.
LogCpuState(const pw_cpu_exception_State & cpu_state)93 void LogCpuState(const pw_cpu_exception_State& cpu_state) {
94   const cortex_m::ExceptionRegisters& base = cpu_state.base;
95   const cortex_m::ExtraRegisters& extended = cpu_state.extended;
96 
97   cortex_m::LogExceptionAnalysis(cpu_state);
98 
99   PW_LOG_INFO("All captured CPU registers:");
100 
101 #define _PW_LOG_REGISTER(state_section, name) \
102   PW_LOG_INFO("  %-10s 0x%08" PRIx32, #name, state_section.name)
103 
104   // Other registers.
105   if (base.pc != cortex_m::kUndefinedPcLrOrPsrRegValue) {
106     _PW_LOG_REGISTER(base, pc);
107   }
108   if (base.lr != cortex_m::kUndefinedPcLrOrPsrRegValue) {
109     _PW_LOG_REGISTER(base, lr);
110   }
111   if (base.psr != cortex_m::kUndefinedPcLrOrPsrRegValue) {
112     _PW_LOG_REGISTER(base, psr);
113   }
114   _PW_LOG_REGISTER(extended, msp);
115   _PW_LOG_REGISTER(extended, psp);
116   _PW_LOG_REGISTER(extended, exc_return);
117 #if _PW_ARCH_ARM_V8M_MAINLINE || _PW_ARCH_ARM_V8_1M_MAINLINE
118   _PW_LOG_REGISTER(extended, msplim);
119   _PW_LOG_REGISTER(extended, psplim);
120 #endif  // _PW_ARCH_ARM_V8M_MAINLINE || _PW_ARCH_ARM_V8_1M_MAINLINE
121 #if !_PW_ARCH_ARM_V6M
122   _PW_LOG_REGISTER(extended, cfsr);
123   _PW_LOG_REGISTER(extended, mmfar);
124   _PW_LOG_REGISTER(extended, bfar);
125 #endif  // !_PW_ARCH_ARM_V6M
126   _PW_LOG_REGISTER(extended, icsr);
127 #if !_PW_ARCH_ARM_V6M
128   _PW_LOG_REGISTER(extended, hfsr);
129 #endif  // !_PW_ARCH_ARM_V6M
130   _PW_LOG_REGISTER(extended, shcsr);
131   _PW_LOG_REGISTER(extended, control);
132 
133   // General purpose registers.
134   _PW_LOG_REGISTER(base, r0);
135   _PW_LOG_REGISTER(base, r1);
136   _PW_LOG_REGISTER(base, r2);
137   _PW_LOG_REGISTER(base, r3);
138   _PW_LOG_REGISTER(extended, r4);
139   _PW_LOG_REGISTER(extended, r5);
140   _PW_LOG_REGISTER(extended, r6);
141   _PW_LOG_REGISTER(extended, r7);
142   _PW_LOG_REGISTER(extended, r8);
143   _PW_LOG_REGISTER(extended, r9);
144   _PW_LOG_REGISTER(extended, r10);
145   _PW_LOG_REGISTER(extended, r11);
146   _PW_LOG_REGISTER(base, r12);
147 
148 #undef _PW_LOG_REGISTER
149 }
150 
151 }  // namespace pw::cpu_exception
152