~aleteoryx/muditaos

22cf94225357069ee327ee23f89dbd6f53a12748 — Lucjan Bryndza 4 years ago f82d6f1
[CP-670] Fix save crash dump

Fix saving crash dump and add create crash dump
when exit function is called.
Also crashdumps size is slighthy reduced
because for backtrace we don't need to grab
the text section and heap section.

Signed-off-by: Lucjan Bryndza <lucjan.bryndza@mudita.com>
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