1 /* Copyright (C) 2018 Adam Green (https://github.com/adamgreen) 2 3 Licensed under the Apache License, Version 2.0 (the "License"); 4 you may not use this file except in compliance with the License. 5 You may obtain a copy of the License at 6 7 http://www.apache.org/licenses/LICENSE-2.0 8 9 Unless required by applicable law or agreed to in writing, software 10 distributed under the License is distributed on an "AS IS" BASIS, 11 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 See the License for the specific language governing permissions and 13 limitations under the License. 14 */ 15 #ifndef _CRASH_CATCHER_H_ 16 #define _CRASH_CATCHER_H_ 17 18 19 #include <stdint.h> 20 #include <stdlib.h> 21 22 23 #define TRUE 1 24 #define FALSE 0 25 26 27 /* The crash dump start with a four byte header. The first two bytes are "cC", the third byte is the major version 28 number, and the fourth bytes is the minor version number. */ 29 #define CRASH_CATCHER_SIGNATURE_BYTE0 'c' 30 #define CRASH_CATCHER_SIGNATURE_BYTE1 'C' 31 #define CRASH_CATCHER_VERSION_MAJOR 3 32 #define CRASH_CATCHER_VERSION_MINOR 0 33 34 /* The second word of the dump contains flags. These are the allowed flags. */ 35 /* Flag to indicate that 32 single-precision floating point registers and FPSCR will follow integer registers. */ 36 #define CRASH_CATCHER_FLAGS_FLOATING_POINT (1 << 0) 37 38 39 /* This magic value will be found as the last word in a crash dump if the fault handler overflowed the stack while 40 generating the crash dump. */ 41 #define CRASH_CATCHER_STACK_SENTINEL 0xACCE55ED 42 43 44 /* Particulars of crash provided to CrashCatcher_DumpStart(). */ 45 typedef struct 46 { 47 /* The SP, Stack Pointer, contained this value at the time of the fault. */ 48 uint32_t sp; 49 /* Was this fault actually just a hardcoded breakpoint from which it is safe to continue. */ 50 int isBKPT; 51 } CrashCatcherInfo; 52 53 54 /* The crash dump will have one of these entries for each memory region included in the dump file. */ 55 typedef struct 56 { 57 uint32_t startAddress; 58 uint32_t endAddress; 59 } CrashCatcherMemoryRegionInfo; 60 61 /* Supported element sizes to be used with CrashCatcher_DumpMemory calls. */ 62 typedef enum 63 { 64 CRASH_CATCHER_BYTE = 1, 65 CRASH_CATCHER_HALFWORD = 2, 66 CRASH_CATCHER_WORD = 4 67 } CrashCatcherElementSizes; 68 69 70 /* Codes to be returned from an implementation's CrashCathcer_DumpEnd() handler. */ 71 typedef enum 72 { 73 /* Crash Catcher should loop around and try dumping again incase user missed it previous time. */ 74 CRASH_CATCHER_TRY_AGAIN = 0, 75 /* Crash Catcher should exit and return to caller. This is used during unit testing or if the crash cause was 76 actually a hardcoded breakpoint that should be logged and then execution continued. */ 77 CRASH_CATCHER_EXIT 78 } CrashCatcherReturnCodes; 79 80 81 /* An array of these structures is returned from CrashCatcher_GetMemoryRegions() to indicate what regions of memory 82 should be dumped as part of the crash dump. The last entry should contain a starting address of 0xFFFFFFFF to 83 indicate that the end of the list has been encountered. */ 84 typedef struct 85 { 86 /* The first address of the element to be dumped for this region of memory. */ 87 /* The last region in the array return from CrashCatcher_GetMemoryRegions() must set this to 0xFFFFFFFF */ 88 uint32_t startAddress; 89 /* Stop dumping the region once this address is encountered. The dump isn't inclusive of this address. */ 90 /* It must be greater than startAddress. */ 91 uint32_t endAddress; 92 /* This should be set to CRASH_CATCHER_BYTE except for peripheral registers which don't support 8-bit reads. */ 93 CrashCatcherElementSizes elementSize; 94 } CrashCatcherMemoryRegion; 95 96 97 #ifdef __cplusplus 98 extern "C" 99 { 100 #endif 101 /* The following functions must be provided by a specific dumping implementation. The Core CrashCatcher calls these 102 routines to have an implementation dump the bytes associated with the current crash. */ 103 104 /* Called at the beginning of crash dump. You should provide an implementation which prepares for the dump by opening 105 a dump file, prompting the user to begin a crash dump, or whatever makes sense for your scenario. */ 106 int CrashCatcher_DumpStart(const CrashCatcherInfo* pInfo); 107 108 /* Called to obtain an array of regions in memory that should be dumped as part of the crash. This will typically 109 be all RAM regions that contain volatile data. For some crash scenarios, a user may decide to also add peripheral 110 registers of interest (ie. dump some ethernet registers when you are encountering crashes in the network stack.) 111 If NULL is returned from this function, the core will only dump the registers. */ 112 const CrashCatcherMemoryRegion* CrashCatcher_GetMemoryRegions(void); 113 114 /* Called to dump the next chunk of memory to the dump (this memory may point to register contents which has been copied 115 to memory by CrashCatcher already. The element size will be 8-bits, 16-bits, or 32-bits. The implementation should 116 use reads of the specified size since some memory locations may only support the indicated size. */ 117 void CrashCatcher_DumpMemory(const void* pvMemory, CrashCatcherElementSizes elementSize, size_t elementCount); 118 119 /* Called at the end of crash dump. You should provide an implementation which cleans up at the end of dump. This could 120 include closing a dump file, blinking LEDs, infinite looping, and/or returning CRASH_CATCHER_TRY_AGAIN if 121 CrashCatcher should prepare to dump again incase user missed the first attempt. */ 122 CrashCatcherReturnCodes CrashCatcher_DumpEnd(void); 123 124 125 /* The following functions must be provided by a hex dumping implementation. Such implementations will also have to 126 implement the core CrashCatcher_GetMemoryRegions() API as well. The HexDump version of CrashCatcher calls these 127 routines to have an implementation query the user when they are ready for the dump to start and actually dump the 128 hex data to the user a character at a time. */ 129 130 /* Called to receive a character of data from the user. Typically this is in response to a "Press any key" type of 131 prompt to the user. This function should be blocking. */ 132 int CrashCatcher_getc(void); 133 134 /* Called to send a character of hex dump data to the user. */ 135 void CrashCatcher_putc(char c); 136 137 #ifdef __cplusplus 138 } 139 #endif 140 141 142 /* Macros which can generate a few forms of crashes. */ 143 #define CRASH_CATCHER_READ_FAULT() (*(volatile unsigned int*)0xFFFFFFF0) 144 #define CRASH_CATCHER_WRITE_FAULT() (*(volatile unsigned int*)0xFFFFFFF0 = 0x0) 145 #define CRASH_CATCHER_INVALID_INSTRUCTION() { __asm volatile (".word 0xDE00"); } 146 147 /* Macro used to insert hardcoded breakpoint into user's code. */ 148 #define CRASH_CATCHER_BREAKPOINT() { __asm volatile ("bkpt #0"); } 149 150 /* Macro used to make some globals writeable from unit tests but constant when running on ARM processors. */ 151 #ifdef RUNNING_HOST_TESTS 152 #define CRASH_CATCHER_TEST_WRITEABLE 153 #else 154 #define CRASH_CATCHER_TEST_WRITEABLE static const 155 #endif 156 157 158 #endif /* _CRASH_CATCHER_H_ */ 159