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