M board/rt1051/crashdump/crashcatcher_impl.cpp => board/rt1051/crashdump/crashcatcher_impl.cpp +6 -3
@@ 7,6 7,7 @@
#include <log/log.hpp>
#include <date/date.h>
+#include <exit_backtrace.h>
#include "crashdumpwriter_vfs.hpp"
#include "consoledump.hpp"
@@ 23,9 24,11 @@ const CrashCatcherMemoryRegion *CrashCatcher_GetMemoryRegions(void)
*/
static const CrashCatcherMemoryRegion regions[] = {
// SRAM_OC
- {0x20200000, 0x20210000, CRASH_CATCHER_BYTE},
+ {0x20200000, 0x20210000, CRASH_CATCHER_WORD},
// SRAM_DTC
- {0x20000000, 0x20070000, CRASH_CATCHER_BYTE},
+ {0x20000000, 0x20070000, CRASH_CATCHER_WORD},
+ // intentionally skip text section
+ // intentionally skip the heap section
// end tag
{0xFFFFFFFF, 0xFFFFFFFF, CRASH_CATCHER_BYTE},
};
@@ 57,6 60,6 @@ void CrashCatcher_DumpMemory(const void *pvMemory, CrashCatcherElementSizes elem
CrashCatcherReturnCodes CrashCatcher_DumpEnd(void)
{
cwrite.saveDump();
- abort();
+ _exit_backtrace(-1, false);
return CRASH_CATCHER_EXIT;
}
M board/rt1051/crashdump/crashdumpwriter_vfs.cpp => board/rt1051/crashdump/crashdumpwriter_vfs.cpp +8 -7
@@ 8,6 8,7 @@
#include <fcntl.h>
#include "purefs/vfs_subsystem.hpp"
#include <purefs/filesystem_paths.hpp>
+#include <exit_backtrace.h>
#include <filesystem>
#include <stdint.h>
@@ 23,12 24,12 @@ namespace crashdump
LOG_INFO("Crash dump %s preparing ...", crashDumpFilePath.c_str());
if (!rotator.rotateFile(crashDumpFilePath)) {
LOG_FATAL("Failed to rotate crash dumps errno: %i", errno);
- std::abort();
+ _exit_backtrace(-1, false);
}
file = std::fopen(crashDumpFilePath.c_str(), "w");
if (!file) {
LOG_FATAL("Failed to open crash dump file errno %i", errno);
- std::abort();
+ _exit_backtrace(-1, false);
}
}
@@ 44,23 45,23 @@ namespace crashdump
{
if (std::fwrite(buff, sizeof(*buff), size, file) != size) {
LOG_FATAL("Unable to write crash dump errno: %i", errno);
- std::abort();
+ _exit_backtrace(-1, false);
}
}
void CrashDumpWriterVFS::writeHalfWords(const uint16_t *buff, std::size_t size)
{
if (std::fwrite(buff, sizeof(*buff), size, file) != size) {
- LOG_FATAL("Unable to write crash dump");
- std::abort();
+ LOG_FATAL("Unable to write crash dump errno: %i", errno);
+ _exit_backtrace(-1, false);
}
}
void CrashDumpWriterVFS::writeWords(const uint32_t *buff, std::size_t size)
{
if (std::fwrite(buff, sizeof(*buff), size, file) != size) {
- LOG_FATAL("Unable to write crash dump");
- std::abort();
+ LOG_FATAL("Unable to write crash dump errno: %i", errno);
+ _exit_backtrace(-1, false);
}
}
M module-os/board/rt1051/_exit.c => module-os/board/rt1051/_exit.c +20 -2
@@ 35,10 35,13 @@
#include <log/log.hpp>
#include <task.h>
#include <macros.h>
+#include <stdbool.h>
+#include <string.h>
+#include <exit_backtrace.h>
-void __attribute__((noreturn, used)) _exit(int code)
+
+static void __attribute__((noreturn)) stop_system(void)
{
- LOG_INFO("_exit %d", code);
haltIfDebugging();
vTaskEndScheduler();
NVIC_SystemReset();
@@ 49,3 52,18 @@ void __attribute__((noreturn, used)) _exit(int code)
#endif
};
}
+
+void __attribute__((noreturn, used)) _exit_backtrace(int code, bool bt_dump)
+{
+ LOG_INFO("_exit %d", code);
+ if( bt_dump ) {
+ _StackTrace_Dump_And_Abort();
+ }
+ stop_system();
+};
+
+
+void __attribute__((noreturn, used)) _exit(int code)
+{
+ _exit_backtrace(code, code!=0);
+}
A module-os/board/rt1051/include/exit_backtrace.h => module-os/board/rt1051/include/exit_backtrace.h +48 -0
@@ 0,0 1,48 @@
+// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#pragma once
+#include <stdbool.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/** This is a extension for standard function @see exit which stop the system
+ * and optionaly takes a backtrace
+ * @param[in] code Standard terminate exit code
+ * @param[in] bt_dump If true backtrace will be created
+ * @note Function never returns
+ */
+void __attribute__((noreturn, used)) _exit_backtrace(int code, bool bt_dump);
+
+
+/** This is internal backtrce function
+ * @note In never shouldn't to be called directly in the user code
+ */
+static inline void __attribute__((always_inline)) _StackTrace_Dump_stage_1(void)
+{
+ // Redirect to the save stacktrace syscall (1)
+ __asm volatile("svc #1\n");
+}
+
+/** This is internal backtrce function
+ * @note In never shouldn't to be called directly in the user code
+ */
+extern void _StackTrace_Dump_stage_2(void);
+
+
+/** This function save a backtrace on the disk and stop the system by abort
+ */
+static inline void __attribute__((always_inline)) _StackTrace_Dump_And_Abort(void)
+{
+ _StackTrace_Dump_stage_1();
+ _StackTrace_Dump_stage_2();
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+
M module-os/board/rt1051/port.c => module-os/board/rt1051/port.c +10 -1
@@ 192,7 192,16 @@ volatile uint32_t ulDummy = 0;
void vPortSVCHandler( void )
{
__asm volatile (
- " ldr r3, pxCurrentTCBConst2 \n" /* Restore the context. */
+ " tst lr, #0x04 \n" /* Extract SVC number from the opcode */
+ " ite eq \n"
+ " mrseq r0, MSP \n"
+ " mrsne r0, PSP \n"
+ " ldr r0, [r0, #24] \n"
+ " sub r0, r0, #2 \n"
+ " ldrb r0, [r0] \n"
+ " cmp r0, #0 \n" /* Check if SVC #0 */
+ " bne _StackTrace_Dump_svc_1 \n" /* Nono zero value go to the dump backtrace */
+ " ldr r3, pxCurrentTCBConst2 \n" /* On SVC #0 Restore the context and start OS. */
" ldr r1, [r3] \n" /* Use pxCurrentTCBConst to get the pxCurrentTCB address. */
" ldr r0, [r1] \n" /* The first item in pxCurrentTCB is the task top of stack. */
" ldmia r0!, {r4-r11, r14} \n" /* Pop the registers that are not automatically saved on exception entry and the critical nesting count. */
M products/BellHybrid/CMakeLists.txt => products/BellHybrid/CMakeLists.txt +1 -0
@@ 17,6 17,7 @@ target_compile_options(BellHybrid
target_sources(BellHybrid
PRIVATE
+ ${TARGET_SOURCES}
BellHybridMain.cpp
PlatformFactory.cpp
EinkSentinelBell.cpp
M third-party/CrashDebug/CrashCatcher/CrashCatcherPriv.h => third-party/CrashDebug/CrashCatcher/CrashCatcherPriv.h +84 -84
@@ 1,84 1,84 @@
-/* Copyright (C) 2017 Adam Green (https://github.com/adamgreen)
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-*/
-/* Private header file shared with unit tests. */
-#ifndef _CRASH_CATCHER_PRIV_H_
-#define _CRASH_CATCHER_PRIV_H_
-
-
-/* Definitions used by assembly language and C code. */
-#define CRASH_CATCHER_STACK_WORD_COUNT 125
-
-/* Does this device support THUMB instructions for FPU access? */
-#ifdef __ARM_ARCH_7EM__
-#define CRASH_CATCHER_WITH_FPU 1
-#else
-#define CRASH_CATCHER_WITH_FPU 0
-#endif
-
-
-/* Definitions only required from C code. */
-#if !defined(__ASSEMBLER__) || (!__ASSEMBLER__)
-
-#include <stdint.h>
-
-
-/* Bit in LR to indicate whether PSP was used for automatic stacking of registers during exception entry. */
-#define LR_PSP (1 << 2)
-
-/* Bit in LR set to 0 when automatic stacking of floating point registers occurs during exception handling. */
-#define LR_FLOAT (1 << 4)
-
-
-/* Bit in auto stacked xPSR which indicates whether stack was force 8-byte aligned. */
-#define PSR_STACK_ALIGN (1 << 9)
-
-/* This structure is filled in by the Hard Fault exception handler (or unit test) and then passed in as a parameter to
- CrashCatcher_Entry(). */
-typedef struct
-{
- uint32_t msp;
- uint32_t psp;
- uint32_t exceptionPSR;
- uint32_t r4;
- uint32_t r5;
- uint32_t r6;
- uint32_t r7;
- uint32_t r8;
- uint32_t r9;
- uint32_t r10;
- uint32_t r11;
- uint32_t exceptionLR;
-} CrashCatcherExceptionRegisters;
-
-/* This is the area of memory that would normally be used for the stack when running on an actual Cortex-M
- processor. Unit tests can write to this buffer to simulate stack overflow. */
-extern uint32_t g_crashCatcherStack[CRASH_CATCHER_STACK_WORD_COUNT];
-
-
-/* The main entry point into CrashCatcher. Is called from the HardFault exception handler and unit tests. */
-void CrashCatcher_Entry(const CrashCatcherExceptionRegisters* pExceptionRegisters);
-
-/* Called from CrashCatcher core to copy all floating point registers to supplied buffer. The supplied buffer must be
- large enough to contain 33 32-bit values (S0-S31 & FPCSR). */
-void CrashCatcher_CopyAllFloatingPointRegisters(uint32_t* pBuffer);
-
-/* Called from CrashCatcher core to copy upper 16 floating point registers to supplied buffer. The supplied buffer must be
- large enough to contain 16 32-bit values (S16-S31). */
-void CrashCatcher_CopyUpperFloatingPointRegisters(uint32_t* pBuffer);
-
-#endif // #if !defined(__ASSEMBLER__) || (!__ASSEMBLER__)
-
-
-#endif /* _CRASH_CATCHER_PRIV_H_ */
+/* Copyright (C) 2017 Adam Green (https://github.com/adamgreen)
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+/* Private header file shared with unit tests. */
+#ifndef _CRASH_CATCHER_PRIV_H_
+#define _CRASH_CATCHER_PRIV_H_
+
+
+/* Definitions used by assembly language and C code. */
+#define CRASH_CATCHER_STACK_WORD_COUNT 8192
+
+/* Does this device support THUMB instructions for FPU access? */
+#ifdef __ARM_ARCH_7EM__
+#define CRASH_CATCHER_WITH_FPU 1
+#else
+#define CRASH_CATCHER_WITH_FPU 0
+#endif
+
+
+/* Definitions only required from C code. */
+#if !defined(__ASSEMBLER__) || (!__ASSEMBLER__)
+
+#include <stdint.h>
+
+
+/* Bit in LR to indicate whether PSP was used for automatic stacking of registers during exception entry. */
+#define LR_PSP (1 << 2)
+
+/* Bit in LR set to 0 when automatic stacking of floating point registers occurs during exception handling. */
+#define LR_FLOAT (1 << 4)
+
+
+/* Bit in auto stacked xPSR which indicates whether stack was force 8-byte aligned. */
+#define PSR_STACK_ALIGN (1 << 9)
+
+/* This structure is filled in by the Hard Fault exception handler (or unit test) and then passed in as a parameter to
+ CrashCatcher_Entry(). */
+typedef struct
+{
+ uint32_t msp;
+ uint32_t psp;
+ uint32_t exceptionPSR;
+ uint32_t r4;
+ uint32_t r5;
+ uint32_t r6;
+ uint32_t r7;
+ uint32_t r8;
+ uint32_t r9;
+ uint32_t r10;
+ uint32_t r11;
+ uint32_t exceptionLR;
+} CrashCatcherExceptionRegisters;
+
+/* This is the area of memory that would normally be used for the stack when running on an actual Cortex-M
+ processor. Unit tests can write to this buffer to simulate stack overflow. */
+extern uint32_t g_crashCatcherStack[CRASH_CATCHER_STACK_WORD_COUNT];
+
+
+/* The main entry point into CrashCatcher. Is called from the HardFault exception handler and unit tests. */
+void CrashCatcher_Entry(const CrashCatcherExceptionRegisters* pExceptionRegisters);
+
+/* Called from CrashCatcher core to copy all floating point registers to supplied buffer. The supplied buffer must be
+ large enough to contain 33 32-bit values (S0-S31 & FPCSR). */
+void CrashCatcher_CopyAllFloatingPointRegisters(uint32_t* pBuffer);
+
+/* Called from CrashCatcher core to copy upper 16 floating point registers to supplied buffer. The supplied buffer must be
+ large enough to contain 16 32-bit values (S16-S31). */
+void CrashCatcher_CopyUpperFloatingPointRegisters(uint32_t* pBuffer);
+
+#endif // #if !defined(__ASSEMBLER__) || (!__ASSEMBLER__)
+
+
+#endif /* _CRASH_CATCHER_PRIV_H_ */
M third-party/CrashDebug/CrashCatcher/CrashCatcher_armv7m.S => third-party/CrashDebug/CrashCatcher/CrashCatcher_armv7m.S +47 -2
@@ 42,7 42,7 @@ HardFault_Handler:
r11
exceptionLR */
// Prevent double fault
- ldr r0, = crash_orig_stack
+ ldr r0, =crash_orig_stack
ldr r0, [r0]
cmp r0, #0
bne .
@@ 53,7 53,6 @@ HardFault_Handler:
mrs r1, msp
ldr sp, =(g_crashCatcherStack + 4 * CRASH_CATCHER_STACK_WORD_COUNT)
push.w {r1-r11,lr}
-
// Call original console dump
ldr r0,=crash_orig_stack
str sp, [r0]
@@ 127,6 126,52 @@ CrashCatcher_CopyUpperFloatingPointRegisters:
.size CrashCatcher_CopyUpperFloatingPointRegisters, .-CrashCatcher_CopyUpperFloatingPointRegisters
+ /*
+ This function is called by the SVC #1 syscall
+ and then collect stack data for the crash dump
+ which will be run in the second stage
+ It also changes stack to the static internal
+ due to possibility of corruption of the oryginal
+ stack frame
+ extern "C" void _StackTrace_Dump_svc_1(void);
+ */
+ .global _StackTrace_Dump_svc_1
+ .type _StackTrace_Dump_svc_1 , %function
+ .thumb_func
+_StackTrace_Dump_svc_1:
+ mrs r3, xpsr
+ mrs r2, psp
+ mrs r1, msp
+ ldr sp, =(g_crashCatcherStack + 4 * CRASH_CATCHER_STACK_WORD_COUNT)
+ push.w {r1-r11,lr}
+
+ ldr r0, =crash_orig_stack
+ str sp, [r0]
+
+ mov sp, r1
+ bx lr
+ .pool
+ .size _StackTrace_Dump_svc_1, .-_StackTrace_Dump_svc_1
+
+
+ /* This function is the second stage of the crash dump
+ crash orig stack should contain valid stack from
+ the exception and now crash catcher should be able
+ to read stack frame pointer and dump data in the
+ user mode from the second part of the exit function
+ In our model crash newer return to the caller so
+ we can use simply branch without care about unstacking
+ extern "C" void _StackTrace_Dump_stage_2(void);
+ */
+ .global _StackTrace_Dump_stage_2
+ .type _StackTrace_Dump_stage_2 , %function
+ .thumb_func
+_StackTrace_Dump_stage_2:
+ ldr r0, =crash_orig_stack
+ ldr r0, [r0]
+ b CrashCatcher_Entry
+ .pool
+ .size _StackTrace_Dump_stage_2, .-_StackTrace_Dump_stage_2
.data
crash_orig_stack: .long 0