159 lines
6.9 KiB
C
159 lines
6.9 KiB
C
|
/* Copyright (C) 2018 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.
|
||
|
*/
|
||
|
#ifndef _CRASH_CATCHER_H_
|
||
|
#define _CRASH_CATCHER_H_
|
||
|
|
||
|
|
||
|
#include <stdint.h>
|
||
|
#include <stdlib.h>
|
||
|
|
||
|
|
||
|
#define TRUE 1
|
||
|
#define FALSE 0
|
||
|
|
||
|
|
||
|
/* The crash dump start with a four byte header. The first two bytes are "cC", the third byte is the major version
|
||
|
number, and the fourth bytes is the minor version number. */
|
||
|
#define CRASH_CATCHER_SIGNATURE_BYTE0 'c'
|
||
|
#define CRASH_CATCHER_SIGNATURE_BYTE1 'C'
|
||
|
#define CRASH_CATCHER_VERSION_MAJOR 3
|
||
|
#define CRASH_CATCHER_VERSION_MINOR 0
|
||
|
|
||
|
/* The second word of the dump contains flags. These are the allowed flags. */
|
||
|
/* Flag to indicate that 32 single-precision floating point registers and FPSCR will follow integer registers. */
|
||
|
#define CRASH_CATCHER_FLAGS_FLOATING_POINT (1 << 0)
|
||
|
|
||
|
|
||
|
/* This magic value will be found as the last word in a crash dump if the fault handler overflowed the stack while
|
||
|
generating the crash dump. */
|
||
|
#define CRASH_CATCHER_STACK_SENTINEL 0xACCE55ED
|
||
|
|
||
|
|
||
|
/* Particulars of crash provided to CrashCatcher_DumpStart(). */
|
||
|
typedef struct
|
||
|
{
|
||
|
/* The SP, Stack Pointer, contained this value at the time of the fault. */
|
||
|
uint32_t sp;
|
||
|
/* Was this fault actually just a hardcoded breakpoint from which it is safe to continue. */
|
||
|
int isBKPT;
|
||
|
} CrashCatcherInfo;
|
||
|
|
||
|
|
||
|
/* The crash dump will have one of these entries for each memory region included in the dump file. */
|
||
|
typedef struct
|
||
|
{
|
||
|
uint32_t startAddress;
|
||
|
uint32_t endAddress;
|
||
|
} CrashCatcherMemoryRegionInfo;
|
||
|
|
||
|
/* Supported element sizes to be used with CrashCatcher_DumpMemory calls. */
|
||
|
typedef enum
|
||
|
{
|
||
|
CRASH_CATCHER_BYTE = 1,
|
||
|
CRASH_CATCHER_HALFWORD = 2,
|
||
|
CRASH_CATCHER_WORD = 4
|
||
|
} CrashCatcherElementSizes;
|
||
|
|
||
|
|
||
|
/* Codes to be returned from an implementation's CrashCathcer_DumpEnd() handler. */
|
||
|
typedef enum
|
||
|
{
|
||
|
/* Crash Catcher should loop around and try dumping again incase user missed it previous time. */
|
||
|
CRASH_CATCHER_TRY_AGAIN = 0,
|
||
|
/* Crash Catcher should exit and return to caller. This is used during unit testing or if the crash cause was
|
||
|
actually a hardcoded breakpoint that should be logged and then execution continued. */
|
||
|
CRASH_CATCHER_EXIT
|
||
|
} CrashCatcherReturnCodes;
|
||
|
|
||
|
|
||
|
/* An array of these structures is returned from CrashCatcher_GetMemoryRegions() to indicate what regions of memory
|
||
|
should be dumped as part of the crash dump. The last entry should contain a starting address of 0xFFFFFFFF to
|
||
|
indicate that the end of the list has been encountered. */
|
||
|
typedef struct
|
||
|
{
|
||
|
/* The first address of the element to be dumped for this region of memory. */
|
||
|
/* The last region in the array return from CrashCatcher_GetMemoryRegions() must set this to 0xFFFFFFFF */
|
||
|
uint32_t startAddress;
|
||
|
/* Stop dumping the region once this address is encountered. The dump isn't inclusive of this address. */
|
||
|
/* It must be greater than startAddress. */
|
||
|
uint32_t endAddress;
|
||
|
/* This should be set to CRASH_CATCHER_BYTE except for peripheral registers which don't support 8-bit reads. */
|
||
|
CrashCatcherElementSizes elementSize;
|
||
|
} CrashCatcherMemoryRegion;
|
||
|
|
||
|
|
||
|
#ifdef __cplusplus
|
||
|
extern "C"
|
||
|
{
|
||
|
#endif
|
||
|
/* The following functions must be provided by a specific dumping implementation. The Core CrashCatcher calls these
|
||
|
routines to have an implementation dump the bytes associated with the current crash. */
|
||
|
|
||
|
/* Called at the beginning of crash dump. You should provide an implementation which prepares for the dump by opening
|
||
|
a dump file, prompting the user to begin a crash dump, or whatever makes sense for your scenario. */
|
||
|
int CrashCatcher_DumpStart(const CrashCatcherInfo* pInfo);
|
||
|
|
||
|
/* Called to obtain an array of regions in memory that should be dumped as part of the crash. This will typically
|
||
|
be all RAM regions that contain volatile data. For some crash scenarios, a user may decide to also add peripheral
|
||
|
registers of interest (ie. dump some ethernet registers when you are encountering crashes in the network stack.)
|
||
|
If NULL is returned from this function, the core will only dump the registers. */
|
||
|
const CrashCatcherMemoryRegion* CrashCatcher_GetMemoryRegions(void);
|
||
|
|
||
|
/* Called to dump the next chunk of memory to the dump (this memory may point to register contents which has been copied
|
||
|
to memory by CrashCatcher already. The element size will be 8-bits, 16-bits, or 32-bits. The implementation should
|
||
|
use reads of the specified size since some memory locations may only support the indicated size. */
|
||
|
void CrashCatcher_DumpMemory(const void* pvMemory, CrashCatcherElementSizes elementSize, size_t elementCount);
|
||
|
|
||
|
/* Called at the end of crash dump. You should provide an implementation which cleans up at the end of dump. This could
|
||
|
include closing a dump file, blinking LEDs, infinite looping, and/or returning CRASH_CATCHER_TRY_AGAIN if
|
||
|
CrashCatcher should prepare to dump again incase user missed the first attempt. */
|
||
|
CrashCatcherReturnCodes CrashCatcher_DumpEnd(void);
|
||
|
|
||
|
|
||
|
/* The following functions must be provided by a hex dumping implementation. Such implementations will also have to
|
||
|
implement the core CrashCatcher_GetMemoryRegions() API as well. The HexDump version of CrashCatcher calls these
|
||
|
routines to have an implementation query the user when they are ready for the dump to start and actually dump the
|
||
|
hex data to the user a character at a time. */
|
||
|
|
||
|
/* Called to receive a character of data from the user. Typically this is in response to a "Press any key" type of
|
||
|
prompt to the user. This function should be blocking. */
|
||
|
int CrashCatcher_getc(void);
|
||
|
|
||
|
/* Called to send a character of hex dump data to the user. */
|
||
|
void CrashCatcher_putc(char c);
|
||
|
|
||
|
#ifdef __cplusplus
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
|
||
|
/* Macros which can generate a few forms of crashes. */
|
||
|
#define CRASH_CATCHER_READ_FAULT() (*(volatile unsigned int*)0xFFFFFFF0)
|
||
|
#define CRASH_CATCHER_WRITE_FAULT() (*(volatile unsigned int*)0xFFFFFFF0 = 0x0)
|
||
|
#define CRASH_CATCHER_INVALID_INSTRUCTION() { __asm volatile (".word 0xDE00"); }
|
||
|
|
||
|
/* Macro used to insert hardcoded breakpoint into user's code. */
|
||
|
#define CRASH_CATCHER_BREAKPOINT() { __asm volatile ("bkpt #0"); }
|
||
|
|
||
|
/* Macro used to make some globals writeable from unit tests but constant when running on ARM processors. */
|
||
|
#ifdef RUNNING_HOST_TESTS
|
||
|
#define CRASH_CATCHER_TEST_WRITEABLE
|
||
|
#else
|
||
|
#define CRASH_CATCHER_TEST_WRITEABLE static const
|
||
|
#endif
|
||
|
|
||
|
|
||
|
#endif /* _CRASH_CATCHER_H_ */
|