mirror of https://github.com/ARMmbed/mbed-os.git
Error and fault handling changes for crash reporting
parent
d643034941
commit
6181394e37
|
@ -80,7 +80,8 @@ Fault_Handler PROC
|
|||
|
||||
Fault_Handler_Continue
|
||||
MOV R12,R3
|
||||
LDR R1,=mbed_fault_context
|
||||
LDR R3,=mbed_fault_context
|
||||
LDR R1,[R3]
|
||||
LDR R2,[R0] ; Capture R0
|
||||
STR R2,[R1]
|
||||
ADDS R1,#4
|
||||
|
|
|
@ -113,7 +113,8 @@ Fault_Handler:
|
|||
|
||||
Fault_Handler_Continue:
|
||||
MOV R12,R3
|
||||
LDR R1,=mbed_fault_context
|
||||
LDR R3,=mbed_fault_context
|
||||
LDR R1,[R3]
|
||||
LDR R2,[R0] // Capture R0
|
||||
STR R2,[R1]
|
||||
ADDS R1,#4
|
||||
|
|
|
@ -75,7 +75,8 @@ Fault_Handler
|
|||
|
||||
Fault_Handler_Continue
|
||||
MOV R12,R3
|
||||
LDR R1,=mbed_fault_context
|
||||
LDR R3,=mbed_fault_context
|
||||
LDR R1,[R3]
|
||||
LDR R2,[R0] ; Capture R0
|
||||
STR R2,[R1]
|
||||
ADDS R1,#4
|
||||
|
|
|
@ -20,8 +20,9 @@
|
|||
#include <inttypes.h>
|
||||
|
||||
#include "device.h"
|
||||
#include "platform/mbed_error.h"
|
||||
#include "platform/mbed_interface.h"
|
||||
#include "mbed_error.h"
|
||||
#include "mbed_interface.h"
|
||||
#include "mbed_crash_data_offsets.h"
|
||||
|
||||
#ifndef MBED_FAULT_HANDLER_DISABLED
|
||||
#include "mbed_fault_handler.h"
|
||||
|
@ -29,8 +30,13 @@
|
|||
//Functions Prototypes
|
||||
void print_context_info(void);
|
||||
|
||||
//Global for populating the context in exception handler
|
||||
mbed_fault_context_t mbed_fault_context;
|
||||
#if MBED_CONF_PLATFORM_CRASH_CAPTURE_ENABLED
|
||||
//Global for populating the context in exception handler
|
||||
mbed_fault_context_t *mbed_fault_context=(mbed_fault_context_t *)((uint32_t)FAULT_CONTEXT_LOCATION);
|
||||
#else
|
||||
mbed_fault_context_t fault_context;
|
||||
mbed_fault_context_t *mbed_fault_context=(mbed_fault_context_t *)&fault_context;
|
||||
#endif
|
||||
|
||||
//This is a handler function called from Fault handler to print the error information out.
|
||||
//This runs in fault context and uses special functions(defined in mbed_rtx_fault_handler.c) to print the information without using C-lib support.
|
||||
|
@ -69,7 +75,7 @@ void mbed_fault_handler (uint32_t fault_type, void *mbed_fault_context_in)
|
|||
mbed_error_printf("\n\n-- MbedOS Fault Handler --\n\n");
|
||||
|
||||
//Now call mbed_error, to log the error and halt the system
|
||||
mbed_error( faultStatus, "Fault exception", mbed_fault_context.PC_reg, NULL, 0 );
|
||||
mbed_error( faultStatus, "Fault exception", mbed_fault_context->PC_reg, NULL, 0 );
|
||||
|
||||
}
|
||||
|
||||
|
@ -77,7 +83,7 @@ MBED_NOINLINE void print_context_info(void)
|
|||
{
|
||||
//Context Regs
|
||||
for(int i=0;i<13;i++) {
|
||||
mbed_error_printf("\nR%-4d: %08" PRIX32, i, ((uint32_t *)&mbed_fault_context)[i]);
|
||||
mbed_error_printf("\nR%-4d: %08" PRIX32, i, ((uint32_t *)(mbed_fault_context))[i]);
|
||||
}
|
||||
|
||||
mbed_error_printf("\nSP : %08" PRIX32
|
||||
|
@ -85,8 +91,8 @@ MBED_NOINLINE void print_context_info(void)
|
|||
"\nPC : %08" PRIX32
|
||||
"\nxPSR : %08" PRIX32
|
||||
"\nPSP : %08" PRIX32
|
||||
"\nMSP : %08" PRIX32, mbed_fault_context.SP_reg, mbed_fault_context.LR_reg, mbed_fault_context.PC_reg,
|
||||
mbed_fault_context.xPSR, mbed_fault_context.PSP, mbed_fault_context.MSP );
|
||||
"\nMSP : %08" PRIX32, mbed_fault_context->SP_reg, mbed_fault_context->LR_reg, mbed_fault_context->PC_reg,
|
||||
mbed_fault_context->xPSR, mbed_fault_context->PSP, mbed_fault_context->MSP );
|
||||
|
||||
//Capture CPUID to get core/cpu info
|
||||
mbed_error_printf("\nCPUID: %08" PRIX32, SCB->CPUID);
|
||||
|
@ -112,12 +118,12 @@ MBED_NOINLINE void print_context_info(void)
|
|||
#endif
|
||||
|
||||
//Print Mode
|
||||
if (mbed_fault_context.EXC_RETURN & 0x8) {
|
||||
if (mbed_fault_context->EXC_RETURN & 0x8) {
|
||||
mbed_error_printf("\nMode : Thread");
|
||||
//Print Priv level in Thread mode - We capture CONTROL reg which reflects the privilege.
|
||||
//Note that the CONTROL register captured still reflects the privilege status of the
|
||||
//thread mode eventhough we are in Handler mode by the time we capture it.
|
||||
if(mbed_fault_context.CONTROL & 0x1) {
|
||||
if(mbed_fault_context->CONTROL & 0x1) {
|
||||
mbed_error_printf("\nPriv : User");
|
||||
} else {
|
||||
mbed_error_printf("\nPriv : Privileged");
|
||||
|
@ -127,11 +133,23 @@ MBED_NOINLINE void print_context_info(void)
|
|||
mbed_error_printf("\nPriv : Privileged");
|
||||
}
|
||||
//Print Return Stack
|
||||
if (mbed_fault_context.EXC_RETURN & 0x4) {
|
||||
if (mbed_fault_context->EXC_RETURN & 0x4) {
|
||||
mbed_error_printf("\nStack: PSP");
|
||||
} else {
|
||||
mbed_error_printf("\nStack: MSP");
|
||||
}
|
||||
}
|
||||
|
||||
mbed_error_status_t mbed_get_reboot_fault_context (mbed_fault_context_t *fault_context)
|
||||
{
|
||||
mbed_error_status_t status = MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_ITEM_NOT_FOUND);
|
||||
#if MBED_CONF_PLATFORM_CRASH_CAPTURE_ENABLED
|
||||
if(fault_context == NULL)
|
||||
return MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_INVALID_ARGUMENT);
|
||||
memcpy(fault_context, mbed_fault_context, sizeof(mbed_fault_context_t));
|
||||
status = MBED_SUCCESS;
|
||||
#endif
|
||||
return status;
|
||||
}
|
||||
|
||||
#endif //MBED_FAULT_HANDLER_SUPPORT
|
||||
|
|
|
@ -15,7 +15,11 @@
|
|||
*/
|
||||
|
||||
#ifndef MBED_FAULT_HANDLER_H
|
||||
#define MBED_FAULT_HANDLER_H
|
||||
#define MBED_FAULT_HANDLER_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
//Fault context struct
|
||||
//WARNING: DO NOT CHANGE THIS STRUCT WITHOUT MAKING CORRESPONDING CHANGES in except.S files.
|
||||
|
@ -55,4 +59,18 @@ typedef struct {
|
|||
//This runs in fault context and uses special functions(defined in mbed_fault_handler.c) to print the information without using C-lib support.
|
||||
void mbed_fault_handler (uint32_t fault_type, void *mbed_fault_context_in);
|
||||
|
||||
/**
|
||||
* Call this function to retrieve the fault context after a fatal exception which triggered a system reboot. The function retrieves the fault context stored in crash-report ram area which is preserved over reboot.
|
||||
* @param fault_context Pointer to mbed_fault_context_t struct allocated by the caller. This is the mbed_fault_context_t info captured as part of the fatal exception which triggered the reboot.
|
||||
* @return 0 or MBED_SUCCESS on success.
|
||||
* MBED_ERROR_INVALID_ARGUMENT in case of invalid error_info pointer
|
||||
* MBED_ERROR_ITEM_NOT_FOUND if no reboot context is currently captured by teh system
|
||||
*
|
||||
*/
|
||||
mbed_error_status_t mbed_get_reboot_fault_context (mbed_fault_context_t *fault_context);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
/* mbed Microcontroller Library
|
||||
* Copyright (c) 2006-2013 ARM Limited
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
#ifndef MBED_CRASH_DATA_INFO_H
|
||||
#define MBED_CRASH_DATA_INFO_H
|
||||
|
||||
#include "platform/mbed_retarget.h"
|
||||
#include "platform/mbed_toolchain.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if MBED_CONF_PLATFORM_CRASH_CAPTURE_ENABLED
|
||||
#if defined(__CC_ARM) || (defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050))
|
||||
extern uint32_t Image$$RW_m_crash_data$$ZI$$Base[];
|
||||
extern uint32_t Image$$RW_m_crash_data$$ZI$$Size;
|
||||
#define __CRASH_DATA_RAM_START__ Image$$RW_m_crash_data$$ZI$$Base
|
||||
#define __CRASH_DATA_RAM_SIZE__ Image$$RW_m_crash_data$$ZI$$Size
|
||||
#elif defined(__ICCARM__)
|
||||
extern uint32_t __CRASH_DATA_RAM_START__[];
|
||||
extern uint32_t __CRASH_DATA_RAM_END__[];
|
||||
#define __CRASH_DATA_RAM_SIZE__ (__CRASH_DATA_RAM_END__ - __CRASH_DATA_RAM_START__)
|
||||
#elif defined(__GNUC__)
|
||||
extern uint32_t __CRASH_DATA_RAM_START__[];
|
||||
extern uint32_t __CRASH_DATA_RAM_END__[];
|
||||
#define __CRASH_DATA_RAM_SIZE__ (__CRASH_DATA_RAM_END__ - __CRASH_DATA_RAM_START__)
|
||||
#endif /* defined(__CC_ARM) */
|
||||
|
||||
/* Offset definitions for context capture */
|
||||
#define FAULT_CONTEXT_OFFSET (0x0)
|
||||
#define FAULT_CONTEXT_SIZE (0x80 / 4) //32 words(128 bytes) for Fault Context
|
||||
#define ERROR_CONTEXT_OFFSET (FAULT_CONTEXT_OFFSET + FAULT_CONTEXT_SIZE)
|
||||
#define ERROR_CONTEXT_SIZE (0x80 / 4) //32 words(128 bytes) bytes for Error Context
|
||||
#define FAULT_CONTEXT_LOCATION (__CRASH_DATA_RAM_START__ + FAULT_CONTEXT_OFFSET)
|
||||
#define ERROR_CONTEXT_LOCATION (__CRASH_DATA_RAM_START__ + ERROR_CONTEXT_OFFSET)
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
|
@ -17,10 +17,13 @@
|
|||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include "device.h"
|
||||
#include "platform/mbed_crash_data_offsets.h"
|
||||
#include "platform/mbed_retarget.h"
|
||||
#include "platform/mbed_critical.h"
|
||||
#include "platform/mbed_error.h"
|
||||
#include "platform/mbed_error_hist.h"
|
||||
#include "platform/mbed_interface.h"
|
||||
#include "platform/mbed_power_mgmt.h"
|
||||
#ifdef MBED_CONF_RTOS_PRESENT
|
||||
#include "rtx_os.h"
|
||||
#endif
|
||||
|
@ -34,8 +37,8 @@
|
|||
#include <inttypes.h>
|
||||
|
||||
#ifndef NDEBUG
|
||||
#define ERROR_REPORT(ctx, error_msg, error_filename, error_line) print_error_report(ctx, error_msg, error_filename, error_line)
|
||||
static void print_error_report(const mbed_error_ctx *ctx, const char *, const char *error_filename, int error_line);
|
||||
#define ERROR_REPORT(ctx, error_msg, error_filename, error_line, print_thread_info) print_error_report(ctx, error_msg, error_filename, error_line, print_thread_info)
|
||||
static void print_error_report(const mbed_error_ctx *ctx, const char *, const char *error_filename, int error_line, bool print_thread_info);
|
||||
#else
|
||||
#define ERROR_REPORT(ctx, error_msg, error_filename, error_line) ((void) 0)
|
||||
#endif
|
||||
|
@ -44,10 +47,46 @@ static core_util_atomic_flag error_in_progress = CORE_UTIL_ATOMIC_FLAG_INIT;
|
|||
static core_util_atomic_flag halt_in_progress = CORE_UTIL_ATOMIC_FLAG_INIT;
|
||||
static int error_count = 0;
|
||||
static mbed_error_ctx first_error_ctx = {0};
|
||||
|
||||
#if MBED_CONF_PLATFORM_CRASH_CAPTURE_ENABLED
|
||||
//Global for populating the context in exception handler
|
||||
static mbed_error_ctx *report_error_ctx=(mbed_error_ctx *)((uint32_t)ERROR_CONTEXT_LOCATION);
|
||||
static bool is_reboot_error_valid = false;
|
||||
#endif
|
||||
|
||||
static mbed_error_ctx last_error_ctx = {0};
|
||||
static mbed_error_hook_t error_hook = NULL;
|
||||
static mbed_error_status_t handle_error(mbed_error_status_t error_status, unsigned int error_value, const char *filename, int line_number, void *caller);
|
||||
|
||||
//Helper function to calculate CRC
|
||||
//NOTE: It would have been better to use MbedCRC implementation. But
|
||||
//MbedCRC uses table based calculation and we dont want to keep that table memory
|
||||
//used up for this purpose. Also we cannot force bitwise calculation in MbedCRC
|
||||
//and it also requires a new wrapper to be called from C implementation. Since
|
||||
//we dont have many uses cases to create a C wrapper for MbedCRC and the data
|
||||
//we calculate CRC on in this context is very less we will use a local
|
||||
//implementation here.
|
||||
static unsigned int compute_crc32(unsigned char *data, int datalen)
|
||||
{
|
||||
const unsigned int polynomial = 0x04C11DB7; /* divisor is 32bit */
|
||||
unsigned int crc = 0; /* CRC value is 32bit */
|
||||
|
||||
for( ;datalen>=0; datalen-- ) {
|
||||
unsigned char b = *data;
|
||||
crc ^= (unsigned int )(b << 24); /* move byte into upper 8bit */
|
||||
for (int i = 0; i < 8; i++) {
|
||||
/* is MSB 1 */
|
||||
if ((crc & 0x80000000) != 0) {
|
||||
crc = (unsigned int)((crc << 1) ^ polynomial);
|
||||
} else {
|
||||
crc <<= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return crc;
|
||||
}
|
||||
|
||||
//Helper function to halt the system
|
||||
static MBED_NORETURN void mbed_halt_system(void)
|
||||
{
|
||||
|
@ -75,7 +114,7 @@ WEAK MBED_NORETURN void error(const char *format, ...)
|
|||
// Prevent recursion if error is called again during store+print attempt
|
||||
if (!core_util_atomic_flag_test_and_set(&error_in_progress)) {
|
||||
handle_error(MBED_ERROR_UNKNOWN, 0, NULL, 0, MBED_CALLER_ADDR());
|
||||
ERROR_REPORT(&last_error_ctx, "Fatal Run-time error", NULL, 0);
|
||||
ERROR_REPORT(&last_error_ctx, "Fatal Run-time error", NULL, 0, true);
|
||||
|
||||
#ifndef NDEBUG
|
||||
va_list arg;
|
||||
|
@ -152,6 +191,44 @@ static mbed_error_status_t handle_error(mbed_error_status_t error_status, unsign
|
|||
return MBED_SUCCESS;
|
||||
}
|
||||
|
||||
WEAK void mbed_error_reboot_callback(mbed_error_ctx *error_context) {
|
||||
//Dont do anything here, let application override this if required.
|
||||
}
|
||||
|
||||
//Initialize Error handling system and report any errors detected on rebooted
|
||||
mbed_error_status_t mbed_error_initialize(void)
|
||||
{
|
||||
#if MBED_CONF_PLATFORM_CRASH_CAPTURE_ENABLED
|
||||
uint32_t crc_val = 0;
|
||||
crc_val = compute_crc32( (unsigned char *)report_error_ctx, ((uint32_t)&(report_error_ctx->crc_error_ctx) - (uint32_t)report_error_ctx) );
|
||||
//Read report_error_ctx and check if CRC is correct for report_error_ctx
|
||||
if((report_error_ctx->crc_error_ctx == crc_val) && (report_error_ctx->is_error_processed == 0)) {
|
||||
is_reboot_error_valid = true;
|
||||
#if MBED_CONF_PLATFORM_REBOOT_CRASH_REPORT_ENABLED && !defined(NDEBUG)
|
||||
//Report the error info
|
||||
mbed_error_printf("\n== Your last reboot was triggered by an error, below is the error information ==");
|
||||
ERROR_REPORT( report_error_ctx, "System rebooted due to fatal error", MBED_FILENAME, __LINE__, false );
|
||||
#endif
|
||||
//Call the mbed_error_reboot_callback, this enables applications to do some handling before we do the handling
|
||||
mbed_error_reboot_callback(report_error_ctx);
|
||||
|
||||
//Enforce max-reboot only if auto reboot is enabled
|
||||
#if MBED_CONF_PLATFORM_FATAL_ERROR_AUTO_REBOOT_ENABLED
|
||||
if( report_error_ctx->error_reboot_count > MBED_CONF_PLATFORM_ERROR_REBOOT_MAX ) {
|
||||
//We have rebooted more than enough, hold the system here.
|
||||
mbed_error_printf("\n== Reboot count(=%ld) exceeded maximum, system halting ==\n", report_error_ctx->error_reboot_count);
|
||||
mbed_halt_system();
|
||||
}
|
||||
#endif
|
||||
report_error_ctx->is_error_processed = 1;//Set the flag that we already processed this error
|
||||
crc_val = compute_crc32( (unsigned char *)report_error_ctx, ((uint32_t)&(report_error_ctx->crc_error_ctx) - (uint32_t)report_error_ctx) );
|
||||
report_error_ctx->crc_error_ctx = crc_val;
|
||||
}
|
||||
#endif
|
||||
|
||||
return MBED_SUCCESS;
|
||||
}
|
||||
|
||||
//Return the first error
|
||||
mbed_error_status_t mbed_get_first_error(void)
|
||||
{
|
||||
|
@ -188,17 +265,40 @@ WEAK MBED_NORETURN mbed_error_status_t mbed_error(mbed_error_status_t error_stat
|
|||
(void) handle_error(error_status, error_value, filename, line_number, MBED_CALLER_ADDR());
|
||||
|
||||
//On fatal errors print the error context/report
|
||||
ERROR_REPORT(&last_error_ctx, error_msg, filename, line_number);
|
||||
ERROR_REPORT(&last_error_ctx, error_msg, filename, line_number, true);
|
||||
}
|
||||
|
||||
#if MBED_CONF_PLATFORM_CRASH_CAPTURE_ENABLED
|
||||
uint32_t crc_val = 0;
|
||||
crc_val = compute_crc32( (unsigned char *)report_error_ctx, ((uint32_t)&(report_error_ctx->crc_error_ctx) - (uint32_t)report_error_ctx) );
|
||||
//Read report_error_ctx and check if CRC is correct for report_error_ctx
|
||||
if(report_error_ctx->crc_error_ctx == crc_val) {
|
||||
uint32_t current_reboot_count = report_error_ctx->error_reboot_count;
|
||||
last_error_ctx.error_reboot_count = current_reboot_count + 1;
|
||||
} else {
|
||||
last_error_ctx.error_reboot_count = 1;
|
||||
}
|
||||
last_error_ctx.is_error_processed = 0;//Set the flag that this is a new error
|
||||
//Update the struct with crc
|
||||
last_error_ctx.crc_error_ctx = compute_crc32( (unsigned char *)&last_error_ctx, ((uint32_t)&(last_error_ctx.crc_error_ctx) - (uint32_t)&last_error_ctx) );
|
||||
memcpy(report_error_ctx, &last_error_ctx, sizeof(mbed_error_ctx));
|
||||
//We need not call delete_mbed_crc(crc_obj) here as we are going to reset the system anyway, and calling delete while handling a fatal error may cause nested exception
|
||||
#if MBED_CONF_PLATFORM_FATAL_ERROR_AUTO_REBOOT_ENABLED
|
||||
system_reset();//do a system reset to get the system rebooted
|
||||
while(1);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
mbed_halt_system();
|
||||
|
||||
return MBED_ERROR_FAILED_OPERATION;
|
||||
}
|
||||
|
||||
//Register an application defined callback with error handling
|
||||
mbed_error_status_t mbed_set_error_hook(mbed_error_hook_t error_hook_in)
|
||||
{
|
||||
//register the new hook/callback
|
||||
if (error_hook_in != NULL) {
|
||||
if (error_hook_in != NULL) {
|
||||
error_hook = error_hook_in;
|
||||
return MBED_SUCCESS;
|
||||
}
|
||||
|
@ -206,6 +306,48 @@ mbed_error_status_t mbed_set_error_hook(mbed_error_hook_t error_hook_in)
|
|||
return MBED_ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
//Reset the reboot error context
|
||||
mbed_error_status_t mbed_reset_reboot_error_info()
|
||||
{
|
||||
#if MBED_CONF_PLATFORM_CRASH_CAPTURE_ENABLED
|
||||
memset(report_error_ctx, 0, sizeof(mbed_error_ctx) );
|
||||
#endif
|
||||
return MBED_SUCCESS;
|
||||
}
|
||||
|
||||
//Reset the reboot error context
|
||||
mbed_error_status_t mbed_reset_reboot_count()
|
||||
{
|
||||
#if MBED_CONF_PLATFORM_CRASH_CAPTURE_ENABLED
|
||||
if(is_reboot_error_valid) {
|
||||
uint32_t crc_val = 0;
|
||||
report_error_ctx->error_reboot_count = 0;//Set reboot count to 0
|
||||
//Update CRC
|
||||
crc_val = compute_crc32( (unsigned char *)report_error_ctx, ((uint32_t)&(report_error_ctx->crc_error_ctx) - (uint32_t)report_error_ctx) );
|
||||
report_error_ctx->crc_error_ctx = crc_val;
|
||||
return MBED_SUCCESS;
|
||||
}
|
||||
#endif
|
||||
return MBED_ERROR_ITEM_NOT_FOUND;
|
||||
}
|
||||
|
||||
//Retrieve the reboot error context
|
||||
mbed_error_status_t mbed_get_reboot_error_info(mbed_error_ctx *error_info)
|
||||
{
|
||||
mbed_error_status_t status = MBED_ERROR_ITEM_NOT_FOUND;
|
||||
#if MBED_CONF_PLATFORM_CRASH_CAPTURE_ENABLED
|
||||
if (is_reboot_error_valid) {
|
||||
if(error_info != NULL) {
|
||||
memcpy(error_info, report_error_ctx, sizeof(mbed_error_ctx));
|
||||
status = MBED_SUCCESS;
|
||||
} else {
|
||||
status = MBED_ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return status;
|
||||
}
|
||||
|
||||
//Retrieve the first error context from error log
|
||||
mbed_error_status_t mbed_get_first_error_info(mbed_error_ctx *error_info)
|
||||
{
|
||||
|
@ -296,7 +438,7 @@ static void print_threads_info(const osRtxThread_t *threads)
|
|||
#endif
|
||||
|
||||
#ifndef NDEBUG
|
||||
static void print_error_report(const mbed_error_ctx *ctx, const char *error_msg, const char *error_filename, int error_line)
|
||||
static void print_error_report(const mbed_error_ctx *ctx, const char *error_msg, const char *error_filename, int error_line, bool print_thread_info)
|
||||
{
|
||||
int error_code = MBED_GET_ERROR_CODE(ctx->error_status);
|
||||
int error_module = MBED_GET_ERROR_MODULE(ctx->error_status);
|
||||
|
@ -369,17 +511,19 @@ static void print_error_report(const mbed_error_ctx *ctx, const char *error_msg,
|
|||
#endif
|
||||
|
||||
#if MBED_CONF_PLATFORM_ERROR_ALL_THREADS_INFO && defined(MBED_CONF_RTOS_PRESENT)
|
||||
mbed_error_printf("\nNext:");
|
||||
print_thread(osRtxInfo.thread.run.next);
|
||||
if(print_thread_info == true) {
|
||||
mbed_error_printf("\nNext:");
|
||||
print_thread(osRtxInfo.thread.run.next);
|
||||
|
||||
mbed_error_printf("\nReady:");
|
||||
print_threads_info(osRtxInfo.thread.ready.thread_list);
|
||||
mbed_error_printf("\nReady:");
|
||||
print_threads_info(osRtxInfo.thread.ready.thread_list);
|
||||
|
||||
mbed_error_printf("\nWait:");
|
||||
print_threads_info(osRtxInfo.thread.wait_list);
|
||||
mbed_error_printf("\nWait:");
|
||||
print_threads_info(osRtxInfo.thread.wait_list);
|
||||
|
||||
mbed_error_printf("\nDelay:");
|
||||
print_threads_info(osRtxInfo.thread.delay_list);
|
||||
mbed_error_printf("\nDelay:");
|
||||
print_threads_info(osRtxInfo.thread.delay_list);
|
||||
}
|
||||
#endif
|
||||
mbed_error_printf(MBED_CONF_PLATFORM_ERROR_DECODE_HTTP_URL_STR, ctx->error_status);
|
||||
mbed_error_printf("\n-- MbedOS Error Info --\n");
|
||||
|
|
|
@ -827,6 +827,11 @@ typedef struct _mbed_error_ctx {
|
|||
char error_filename[MBED_CONF_PLATFORM_MAX_ERROR_FILENAME_LEN];
|
||||
uint32_t error_line_number;
|
||||
#endif
|
||||
#if MBED_CONF_PLATFORM_CRASH_CAPTURE_ENABLED
|
||||
int32_t error_reboot_count;//everytime we write this struct we increment this value by 1, irrespective of time between reboots. Note that the data itself might change, but everytime we reboot due to error we update this count by 1
|
||||
int32_t is_error_processed;//once this error is processed set this value to 1
|
||||
uint32_t crc_error_ctx;//crc_error_ctx should always be the last member in this struct
|
||||
#endif
|
||||
} mbed_error_ctx;
|
||||
|
||||
/** To generate a fatal compile-time error, you can use the pre-processor #error directive.
|
||||
|
@ -928,6 +933,58 @@ MBED_NORETURN void error(const char *format, ...) MBED_PRINTF(1, 2);
|
|||
*/
|
||||
typedef void (*mbed_error_hook_t)(const mbed_error_ctx *error_ctx);
|
||||
|
||||
|
||||
/**
|
||||
* Callback function for reporting error context during boot up. When MbedOS error handling system detects a fatal error
|
||||
* it will auto-reboot the system(if MBED_CONF_PLATFORM_FATAL_ERROR_AUTO_REBOOT_ENABLED is enabled) after capturing the
|
||||
* error info in special crash data RAM region. Once rebooted, MbedOS initialization routines will call this function with a pointer to
|
||||
* the captured mbed_error_ctx structure. If application implementation needs to receive this callback, mbed_error_reboot_callback
|
||||
* function should be overriden with custom implementation. By default it's defined as a WEAK function in mbed_error.c.
|
||||
* Note that this callback will be invoked before the system starts executing main() function. So the implementation of
|
||||
* the callback should be aware any resource limitations/availability of resources which are yet to be initialized by application main().
|
||||
*
|
||||
* @param error_ctx Error context structure associated with this error.
|
||||
* @return void
|
||||
*
|
||||
*/
|
||||
void mbed_error_reboot_callback(mbed_error_ctx *error_context);
|
||||
|
||||
/**
|
||||
* Initialize error handling system, this is called by the mbed-os boot sequence. This is not required to be called by Application unless the boot sequence is overridden by the system implementation.
|
||||
* NOTE: This function also prints the error report to serial terminal if MBED_CONF_PLATFORM_REBOOT_CRASH_REPORT_ENABLED is enabled.
|
||||
* If MBED_CONF_PLATFORM_FATAL_ERROR_AUTO_REBOOT_ENABLED is enabled and if the current reboot count exceeds MBED_CONF_PLATFORM_ERROR_REBOOT_MAX the system will halt when this function is called,
|
||||
* and in such cases the caller will not get the control back. Also note that calling this function may trigger mbed_error_reboot_callback() if application side overides mbed_error_reboot_callback().
|
||||
* @return MBED_SUCCESS on success.
|
||||
*
|
||||
*/
|
||||
|
||||
mbed_error_status_t mbed_error_initialize(void);
|
||||
|
||||
/**
|
||||
* Call this function to retrieve the error context after a fatal error which triggered a system reboot. The function retrieves the error context stored in crash-report ram area which is preserved over reboot.
|
||||
* @param error_info Pointer to mbed_error_ctx struct allocated by the caller. This is the mbed_error_ctx info captured as part of the fatal error which triggered the reboot.
|
||||
* @return 0 or MBED_SUCCESS on success.
|
||||
* MBED_ERROR_INVALID_ARGUMENT in case of invalid error_info pointer
|
||||
* MBED_ERROR_ITEM_NOT_FOUND if no reboot context is currently captured by the system
|
||||
*
|
||||
*/
|
||||
mbed_error_status_t mbed_get_reboot_error_info(mbed_error_ctx *error_info);
|
||||
|
||||
/**
|
||||
* Calling this function resets the current reboot context captured by the system(stored in special crash data RAM region).
|
||||
* @return MBED_SUCCESS on success.
|
||||
* MBED_ERROR_ITEM_NOT_FOUND if no reboot context is currently captured by the system
|
||||
*/
|
||||
mbed_error_status_t mbed_reset_reboot_error_info(void);
|
||||
|
||||
/**
|
||||
* Calling this function resets the current reboot count stored as part of error context captured in special crash data RAM region.
|
||||
* The function will also update the CRC value stored as part of error context accordingly.
|
||||
* @return MBED_SUCCESS on success.
|
||||
* MBED_ERROR_ITEM_NOT_FOUND if no reboot context is currently captured by the system
|
||||
*/
|
||||
mbed_error_status_t mbed_reset_reboot_count(void);
|
||||
|
||||
/**
|
||||
* Call this function to set a system error/warning. This function will log the error status with the context info and return to caller.
|
||||
*
|
||||
|
|
|
@ -109,6 +109,22 @@
|
|||
"cthunk_count_max": {
|
||||
"help": "The maximum CThunk objects used at the same time. This must be greater than 0 and less 256",
|
||||
"value": 8
|
||||
},
|
||||
"crash-capture-enabled": {
|
||||
"help": "Enables crash context capture when the system enters a fatal error/crash.",
|
||||
"value": false
|
||||
},
|
||||
"reboot-crash-report-enabled": {
|
||||
"help": "Enables crash context capture when the system enters a fatal error/crash.",
|
||||
"value": false
|
||||
},
|
||||
"error-reboot-max": {
|
||||
"help": "Maximum number of auto reboots permitted when an error happens.",
|
||||
"value": 0
|
||||
},
|
||||
"fatal-error-auto-reboot-enabled": {
|
||||
"help": "Setting this to true enables auto-reboot on a fatal error.",
|
||||
"value": false
|
||||
}
|
||||
},
|
||||
"target_overrides": {
|
||||
|
|
|
@ -75,6 +75,7 @@
|
|||
#include "cmsis.h"
|
||||
#include "mbed_toolchain.h"
|
||||
#include "mbed_boot.h"
|
||||
#include "mbed_error.h"
|
||||
|
||||
int main(void);
|
||||
static void mbed_cpy_nvic(void);
|
||||
|
@ -94,6 +95,7 @@ void mbed_start(void)
|
|||
{
|
||||
mbed_toolchain_init();
|
||||
mbed_main();
|
||||
mbed_error_initialize();
|
||||
main();
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue