system/core_dump/main.c

/*******************************************************************************
* # License
* Copyright 2019 Silicon Laboratories Inc. www.silabs.com
*******************************************************************************
*
* The licensor of this software is Silicon Laboratories Inc. Your use of this
* software is governed by the terms of Silicon Labs Master Software License
* Agreement (MSLA) available at
* www.silabs.com/about-us/legal/master-software-license-agreement. This
* software is distributed to you in Source Code format and is governed by the
* sections of the MSLA applicable to Source Code.
*
******************************************************************************/
#include "gos.h"
#define APPLICATION_START_LINE "\r\nCore Dump Example starting ..."
GOS_CMD_CREATE_COMMAND(trigger, hardfault, "trigger_hardfault", "fault", 0, 0, true);
// This is the app's context
// When debugging the core dump, these values should be in the exact state
// when the coredump triggered
static struct
{
uint32_t rtos_timestamp;
gos_utc_ms_t rtc_timestamp;
char version_str[128];
} mycontext;
/*************************************************************************************************/
void gos_app_init(void)
{
GOS_LOG(APPLICATION_START_LINE);
GOS_LOG("\r\nThis example demonstrates how to use Gecko's 'Core Dump' debugging feature.");
GOS_LOG("The Core Dump debugging feature allows for viewing the state of the device");
GOS_LOG("at the exact moment an exception/fault was triggered in Gecko OS.");
GOS_LOG("This can be extremely useful for debugging device exceptions/faults in the field.");
GOS_LOG("\r\nPerform the following steps to demo Core Dump:");
GOS_LOG("1. Issue the Gecko OS command:");
GOS_LOG(" trigger_hardfault\r\n");
GOS_LOG("2. From your project directory, issue the command:");
GOS_LOG(" make core_dump\r\n");
GOS_LOG("3. Refresh your IDE project\r\n");
GOS_LOG("4. Using the IDE, launch a debugging session with the generated core dump,");
GOS_LOG(" the debug session name in the dropdown list should be something like:");
GOS_LOG(" <project name>-coredump-0\r\n");
GOS_LOG("5. Upon launching the debug session, your device will be in the exact state");
GOS_LOG(" it was in when the exception/fault was triggered.");
GOS_LOG(" Using the IDE debug session, you should be able to see the full stacktrace");
GOS_LOG(" of all the threads.");
GOS_LOG("\r\n");
GOS_LOG("HINT: You can clear old core dumps from the device with the Gecko OS command:");
GOS_LOG(" faults_reset --coredumps\r\n\r\n");
gos_system_get_version_str(mycontext.version_str);
}
typedef struct
{
uint32_t id;
uint32_t timestamp;
uint32_t length;
uint8_t buffer[256];
uint8_t *ptr;
} msgpack_user_context_t;
/*************************************************************************************************/
gos_cmd_result_t trigger_hardfault_command(int argc, char **argv)
{
msgpack_user_context_t context;
MSGPACK_INIT_WITH_WRITER(msgpack, msgpack_writer, &context);
memset(&context, 0, sizeof(msgpack_user_context_t));
context.id = gos_get_random_uint32(0, UINT32_MAX);
context.ptr = context.buffer;
// We trigger a fault by writing msgpack data
// When the length is > 128, msgpack_writer() will write to a bogus address which should cause a hardfault
gos_msgpack_write_dict_uint(&msgpack, "id", context.id);
gos_msgpack_write_dict_ulong(&msgpack, "rtc_timestamp", mycontext.rtc_timestamp);
gos_msgpack_write_dict_uint(&msgpack, "rtos_timestamp", mycontext.rtos_timestamp);
gos_msgpack_write_dict_array(&msgpack, "data", 128);
const char dummy_buffer[] = "abcdefghijklmnopqrstuvwxyz";
for(int i = 0; i < 128; ++i)
{
gos_msgpack_write_str(&msgpack, dummy_buffer);
}
}
/*************************************************************************************************/
static void my_periodic_handler(void *unused)
{
gos_time_get_current_utc_ms(&mycontext.rtc_timestamp, true);
mycontext.rtos_timestamp = gos_rtos_get_time();
}
/*************************************************************************************************/
static gos_result_t msgpack_writer(void *user, const void *data, uint32_t length)
{
msgpack_user_context_t *context = user;
context->timestamp = gos_rtos_get_time();
memcpy(context->ptr, data, length);
context->ptr += length;
context->length += length;
if(context->length > 128)
{
GOS_LOG("Forcefully triggering a hardfault ...");
// Simulate the write pointer getting corrupted
// The next time this executes, a hardfault should trigger
context->ptr = (void*)UINT32_MAX;
}
return GOS_SUCCESS;
}