<commit_before>/* mbed Microcontroller Library
 * Copyright (c) 2006-2019 ARM Limited
 * SPDX-License-Identifier: Apache-2.0
 *
 * 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 <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include "device.h"
#include "platform/source/mbed_crash_data_offsets.h"
#include "platform/mbed_atomic.h"
#include "platform/mbed_critical.h"
#include "platform/mbed_error.h"
#include "platform/source/mbed_error_hist.h"
#include "platform/mbed_interface.h"
#include "platform/mbed_power_mgmt.h"
#include "platform/mbed_stats.h"
#if defined(__CORTEX_M)
#include "platform/source/TARGET_CORTEX_M/mbed_fault_handler.h"
#endif
#ifdef MBED_CONF_RTOS_PRESENT
#include "rtx_os.h"
#endif

#if DEVICE_STDIO_MESSAGES
#include <stdio.h>
#endif
#ifndef __STDC_FORMAT_MACROS
#define __STDC_FORMAT_MACROS
#endif
#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);
#else
#define ERROR_REPORT(ctx, error_msg, error_filename, error_line) ((void) 0)
#endif

static bool error_in_progress;
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};

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);

#if MBED_CONF_PLATFORM_CRASH_CAPTURE_ENABLED
//Global for populating the context in exception handler
static mbed_error_ctx *const report_error_ctx = (mbed_error_ctx *)(ERROR_CONTEXT_LOCATION);
static bool is_reboot_error_valid = false;

//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(const void *data, int datalen)
{
    const unsigned int polynomial = 0x04C11DB7; /* divisor is 32bit */
    unsigned int crc = 0; /* CRC value is 32bit */
    unsigned char *buf = (unsigned char *)data;//use a temp variable to make code readable and to avoid typecasting issues.

    for (; datalen > 0; datalen--) {
        unsigned char b = *buf++;
        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;
}
#endif

//Helper function to halt the system
static MBED_NORETURN void mbed_halt_system(void)
{
    // Prevent recursion if halt is called again during halt attempt - try
    // something simple instead.
    if (core_util_atomic_flag_test_and_set(&halt_in_progress)) {
        core_util_critical_section_enter();
        __DSB();
        for (;;) {
            __WFE(); // Not WFI, as don't want to wake for pending interrupts
        }
    }

    //If in ISR context, call mbed_die directly
    if (core_util_is_isr_active() || !core_util_are_interrupts_enabled()) {
        mbed_die();
    }

    // In normal context, try orderly exit(1), which eventually calls mbed_die
    exit(1);
}

WEAK MBED_NORETURN void error(const char *format, ...)
{
    // Prevent recursion if error is called again during store+print attempt
    if (!core_util_atomic_exchange_bool(&error_in_progress, true)) {
        handle_error(MBED_ERROR_UNKNOWN, 0, NULL, 0, MBED_CALLER_ADDR());
        ERROR_REPORT(&last_error_ctx, "Fatal Run-time error", NULL, 0);

#ifndef NDEBUG
        va_list arg;
        va_start(arg, format);
        mbed_error_vprintf(format, arg);
        va_end(arg);
        // Add a newline to prevent any line buffering
        mbed_error_puts("\n");
#endif
    }

    mbed_halt_system();
}

//Set an error status with the error handling system
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)
{
    mbed_error_ctx current_error_ctx;

    //Error status should always be < 0
    if (error_status >= 0) {
        //This is a weird situation, someone called mbed_error with an invalid error code.
        //We will still handle the situation but change the error code to ERROR_INVALID_ARGUMENT, at least the context will have info on who called it
        error_status = MBED_ERROR_INVALID_ARGUMENT;
    }

    //Clear the context capturing buffer
    memset(&current_error_ctx, 0, sizeof(mbed_error_ctx));

    //Capture error information
    current_error_ctx.error_status = error_status;
    current_error_ctx.error_value = error_value;
    if (error_status == MBED_ERROR_MEMMANAGE_EXCEPTION ||
        error_status == MBED_ERROR_BUSFAULT_EXCEPTION ||
        error_status == MBED_ERROR_USAGEFAULT_EXCEPTION ||
        error_status == MBED_ERROR_HARDFAULT_EXCEPTION)
    {
#if defined(__CORTEX_M)
        mbed_fault_context_t *mfc = (mbed_fault_context_t*)error_value;
        current_error_ctx.error_address = (uint32_t)mfc->PC_reg;
        current_error_ctx.thread_current_sp = (uint32_t)mfc->SP_reg;
        // Note that the RTX thread itself is same even under fault exception handlers.
#else
#warning Please implement non Cortex-M handler for those error cases.
#endif
    }
    else
    {
        current_error_ctx.error_address = (uint32_t)caller;
        current_error_ctx.thread_current_sp = (uint32_t)&current_error_ctx; // Address local variable to get a stack pointer
    }

#ifdef MBED_CONF_RTOS_PRESENT
    //Capture thread info
    osRtxThread_t *current_thread = osRtxInfo.thread.run.curr;
    current_error_ctx.thread_id = (uint32_t)current_thread;
    current_error_ctx.thread_entry_address = (uint32_t)current_thread->thread_addr;
    current_error_ctx.thread_stack_size = current_thread->stack_size;
    current_error_ctx.thread_stack_mem = (uint32_t)current_thread->stack_mem;
#endif //MBED_CONF_RTOS_PRESENT

#if MBED_CONF_PLATFORM_ERROR_FILENAME_CAPTURE_ENABLED
    //Capture filename/linenumber if provided<commit_msg>Fixed astyle failures on handle_error().<commit_after>/* mbed Microcontroller Library
 * Copyright (c) 2006-2019 ARM Limited
 * SPDX-License-Identifier: Apache-2.0
 *
 * 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 <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include "device.h"
#include "platform/source/mbed_crash_data_offsets.h"
#include "platform/mbed_atomic.h"
#include "platform/mbed_critical.h"
#include "platform/mbed_error.h"
#include "platform/source/mbed_error_hist.h"
#include "platform/mbed_interface.h"
#include "platform/mbed_power_mgmt.h"
#include "platform/mbed_stats.h"
#if defined(__CORTEX_M)
#include "platform/source/TARGET_CORTEX_M/mbed_fault_handler.h"
#endif
#ifdef MBED_CONF_RTOS_PRESENT
#include "rtx_os.h"
#endif

#if DEVICE_STDIO_MESSAGES
#include <stdio.h>
#endif
#ifndef __STDC_FORMAT_MACROS
#define __STDC_FORMAT_MACROS
#endif
#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);
#else
#define ERROR_REPORT(ctx, error_msg, error_filename, error_line) ((void) 0)
#endif

static bool error_in_progress;
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};

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);

