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