• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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