#if MBED_CONF_PLATFORM_CRASH_CAPTURE_ENABLED
//Global for populating the context in exception handler
static mbed_error_ctx *const report_error_ctx = (mbed_error_ctx *)(ERROR_CONTEXT_LOCATION);
static bool is_reboot_error_valid = false;

//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(const void *data, int datalen)
{
    const unsigned int polynomial = 0x04C11DB7; /* divisor is 32bit */
    unsigned int crc = 0; /* CRC value is 32bit */
    unsigned char *buf = (unsigned char *)data;//use a temp variable to make code readable and to avoid typecasting issues.

    for (; datalen > 0; datalen--) {
        unsigned char b = *buf++;
        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;
}
#endif

//Helper function to halt the system
static MBED_NORETURN void mbed_halt_system(void)
{
    // Prevent recursion if halt is called again during halt attempt - try
    // something simple instead.
    if (core_util_atomic_flag_test_and_set(&halt_in_progress)) {
        core_util_critical_section_enter();
        __DSB();
        for (;;) {
            __WFE(); // Not WFI, as don't want to wake for pending interrupts
        }
    }

    //If in ISR context, call mbed_die directly
    if (core_util_is_isr_active() || !core_util_are_interrupts_enabled()) {
        mbed_die();
    }

    // In normal context, try orderly exit(1), which eventually calls mbed_die
    exit(1);
}

WEAK MBED_NORETURN void error(const char *format, ...)
{
    // Prevent recursion if error is called again during store+print attempt
    if (!core_util_atomic_exchange_bool(&error_in_progress, true)) {
        handle_error(MBED_ERROR_UNKNOWN, 0, NULL, 0, MBED_CALLER_ADDR());
        ERROR_REPORT(&last_error_ctx, "Fatal Run-time error", NULL, 0);

#ifndef NDEBUG
        va_list arg;
        va_start(arg, format);
        mbed_error_vprintf(format, arg);
        va_end(arg);
        // Add a newline to prevent any line buffering
        mbed_error_puts("\n");
#endif
    }

    mbed_halt_system();
}

//Set an error status with the error handling system
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)
{
    mbed_error_ctx current_error_ctx;

    //Error status should always be < 0
    if (error_status >= 0) {
        //This is a weird situation, someone called mbed_error with an invalid error code.
        //We will still handle the situation but change the error code to ERROR_INVALID_ARGUMENT, at least the context will have info on who called it
        error_status = MBED_ERROR_INVALID_ARGUMENT;
    }

    //Clear the context capturing buffer
    memset(&current_error_ctx, 0, sizeof(mbed_error_ctx));

    //Capture error information
    current_error_ctx.error_status = error_status;
    current_error_ctx.error_value = error_value;
    if (error_status == MBED_ERROR_MEMMANAGE_EXCEPTION ||
            error_status == MBED_ERROR_BUSFAULT_EXCEPTION ||
            error_status == MBED_ERROR_USAGEFAULT_EXCEPTION ||
            error_status == MBED_ERROR_HARDFAULT_EXCEPTION) {
#if defined(__CORTEX_M)
        mbed_fault_context_t *mfc = (mbed_fault_context_t *)error_value;
        current_error_ctx.error_address = (uint32_t)mfc->PC_reg;
        current_error_ctx.thread_current_sp = (uint32_t)mfc->SP_reg;
        // Note that the RTX thread itself is same even under fault exception handlers.
#else
#warning Please implement non Cortex-M handler for those error cases.
#endif
    } else {
        current_error_ctx.error_address = (uint32_t)caller;
        current_error_ctx.thread_current_sp = (uint32_t)&current_error_ctx; // Address local variable to get a stack pointer
    }

#ifdef MBED_CONF_RTOS_PRESENT
    //Capture thread info
    osRtxThread_t *current_thread = osRtxInfo.thread.run.curr;
    current_error_ctx.thread_id = (uint32_t)current_thread;
    current_error_ctx.thread_entry_address = (uint32_t)current_thread->thread_addr;
    current_error_ctx.thread_stack_size = current_thread->stack_size;
    current_error_ctx.thread_stack_mem = (uint32_t)current_thread->stack_mem;
#endif //MBED_CONF_RTOS_PRESENT

#if MBED_CONF_PLATFORM_ERROR_FILENAME_CAPTURE_ENABLED
    //Capture filename/linenumber if provided
{'fraction_non_alphanumeric': 0.08493322203672787, 'fraction_numerical': 0.01001669449081803, 'mean_word_length': 3.8951310861423223, 'pattern_counts': {'":': 0, '<': 29, '<?xml version=': 0, '>': 27, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 2, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '491659', 'n_tokens_mistral': 4675, 'n_tokens_neox': 4502, 'n_words': 1362}