~aleteoryx/muditaos

33d652c1a170e17b4de4a049577558497b0f73c0 — Artur Śleszyński 5 years ago 9f0c945
[EGD-6156] Create crash dumps

Integrate the CrashCatcher library in order to store phone state after
a fault occurs. The dumps are stored in the CrashCatcher hex format and
can be debugged using the CrashDebug stub built for x86_64 via the
'debug_crash_dump.sh' script.
M .gitmodules => .gitmodules +3 -0
@@ 81,3 81,6 @@
	path = test/harness
	url = ../QAMuditaHarness.git
	shallow = true
[submodule "module-utils/CrashDebug"]
	path = module-utils/CrashDebug
	url = git@github.com:adamgreen/CrashDebug.git

M Target_RT1051.cmake => Target_RT1051.cmake +8 -0
@@ 68,6 68,7 @@ set(TARGET_COMPILE_FEATURES
        CACHE INTERNAL "" )


set_property(SOURCE ${CMAKE_CURRENT_LIST_DIR}/board/rt1051/crashdump/CrashCatcher_armv7m.S PROPERTY LANGUAGE C)
set(TARGET_SOURCES

        ${CMAKE_CURRENT_LIST_DIR}/board/rt1051/_exit.c


@@ 77,6 78,11 @@ set(TARGET_SOURCES
        ${CMAKE_CURRENT_LIST_DIR}/board/rt1051/xip/evkbimxrt1050_flexspi_nor_config.c
        ${CMAKE_CURRENT_LIST_DIR}/board/rt1051/xip/evkbimxrt1050_sdram_ini_dcd.c
        ${CMAKE_CURRENT_LIST_DIR}/board/rt1051/xip/fsl_flexspi_nor_boot.c
        ${CMAKE_SOURCE_DIR}/module-utils/CrashDebug/CrashCatcher/Core/src/CrashCatcher.c
        ${CMAKE_CURRENT_LIST_DIR}/board/rt1051/crashdump/CrashCatcher_armv7m.S
        ${CMAKE_CURRENT_LIST_DIR}/board/rt1051/crashdump/crashcatcher_impl.cpp
        ${CMAKE_CURRENT_LIST_DIR}/board/rt1051/crashdump/crashdumpwriter_vfs.cpp
        ${CMAKE_CURRENT_LIST_DIR}/board/rt1051/crashdump/consoledump.cpp
        CACHE INTERNAL ""
        )



@@ 87,6 93,8 @@ set(TARGET_DIR_INCLUDES

set(BOARD_DIR_INCLUDES
        ${CMAKE_CURRENT_LIST_DIR}/board/rt1051/newlib/include
        ${CMAKE_SOURCE_DIR}/module-utils/CrashDebug/CrashCatcher/include
        ${CMAKE_SOURCE_DIR}/module-utils/CrashDebug/CrashCatcher/Core/src
)

set(TARGET_LIBRARIES

A board/rt1051/crashdump/CrashCatcher_armv7m.S => board/rt1051/crashdump/CrashCatcher_armv7m.S +142 -0
@@ 0,0 1,142 @@
/* Copyright (C) 2019  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.
*/
#include "CrashCatcherPriv.h"

/* Implementation of ARMv7-M assembly language code to trap exceptions and call CrashCatcher_Entry(). */
    .text
    .syntax unified
    .arch armv7-m

    /* Called on Hard Fault exception.  Stacks important registers and calls CrashCatcher_Entry().

        extern "C" void HardFault_Handler(void);
    */
    .global HardFault_Handler
    .type HardFault_Handler, %function
    .thumb_func
HardFault_Handler:
    /* Push the following onto the stack (see CrashCatcherExceptionRegisters structure). The g_crashCatcherStack buffer
       is reserved for use as the stack while CrashCatcher is running.
        msp
        psp
        exceptionPSR
        r4
        r5
        r6
        r7
        r8
        r9
        r10
        r11
        exceptionLR */
    // Prevent double fault
    ldr r0, = crash_orig_stack
    ldr r0, [r0]
    cmp r0, #0
    bne .

    // Create stack for CrashCatcher
    mrs     r3, xpsr
    mrs     r2, psp
    mrs     r1, msp
    ldr     sp, =(g_crashCatcherStack + 4 * CRASH_CATCHER_STACK_WORD_COUNT)
    push.w  {r1-r11,lr}
    // Call oryginal console dump
    ldr r0,=crash_orig_stack
    str sp, [r0]
    mov sp, r1

    // Call console crash handler
    mrs r0, msp
    mov sp, r0
    tst lr, #4
    ite eq
    mrseq r0,msp
    mrsne r0,psp
    push {lr}
    bl crashCatcherExtPrintConsoleHF
    pop {lr}
    ldr r0,=crash_orig_stack
    ldr sp, [r0]

    // Call CrashCatcher_Entry with first argument pointing to registers that were just stacked.
    mov     r0, sp
    ldr r2,=CrashCatcher_Entry  // Stack frame exception return
    mrs r3, psp
    str r2, [r3, #0x18]
    str r0, [r3]
    orr lr, lr, #4        // Back to user stack
    orr lr, lr, #8        // Back to user mode
    bx lr                 // Return from exception and jump to the CatchCatcher_Entry
    b .


    // Let assembler know that we have hit the end of the HardFault_Handler function.
    .pool
    .size   HardFault_Handler, .-HardFault_Handler



    /* 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 & FPSCR).

        void CrashCatcher_CopyAllFloatingPointRegisters(uint32_t* pBuffer);
    */
    .global CrashCatcher_CopyAllFloatingPointRegisters
    .type CrashCatcher_CopyAllFloatingPointRegisters, %function
    .thumb_func
CrashCatcher_CopyAllFloatingPointRegisters:
#if CRASH_CATCHER_WITH_FPU
    // Grab a copy of FPSCR before issuing any other FP instructions.
    vmrs        r1, fpscr

    // Move s0 - s31 to pBuffer.
    vstmia.32   r0!, {s0 - s31}

    // Move fpscr to pBuffer.
    str         r1, [r0]
#endif
    // Return to caller.
    bx          lr

    .pool
    .size   CrashCatcher_CopyAllFloatingPointRegisters, .-CrashCatcher_CopyAllFloatingPointRegisters



    /* 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);
    */
    .global CrashCatcher_CopyUpperFloatingPointRegisters
    .type CrashCatcher_CopyUpperFloatingPointRegisters, %function
    .thumb_func
CrashCatcher_CopyUpperFloatingPointRegisters:
#if CRASH_CATCHER_WITH_FPU
    // Move s16 - s31 to pBuffer.
    vstmia.32   r0!, {s16 - s31}
#endif
    // Return to caller.
    bx      lr

    .pool
    .size   CrashCatcher_CopyUpperFloatingPointRegisters, .-CrashCatcher_CopyUpperFloatingPointRegisters



    .data
    crash_orig_stack: .long 0


A board/rt1051/crashdump/consoledump.cpp => board/rt1051/crashdump/consoledump.cpp +240 -0
@@ 0,0 1,240 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include <log/log.hpp>

#include "consoledump.hpp"
#include "MIMXRT1051.h"

/// Hard Fault Fault Status Register
struct __attribute__((packed)) hfsr_t
{
    union
    {
        uint32_t all;
        struct
        {
            uint32_t rsrvd0 : 1;
            uint32_t vecttbl : 1;
            uint32_t rsrvd1 : 28;
            uint32_t forced : 1;
            uint32_t debugevt : 1;
        };
    };
};

/// MemManage Fault Status Register
struct __attribute__((packed)) mmfsr_t
{
    union
    {
        uint8_t all;
        struct
        {
            uint8_t iaccviol : 1;
            uint8_t daccviol : 1;
            uint8_t rsrvd2 : 1;
            uint8_t munstkerr : 1;
            uint8_t mstkerr : 1;
            uint8_t mlsperr : 1;
            uint8_t rsrvd6 : 1;
            uint8_t mmarvalid : 1;
        };
    };
};

/// BusFault Status Register
struct __attribute__((packed)) bfsr_t
{
    union
    {
        uint8_t all;
        struct
        {
            uint8_t ibuserr : 1;
            uint8_t preciserr : 1;
            uint8_t impreciserr : 1;
            uint8_t unstkerr : 1;
            uint8_t stkerr : 1;
            uint8_t lsperr : 1;
            uint8_t rsrvd6 : 1;
            uint8_t bfarvalid : 1;
        };
    };
};

/// UsageFault Status Register
struct __attribute__((packed)) ufsr_t
{
    union
    {
        uint16_t all;
        struct
        {
            uint8_t undefinstr : 1;
            uint8_t invstate : 1;
            uint8_t invpc : 1;
            uint8_t nocp : 1;
            uint8_t rsrvd4_7 : 3;
            uint8_t unaligned : 1;
            uint8_t divbyzero : 1;
            uint8_t rsrvd10_15 : 6;
        };
    };
};

/// Configurable Fault Status Register
struct __attribute__((packed)) cfsr_t
{
    union
    {
        uint32_t all;
        struct
        {
            mmfsr_t mmfsr;
            bfsr_t bfsr;
            ufsr_t ufsr;
        };
    };
};

/// Auxiliary Bus Fault Status register
struct __attribute__((packed)) abfsr_t
{
    union
    {
        uint32_t all;
        struct
        {
            uint32_t itcm : 1;
            uint32_t dtcm : 1;
            uint32_t ahbp : 1;
            uint32_t axim : 1;
            uint32_t eppb : 1;
            uint32_t rsrvd5_7 : 3;
            uint32_t aximtype : 2;
            uint32_t rsrvd10_31 : 1;
        };
    };
};

struct __attribute__((packed)) syslog_t
{
    syslog_exception_stack_frame_t stackFrame;
    struct
    {
        hfsr_t hfsr;         /// Hard Fault Fault Status Register
        cfsr_t cfsr;         /// Configurable Fault Status Register
        uint32_t mmfar;      /// MemManage Fault Address Register
        uint32_t bfar;       /// BusFault Address Register
        abfsr_t abfsr;       /// Auxiliary Bus Fault Status register
        uint32_t exc_return; /// EXC_RETURN value for the exception being serviced
    } registers;
};

namespace
{
    static void printHardFaultInfo(const syslog_t &syslog)
    {
        LOG_FATAL("!!! HardFault Detected !!!");
        LOG_FATAL("* Stack Frame:");
        LOG_FATAL("R0  = 0x%0" PRIX32, syslog.stackFrame.r0);
        LOG_FATAL("R1  = 0x%0" PRIX32, syslog.stackFrame.r1);
        LOG_FATAL("R2  = 0x%0" PRIX32, syslog.stackFrame.r2);
        LOG_FATAL("R3  = 0x%0" PRIX32, syslog.stackFrame.r3);
        LOG_FATAL("R12 = 0x%0" PRIX32, syslog.stackFrame.r12);
        LOG_FATAL("LR  = 0x%0" PRIX32, syslog.stackFrame.lr);
        LOG_FATAL("PC  = 0x%0" PRIX32, syslog.stackFrame.pc);
        LOG_FATAL("PSR = 0x%0" PRIX32, syslog.stackFrame.psr);

        LOG_FATAL("* Fault Status Registers:");
        LOG_FATAL("SCB->HFSR = 0x%0" PRIX32, syslog.registers.hfsr.all);
        LOG_FATAL("SCB->CFSR = 0x%0" PRIX32, syslog.registers.cfsr.all);
        LOG_FATAL("SCB->MMAR = 0x%0" PRIX32, syslog.registers.mmfar);
        LOG_FATAL("SCB->BFAR = 0x%0" PRIX32, syslog.registers.bfar);
        LOG_FATAL("SCB->ABFSR = 0x%0" PRIX32, syslog.registers.abfsr.all);
        LOG_FATAL("EXC_RETURN = 0x%0" PRIX32, syslog.registers.exc_return);

        LOG_FATAL("* Details of Fault Status Registers:");
        hfsr_t hfsr = syslog.registers.hfsr;
        LOG_FATAL("SCB->HFSR = 0x%0" PRIX32 " - HardFault Status Register", hfsr.all);
        if (hfsr.debugevt)
            LOG_FATAL(" - DEBUGEVT: Hard fault caused by debug event");
        if (hfsr.forced)
            LOG_FATAL(" - FORCED: Hard fault caused by bus/memory management/usage fault");
        if (hfsr.vecttbl)
            LOG_FATAL(" - VECTBL: BusFault on vector table read");

        cfsr_t cfsr = syslog.registers.cfsr;
        LOG_FATAL("SCB->CFSR = 0x%0" PRIX32 " - Configurable Fault Status Register", cfsr.all);
        mmfsr_t mmfsr = cfsr.mmfsr;
        LOG_FATAL("> SCB->MMFSR = 0x%0" PRIX8 " Memory Management Fault Status Register", mmfsr.all);
        if (mmfsr.mmarvalid)
            LOG_FATAL(" - MMARVALID: MMAR is valid");
        if (mmfsr.mlsperr)
            LOG_FATAL(" - MLSPERR: A MemManage fault occurred during floating-point lazy state preservation");
        if (mmfsr.mstkerr)
            LOG_FATAL(" - MSTKERR: MemManage fault on stacking for exception entry");
        if (mmfsr.munstkerr)
            LOG_FATAL(" - MUNSTKERR: MemManage fault on unstacking for a return from exception:");
        if (mmfsr.daccviol)
            LOG_FATAL(" - DACCVIOL: Data access violation");
        if (mmfsr.iaccviol)
            LOG_FATAL(" - IACCVIOL: Instruction access violation");

        bfsr_t bfsr = cfsr.bfsr;
        LOG_FATAL("> SCB->BFSR = 0x%0" PRIX8 " - Bus Fault Status Register ", bfsr.all);
        if (bfsr.bfarvalid)
            LOG_FATAL(" - BFARVALID: BFAR is valid  ");
        if (bfsr.lsperr)
            LOG_FATAL(" - LSPERR: A bus fault occurred during floating-point lazy state preservation");
        if (bfsr.stkerr)
            LOG_FATAL(" - STKERR: Stacking error");
        if (bfsr.unstkerr)
            LOG_FATAL(" - UNSTKERR: Unstacking error");
        if (bfsr.impreciserr)
            LOG_FATAL(" - IMPREISERR: Imprecise data bus error");
        if (bfsr.preciserr)
            LOG_FATAL(" - PRECISERR: Precise data bus error");
        if (bfsr.ibuserr)
            LOG_FATAL(" - IBUSERR: Instruction bus error");

        ufsr_t ufsr = cfsr.ufsr;
        LOG_FATAL("> SCB->UFSR = 0x%0" PRIX16 " - Usage Fault Status Register", ufsr.all);
        if (ufsr.divbyzero)
            LOG_FATAL(" - DIVBYZERO: Divide by zero UsageFault");
        if (ufsr.unaligned)
            LOG_FATAL(" - UNALIGNED: Unaligned access UsageFault");
        if (ufsr.nocp)
            LOG_FATAL(" - NOCP: Attempt to execute a coprocessor instruction");
        if (ufsr.invpc)
            LOG_FATAL(" - INVPC: Invalid PC load UsageFault");
        if (ufsr.invstate)
            LOG_FATAL(" - INVSTATE: Invalid state UsageFault");
        if (ufsr.undefinstr)
            LOG_FATAL(" - UNDEFINSTR: Undefined instruction UsageFault");

        abfsr_t abfsr = syslog.registers.abfsr;
        LOG_FATAL("SCB->ABFSR = 0x%0" PRIX32 " - Auxiliary Bus Fault Status register", abfsr.all);
        if (abfsr.itcm)
            LOG_FATAL(" - ITCM: Asynchronous fault on ITCM interface");
        if (abfsr.dtcm)
            LOG_FATAL(" - DTCM: Asynchronous fault on DTCM interface.");
        if (abfsr.ahbp)
            LOG_FATAL(" - AHBP: Asynchronous fault on AHBP interface");
        if (abfsr.eppb)
            LOG_FATAL(" - EPPB: Asynchronous fault on EPPB interface");
    }
} // namespace

extern "C" void crashCatcherExtPrintConsoleHF(uint32_t sp)
{
    static syslog_t syslog     = {};
    syslog.stackFrame          = *(reinterpret_cast<syslog_exception_stack_frame_t *>(sp));
    syslog.registers.hfsr.all  = SCB->HFSR;
    syslog.registers.cfsr.all  = SCB->CFSR;
    syslog.registers.mmfar     = SCB->MMFAR;
    syslog.registers.bfar      = SCB->BFAR;
    syslog.registers.abfsr.all = SCB->ABFSR;
    printHardFaultInfo(syslog);
}

A board/rt1051/crashdump/consoledump.hpp => board/rt1051/crashdump/consoledump.hpp +22 -0
@@ 0,0 1,22 @@
// 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 <cstdint>

// Exception Stack Frame
typedef struct __attribute__((packed))
{
    uint32_t r0;
    uint32_t r1;
    uint32_t r2;
    uint32_t r3;
    uint32_t r12;
    uint32_t lr;
    uint32_t pc;
    uint32_t psr;
#if defined(__ARM_ARCH_7EM__)
    uint32_t s[16];
#endif
} syslog_exception_stack_frame_t;

A board/rt1051/crashdump/crashcatcher_impl.cpp => board/rt1051/crashdump/crashcatcher_impl.cpp +56 -0
@@ 0,0 1,56 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma GCC optimize("Og")

#include <CrashCatcher.h>

#include <log/log.hpp>
#include <module-utils/date/include/date/date.h>
#include "crashdumpwriter.hpp"

const CrashCatcherMemoryRegion *CrashCatcher_GetMemoryRegions(void)
{
    // board/rt1051/ldscripts/memory.ld
    static const CrashCatcherMemoryRegion regions[] = {
        // SRAM_OC
        {0x20200000, 0x20210000, CRASH_CATCHER_BYTE},
        // SRAM_DTC
        {0x20000000, 0x20070000, CRASH_CATCHER_BYTE},
        // intentionally skip text section
        // BOARD_SDRAM_HEAP
        {0x80620000, 0x81000000, CRASH_CATCHER_BYTE},
        // end tag
        {0xFFFFFFFF, 0xFFFFFFFF, CRASH_CATCHER_BYTE},
    };

    return regions;
}

void CrashCatcher_DumpStart(const CrashCatcherInfo *pInfo)
{
    crashdump::CrashDumpWriter::instance().openDump();
}

void CrashCatcher_DumpMemory(const void *pvMemory, CrashCatcherElementSizes elementSize, size_t elementCount)
{
    switch (elementSize) {
    case CRASH_CATCHER_BYTE:
        crashdump::CrashDumpWriter::instance().writeBytes(static_cast<const std::uint8_t *>(pvMemory), elementCount);
        break;
    case CRASH_CATCHER_HALFWORD:
        crashdump::CrashDumpWriter::instance().writeHalfWords(static_cast<const std::uint16_t *>(pvMemory),
                                                              elementCount);
        break;
    case CRASH_CATCHER_WORD:
        crashdump::CrashDumpWriter::instance().writeWords(static_cast<const std::uint32_t *>(pvMemory), elementCount);
        break;
    }
}

CrashCatcherReturnCodes CrashCatcher_DumpEnd(void)
{
    crashdump::CrashDumpWriter::instance().saveDump();
    abort();
    return CRASH_CATCHER_EXIT;
}

A board/rt1051/crashdump/crashdumpwriter.hpp => board/rt1051/crashdump/crashdumpwriter.hpp +25 -0
@@ 0,0 1,25 @@
// 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 <cstdint>

namespace crashdump
{
    class CrashDumpWriter
    {
      public:
        static CrashDumpWriter &instance();

        virtual ~CrashDumpWriter() = default;

        virtual void openDump() = 0;
        virtual void saveDump() = 0;

        virtual void writeBytes(const std::uint8_t *buff, std::size_t size)      = 0;
        virtual void writeHalfWords(const std::uint16_t *buff, std::size_t size) = 0;
        virtual void writeWords(const std::uint32_t *buff, std::size_t size)     = 0;
    };

} // namespace crashdump

A board/rt1051/crashdump/crashdumpwriter_vfs.cpp => board/rt1051/crashdump/crashdumpwriter_vfs.cpp +56 -0
@@ 0,0 1,56 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "crashdumpwriter_vfs.hpp"

#include <log/log.hpp>
#include <fcntl.h>
#include "purefs/vfs_subsystem.hpp"

namespace crashdump
{
    void CrashDumpWriterVFS::openDump()
    {
        std::array<char, 64> crashDumpFileName;
        formatCrashDumpFileName(crashDumpFileName);

        vfs    = purefs::subsystem::vfs_core();
        dumpFd = vfs->open(crashDumpFileName.data(), O_WRONLY | O_CREAT | O_TRUNC, 0666);

        if (dumpFd < 0) {
            LOG_FATAL("Failed to open crash dump file [%s]. Won't be able to save crash info.",
                      crashDumpFileName.data());
        }
    }

    void CrashDumpWriterVFS::saveDump()
    {
        vfs->close(dumpFd);
    }

    void CrashDumpWriterVFS::writeBytes(const uint8_t *buff, std::size_t size)
    {
        vfs->write(dumpFd, reinterpret_cast<const char *>(buff), size);
    }

    void CrashDumpWriterVFS::writeHalfWords(const uint16_t *buff, std::size_t size)
    {
        for (std::size_t n = 0; n < size; ++n) {
            writeBytes(reinterpret_cast<const uint8_t *>(buff + n), sizeof(uint16_t));
        }
    }

    void CrashDumpWriterVFS::writeWords(const uint32_t *buff, std::size_t size)
    {
        for (std::size_t n = 0; n < size; ++n) {
            writeBytes(reinterpret_cast<const uint8_t *>(buff + n), sizeof(uint32_t));
        }
    }

    CrashDumpWriter &CrashDumpWriter::instance()
    {
        static CrashDumpWriterVFS writer;
        return writer;
    }

} // namespace crashdump

A board/rt1051/crashdump/crashdumpwriter_vfs.hpp => board/rt1051/crashdump/crashdumpwriter_vfs.hpp +44 -0
@@ 0,0 1,44 @@
// 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 "crashdumpwriter.hpp"

#include <array>
#include <ctime>
#include <memory>

namespace purefs::fs
{
    class filesystem;
}

namespace crashdump
{
    constexpr inline auto CrashDumpFileNameFormat = "/sys/user/crashdump-%FT%TZ.hex";

    class CrashDumpWriterVFS : public CrashDumpWriter
    {
      public:
        void openDump() override;
        void saveDump() override;

        void writeBytes(const std::uint8_t *buff, std::size_t size) override;
        void writeHalfWords(const std::uint16_t *buff, std::size_t size) override;
        void writeWords(const std::uint32_t *buff, std::size_t size) override;

      private:
        template <std::size_t N> void formatCrashDumpFileName(std::array<char, N> &name)
        {
            std::time_t now;
            std::time(&now);
            std::strftime(name.data(), name.size(), CrashDumpFileNameFormat, gmtime(&now));
        }

        int dumpFd{-1};

        std::shared_ptr<purefs::fs::filesystem> vfs;
    };

} // namespace crashdump

M board/rt1051/ldscripts/memory.ld => board/rt1051/ldscripts/memory.ld +6 -0
@@ 10,6 10,12 @@
 */
MEMORY
{
        /********************************   WARNING   *******************************/
        /*                                                                          */
        /* must be kept in sync with 'board/rt1051/crashdump/crashcatcher_impl.cpp' */
        /*                                                                          */
        /****************************************************************************/

	/* Define each memory region */
	SRAM_OC (rwx) : ORIGIN = 0x20200000, LENGTH = 0x10000 /* 64K bytes (alias RAM) */
	/*SRAM_ITC (rwx) : ORIGIN = 0x0, LENGTH = 0x0*/ /* 0K bytes (alias RAM2) */

A debug_crash_dump.sh => debug_crash_dump.sh +93 -0
@@ 0,0 1,93 @@
#!/bin/bash
# Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
# For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

BUILD_DIR=
CRASH_DUMP=
PURE_ELF=
GDB=${GDB:-arm-none-eabi-gdb}

function perror()
{
    echo "Error:" $@ >&2
}

function print_usage()
{
    echo "debug_crash_dump: This utility uses the CrashDebug stub to load the"
    echo "crash dumps generated by the CrashCatcher fault handler library."
    echo "The dump must be in the CrashCatcher hex dump format. This format is"
    echo "different from the standard core dump file format and this utility"
    echo "won't load standard core files."
    echo
    echo "Usage: [OPTIONS] <builddir> <crashdump>"
    echo
    echo "Options:"
    echo "  -e|--elf   The elf file that generated the crash dump (full path)."
    echo "             '<builddir>/PurePhone.elf' by default."
    echo
    echo "ENV vars:"
    echo "  GDB        The gdb executable used to load the crash dump."
    echo "             'arm-none-eabi-gdb' by default."
}

function parse_args()
{
    local PARAMS=""
    while (( "$#" )); do
        case "$1" in
            -h|--help)
                print_usage
                exit
                ;;
            -e|--elf)
                if [ -n "$2" ] && [ ${2:0:1} != "-" ]; then
                    PURE_ELF="$2"
                    shift 2
                else
                    perror "Argument missing for '$1'."
                    print_usage
                    exit 1
                fi
                ;;
            -*|--*=) # unsupported flags
              perror "Unsupported flag: '$1'."
              exit 1
              ;;
            *) # preserve positional arguments
              PARAMS="$PARAMS $1"
              shift
              ;;
        esac
    done

    eval set -- "$PARAMS"

    if [[ $# != 2 ]]; then
        perror "Bad number of arguments."
        print_usage
        exit 1
    fi

    BUILD_DIR="$1"
    CRASH_DUMP="$2"
    PURE_ELF="${PURE_ELF:-$BUILD_DIR/PurePhone.elf}"
}

function exec_gdb()
{
    local CRASH_DEBUG="$BUILD_DIR/host-tools/crashdebug/CrashDebug"

    exec "$GDB" "$PURE_ELF"                                                             \
        -ex "set target-charset ASCII"                                                  \
        -ex "target remote | \"$CRASH_DEBUG\" --elf \"$PURE_ELF\" --dump \"$CRASH_DUMP\""
}

function main()
{
    parse_args $@
    exec_gdb
}

main $@


M host-tools/CMakeLists.txt => host-tools/CMakeLists.txt +7 -0
@@ 1,6 1,13 @@
if (CMAKE_CROSSCOMPILING)
    # Littlefs fuse is needed in rt1051 and Linux for manipulate images
    # genlittlefs is needed only on the Linux image for generate emulator target image
    set(CRASH_DEBUG_DIR "${CMAKE_SOURCE_DIR}/module-utils/CrashDebug")
    add_custom_target(
        crashdebug ALL
        COMMAND make -C ${CRASH_DEBUG_DIR} CrashDebug
        COMMAND ${CMAKE_COMMAND} -E make_directory crashdebug
        COMMAND ${CMAKE_COMMAND} -E copy ${CRASH_DEBUG_DIR}/bins/lin64/CrashDebug crashdebug
    )
    add_custom_target(
        lfsfuse ALL
        COMMAND ${CMAKE_COMMAND}

M module-bsp/board/rt1051/common/board.cpp => module-bsp/board/rt1051/common/board.cpp +2 -0
@@ 173,6 173,8 @@ namespace bsp
        /* Enable MPU */
        ARM_MPU_Enable(MPU_CTRL_PRIVDEFENA_Msk);

        SCB->SHCSR &= ~(SCB_SHCSR_MEMFAULTENA_Msk | SCB_SHCSR_USGFAULTENA_Msk | SCB_SHCSR_BUSFAULTENA_Msk);

        /* Enable I cache and D cache */
        SCB_EnableDCache();
        SCB_EnableICache();

M module-bsp/board/rt1051/common/startup_mimxrt1052.cpp => module-bsp/board/rt1051/common/startup_mimxrt1052.cpp +3 -346
@@ 1,3 1,6 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

//*****************************************************************************
// MIMXRT1052 startup code for use with MCUXpresso IDE
//


@@ 776,352 779,6 @@ WEAK_AV void SysTick_Handler(void)
    while (1) {}
}

#if defined(__cplusplus)
extern "C"
{
#endif

    // Exception Stack Frame
    typedef struct __attribute__((packed))
    {
        uint32_t r0;
        uint32_t r1;
        uint32_t r2;
        uint32_t r3;
        uint32_t r12;
        uint32_t lr;
        uint32_t pc;
        uint32_t psr;
#if defined(__ARM_ARCH_7EM__)
        uint32_t s[16];
#endif
    } syslog_exception_stack_frame_t;

    /// Hard Fault Fault Status Register
    struct __attribute__((packed)) hfsr_t
    {
        union
        {
            uint32_t all;
            struct
            {
                uint32_t rsrvd0 : 1;
                uint32_t vecttbl : 1;
                uint32_t rsrvd1 : 28;
                uint32_t forced : 1;
                uint32_t debugevt : 1;
            };
        };
    };

    /// MemManage Fault Status Register
    struct __attribute__((packed)) mmfsr_t
    {
        union
        {
            uint8_t all;
            struct
            {
                uint8_t iaccviol : 1;
                uint8_t daccviol : 1;
                uint8_t rsrvd2 : 1;
                uint8_t munstkerr : 1;
                uint8_t mstkerr : 1;
                uint8_t mlsperr : 1;
                uint8_t rsrvd6 : 1;
                uint8_t mmarvalid : 1;
            };
        };
    };

    /// BusFault Status Register
    struct __attribute__((packed)) bfsr_t
    {
        union
        {
            uint8_t all;
            struct
            {
                uint8_t ibuserr : 1;
                uint8_t preciserr : 1;
                uint8_t impreciserr : 1;
                uint8_t unstkerr : 1;
                uint8_t stkerr : 1;
                uint8_t lsperr : 1;
                uint8_t rsrvd6 : 1;
                uint8_t bfarvalid : 1;
            };
        };
    };

    /// UsageFault Status Register
    struct __attribute__((packed)) ufsr_t
    {
        union
        {
            uint16_t all;
            struct
            {
                uint8_t undefinstr : 1;
                uint8_t invstate : 1;
                uint8_t invpc : 1;
                uint8_t nocp : 1;
                uint8_t rsrvd4_7 : 3;
                uint8_t unaligned : 1;
                uint8_t divbyzero : 1;
                uint8_t rsrvd10_15 : 6;
            };
        };
    };

    /// Configurable Fault Status Register
    struct __attribute__((packed)) cfsr_t
    {
        union
        {
            uint32_t all;
            struct
            {
                mmfsr_t mmfsr;
                bfsr_t bfsr;
                ufsr_t ufsr;
            };
        };
    };

    /// Auxiliary Bus Fault Status register
    struct __attribute__((packed)) abfsr_t
    {
        union
        {
            uint32_t all;
            struct
            {
                uint32_t itcm : 1;
                uint32_t dtcm : 1;
                uint32_t ahbp : 1;
                uint32_t axim : 1;
                uint32_t eppb : 1;
                uint32_t rsrvd5_7 : 3;
                uint32_t aximtype : 2;
                uint32_t rsrvd10_31 : 1;
            };
        };
    };

    struct __attribute__((packed)) syslog_t
    {
        syslog_exception_stack_frame_t stackFrame;
        struct
        {
            hfsr_t hfsr;         /// Hard Fault Fault Status Register
            cfsr_t cfsr;         /// Configurable Fault Status Register
            uint32_t mmfar;      /// MemManage Fault Address Register
            uint32_t bfar;       /// BusFault Address Register
            abfsr_t abfsr;       /// Auxiliary Bus Fault Status register
            uint32_t exc_return; /// EXC_RETURN value for the exception being serviced
        } registers;
    };

#define DEBUG_PRINT_HARD_FAULT_INFO    1
#define DEBUG_DETAILED_HARD_FAULT_INFO 1

    static void printHardFaultInfo(const syslog_t &syslog)
    {
#if (DEBUG_PRINT_HARD_FAULT_INFO == 1)
        LOG_FATAL("!!! HardFault Detected !!!");
        LOG_FATAL("* Stack Frame:");
        LOG_FATAL("R0  = 0x%0" PRIX32, syslog.stackFrame.r0);
        LOG_FATAL("R1  = 0x%0" PRIX32, syslog.stackFrame.r1);
        LOG_FATAL("R2  = 0x%0" PRIX32, syslog.stackFrame.r2);
        LOG_FATAL("R3  = 0x%0" PRIX32, syslog.stackFrame.r3);
        LOG_FATAL("R12 = 0x%0" PRIX32, syslog.stackFrame.r12);
        LOG_FATAL("LR  = 0x%0" PRIX32, syslog.stackFrame.lr);
        LOG_FATAL("PC  = 0x%0" PRIX32, syslog.stackFrame.pc);
        LOG_FATAL("PSR = 0x%0" PRIX32, syslog.stackFrame.psr);

        LOG_FATAL("* Fault Status Registers:");
        LOG_FATAL("SCB->HFSR = 0x%0" PRIX32, syslog.registers.hfsr.all);
        LOG_FATAL("SCB->CFSR = 0x%0" PRIX32, syslog.registers.cfsr.all);
        LOG_FATAL("SCB->MMAR = 0x%0" PRIX32, syslog.registers.mmfar);
        LOG_FATAL("SCB->BFAR = 0x%0" PRIX32, syslog.registers.bfar);
        LOG_FATAL("SCB->ABFSR = 0x%0" PRIX32, syslog.registers.abfsr.all);
        LOG_FATAL("EXC_RETURN = 0x%0" PRIX32, syslog.registers.exc_return);

#if (DEBUG_DETAILED_HARD_FAULT_INFO == 1)
        LOG_FATAL("* Details of Fault Status Registers:");
        hfsr_t hfsr = syslog.registers.hfsr;
        LOG_FATAL("SCB->HFSR = 0x%0" PRIX32 " - HardFault Status Register", hfsr.all);
        if (hfsr.debugevt)
            LOG_FATAL(" - DEBUGEVT: Hard fault caused by debug event");
        if (hfsr.forced)
            LOG_FATAL(" - FORCED: Hard fault caused by bus/memory management/usage fault");
        if (hfsr.vecttbl)
            LOG_FATAL(" - VECTBL: BusFault on vector table read");

        cfsr_t cfsr = syslog.registers.cfsr;
        LOG_FATAL("SCB->CFSR = 0x%0" PRIX32 " - Configurable Fault Status Register", cfsr.all);
        mmfsr_t mmfsr = cfsr.mmfsr;
        LOG_FATAL("> SCB->MMFSR = 0x%0" PRIX8 " Memory Management Fault Status Register", mmfsr.all);
        if (mmfsr.mmarvalid)
            LOG_FATAL(" - MMARVALID: MMAR is valid");
        if (mmfsr.mlsperr)
            LOG_FATAL(" - MLSPERR: A MemManage fault occurred during floating-point lazy state preservation");
        if (mmfsr.mstkerr)
            LOG_FATAL(" - MSTKERR: MemManage fault on stacking for exception entry");
        if (mmfsr.munstkerr)
            LOG_FATAL(" - MUNSTKERR: MemManage fault on unstacking for a return from exception:");
        if (mmfsr.daccviol)
            LOG_FATAL(" - DACCVIOL: Data access violation");
        if (mmfsr.iaccviol)
            LOG_FATAL(" - IACCVIOL: Instruction access violation");

        bfsr_t bfsr = cfsr.bfsr;
        LOG_FATAL("> SCB->BFSR = 0x%0" PRIX8 " - Bus Fault Status Register ", bfsr.all);
        if (bfsr.bfarvalid)
            LOG_FATAL(" - BFARVALID: BFAR is valid  ");
        if (bfsr.lsperr)
            LOG_FATAL(" - LSPERR: A bus fault occurred during floating-point lazy state preservation");
        if (bfsr.stkerr)
            LOG_FATAL(" - STKERR: Stacking error");
        if (bfsr.unstkerr)
            LOG_FATAL(" - UNSTKERR: Unstacking error");
        if (bfsr.impreciserr)
            LOG_FATAL(" - IMPREISERR: Imprecise data bus error");
        if (bfsr.preciserr)
            LOG_FATAL(" - PRECISERR: Precise data bus error");
        if (bfsr.ibuserr)
            LOG_FATAL(" - IBUSERR: Instruction bus error");

        ufsr_t ufsr = cfsr.ufsr;
        LOG_FATAL("> SCB->UFSR = 0x%0" PRIX16 " - Usage Fault Status Register", ufsr.all);
        if (ufsr.divbyzero)
            LOG_FATAL(" - DIVBYZERO: Divide by zero UsageFault");
        if (ufsr.unaligned)
            LOG_FATAL(" - UNALIGNED: Unaligned access UsageFault");
        if (ufsr.nocp)
            LOG_FATAL(" - NOCP: Attempt to execute a coprocessor instruction");
        if (ufsr.invpc)
            LOG_FATAL(" - INVPC: Invalid PC load UsageFault");
        if (ufsr.invstate)
            LOG_FATAL(" - INVSTATE: Invalid state UsageFault");
        if (ufsr.undefinstr)
            LOG_FATAL(" - UNDEFINSTR: Undefined instruction UsageFault");

        abfsr_t abfsr = syslog.registers.abfsr;
        LOG_FATAL("SCB->ABFSR = 0x%0" PRIX32 " - Auxiliary Bus Fault Status register", abfsr.all);
        if (abfsr.itcm)
            LOG_FATAL(" - ITCM: Asynchronous fault on ITCM interface");
        if (abfsr.dtcm)
            LOG_FATAL(" - DTCM: Asynchronous fault on DTCM interface.");
        if (abfsr.ahbp)
            LOG_FATAL(" - AHBP: Asynchronous fault on AHBP interface");
        if (abfsr.eppb)
            LOG_FATAL(" - EPPB: Asynchronous fault on EPPB interface");
#endif // (DEBUG_DETAILED_HARD_FAULT_INFO == 1)
#endif //(DEBUG_PRINT_HARD_FAULT_INFO == 1)
    }

    WEAK_AV void HardFault_Handler_C(syslog_exception_stack_frame_t *frame __attribute__((unused)),
                                     uint32_t lr_value __attribute__((unused)))
    {
        static syslog_t syslog     = {};
        syslog.stackFrame          = *frame;
        syslog.registers.hfsr.all  = SCB->HFSR;
        syslog.registers.cfsr.all  = SCB->CFSR;
        syslog.registers.mmfar     = SCB->MMFAR;
        syslog.registers.bfar      = SCB->BFAR;
        syslog.registers.abfsr.all = SCB->ABFSR;

        printHardFaultInfo(syslog);

        abort();
    }

    WEAK_AV void MemManage_Handler_C(syslog_exception_stack_frame_t *frame __attribute__((unused)),
                                     uint32_t lr __attribute__((unused)))
    {
        abort();
    }

#if defined(__cplusplus)
}
#endif

WEAK_AV void MemManage_Handler(void)
{
#if 1
    asm volatile(" tst lr,#4       \n"
                 " ite eq          \n"
                 " mrseq r0,msp    \n"
                 " mrsne r0,psp    \n"
                 " mov r1,lr       \n"
                 " ldr r2,=MemManage_Handler_C \n"
                 " bx r2"

                 : /* Outputs */
                 : /* Inputs */
                 : /* Clobbers */
    );
#endif
}

[[gnu::naked]] WEAK_AV void HardFault_Handler(void)
{
    asm volatile(" tst lr,#4       \n"
                 " ite eq          \n"
                 " mrseq r0,msp    \n"
                 " mrsne r0,psp    \n"
                 " mov r1,lr       \n"
                 " ldr r2,=HardFault_Handler_C \n"
                 " bx r2"

                 : /* Outputs */
                 : /* Inputs */
                 : /* Clobbers */
    );
}

WEAK_AV void BusFault_Handler(void)
{

#if 0
  asm volatile(
      " tst lr,#4       \n"
      " ite eq          \n"
      " mrseq r0,msp    \n"
      " mrsne r0,psp    \n"
      " mov r1,lr       \n"
      " ldr r2,=BusFault_Handler_C \n"
      " bx r2"

      : /* Outputs */
      : /* Inputs */
      : /* Clobbers */
  );
#endif
}

WEAK_AV void UsageFault_Handler(void)
{

#if 0
  asm volatile(
      " tst lr,#4       \n"
      " ite eq          \n"
      " mrseq r0,msp    \n"
      " mrsne r0,psp    \n"
      " mov r1,lr       \n"
      " ldr r2,=UsageFault_Handler_C \n"
      " bx r2"

      : /* Outputs */
      : /* Inputs */
      : /* Clobbers */
  );
#endif
}

//*****************************************************************************
// Processor ends up here if an unexpected interrupt occurs or a specific
// handler is not present in the application code.

A module-utils/CrashDebug => module-utils/CrashDebug +1 -0
@@ 0,0 1,1 @@
Subproject commit 0104eb5480d9213d9fe944f13958f785a311a191

M module-vfs/drivers/src/thirdparty/littlefs/lfs_glue.cpp => module-vfs/drivers/src/thirdparty/littlefs/lfs_glue.cpp +1 -1
@@ 1,4 1,4 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
#include <littlefs/volume_mapper.hpp>
#include <littlefs/lfs.h>

M module-vfs/include/user/purefs/fs/filesystem.hpp => module-vfs/include/user/purefs/fs/filesystem.hpp +1 -1
@@ 1,4 1,4 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once

M tools/gdb_crash_extend.py => tools/gdb_crash_extend.py +1 -1
@@ 1,4 1,4 @@
# Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
# Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
# For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

from __future__ import print_function