AP_HAL_ChibiOS: move CrashCatcher core in-tree

Keep the Cortex-M fault entry and dump-format implementation alongside the ChibiOS crashdump backends.
This commit is contained in:
Andrew Tridgell
2026-08-25 10:46:36 +10:00
parent 86a4387efb
commit e644fdad79
9 changed files with 398 additions and 44 deletions
+177
View File
@@ -0,0 +1,177 @@
/*
* 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.
*
* Adapted for ArduPilot.
*/
#include <AP_HAL/AP_HAL.h>
#if AP_CRASHDUMP_ENABLED
#include "CrashCatcher.h"
#include <string.h>
#define LR_PSP (1U << 2)
#define LR_FLOAT (1U << 4)
#define PSR_STACK_ALIGN (1U << 9)
static constexpr uintptr_t COPROCESSOR_ACCESS_CONTROL_REGISTER = 0xE000ED88U;
static constexpr uintptr_t FAULT_STATUS_REGISTERS = 0xE000ED28U;
alignas(8) uint32_t g_crashCatcherStack[CRASH_CATCHER_STACK_WORD_COUNT];
struct CrashCatcherObject {
const CrashCatcherExceptionRegisters *exception_registers;
CrashCatcherStackedRegisters *stacked_registers;
uint32_t flags;
CrashCatcherInfo info;
};
static_assert(sizeof(CrashCatcherExceptionRegisters) == 12U * sizeof(uint32_t),
"CrashCatcher exception register layout changed");
static_assert(offsetof(CrashCatcherStackedRegisters, floats) == 8U * sizeof(uint32_t),
"CrashCatcher stacked register layout changed");
static void *address_to_pointer(uint32_t address)
{
return reinterpret_cast<void *>(static_cast<uintptr_t>(address));
}
static uint32_t exception_stack_address(const CrashCatcherExceptionRegisters *exception_registers)
{
if ((exception_registers->exceptionLR & LR_PSP) != 0) {
return exception_registers->psp;
}
return exception_registers->msp;
}
static CrashCatcherObject initialise(const CrashCatcherExceptionRegisters *exception_registers)
{
CrashCatcherObject object {};
object.exception_registers = exception_registers;
object.info.sp = exception_stack_address(exception_registers);
object.stacked_registers = static_cast<CrashCatcherStackedRegisters *>(address_to_pointer(object.info.sp));
// Cortex-M always stacks eight integer registers on exception entry.
object.info.sp += 8U * sizeof(uint32_t);
// An extended exception frame also contains S0-S15, FPSCR and a reserved word.
if ((exception_registers->exceptionLR & LR_FLOAT) == 0) {
object.info.sp += 18U * sizeof(uint32_t);
}
// xPSR records the alignment word inserted before the exception frame.
if ((object.stacked_registers->psr & PSR_STACK_ALIGN) != 0) {
object.info.sp |= 4U;
}
const volatile uint32_t *const cpacr =
reinterpret_cast<const volatile uint32_t *>(COPROCESSOR_ACCESS_CONTROL_REGISTER);
constexpr uint32_t CP10_CP11_ENABLED = 5U << 20;
if ((*cpacr & CP10_CP11_ENABLED) == CP10_CP11_ENABLED) {
object.flags |= CRASH_CATCHER_FLAGS_FLOATING_POINT;
}
const uint16_t *const instruction =
static_cast<const uint16_t *>(address_to_pointer(object.stacked_registers->pc));
object.info.isBKPT = ((*instruction & 0xFF00U) == 0xBE00U);
return object;
}
static void dump_signature()
{
static const uint8_t signature[] = {
CRASH_CATCHER_SIGNATURE_BYTE0,
CRASH_CATCHER_SIGNATURE_BYTE1,
CRASH_CATCHER_VERSION_MAJOR,
CRASH_CATCHER_VERSION_MINOR
};
CrashCatcher_DumpMemory(signature, CRASH_CATCHER_BYTE, sizeof(signature));
}
static void dump_core_registers(const CrashCatcherObject &object)
{
CrashCatcher_DumpMemory(&object.stacked_registers->r0, CRASH_CATCHER_BYTE, 4U * sizeof(uint32_t));
CrashCatcher_DumpMemory(&object.exception_registers->r4, CRASH_CATCHER_BYTE, 8U * sizeof(uint32_t));
CrashCatcher_DumpMemory(&object.stacked_registers->r12, CRASH_CATCHER_BYTE, sizeof(uint32_t));
CrashCatcher_DumpMemory(&object.info.sp, CRASH_CATCHER_BYTE, sizeof(uint32_t));
CrashCatcher_DumpMemory(&object.stacked_registers->lr, CRASH_CATCHER_BYTE, 3U * sizeof(uint32_t));
CrashCatcher_DumpMemory(&object.exception_registers->msp, CRASH_CATCHER_BYTE, 3U * sizeof(uint32_t));
}
static void dump_floating_point_registers(const CrashCatcherObject &object)
{
uint32_t registers[33];
if ((object.exception_registers->exceptionLR & LR_FLOAT) == 0) {
// Accessing S16-S31 first completes any pending lazy exception stacking.
CrashCatcher_CopyUpperFloatingPointRegisters(&registers[16]);
memcpy(&registers[0], &object.stacked_registers->floats, sizeof(object.stacked_registers->floats));
registers[32] = object.stacked_registers->fpscr;
} else {
CrashCatcher_CopyAllFloatingPointRegisters(registers);
}
CrashCatcher_DumpMemory(registers, CRASH_CATCHER_BYTE, sizeof(registers));
}
static void dump_memory_regions(const CrashCatcherMemoryRegion *region)
{
while (region != nullptr && region->startAddress != UINT32_MAX) {
// The dump format stores only the start and end addresses, not elementSize.
CrashCatcher_DumpMemory(region, CRASH_CATCHER_BYTE, 2U * sizeof(uint32_t));
CrashCatcher_DumpMemory(address_to_pointer(region->startAddress), region->elementSize,
(region->endAddress - region->startAddress) / region->elementSize);
region++;
}
}
static void dump_fault_status_registers()
{
const CrashCatcherMemoryRegion regions[] = {
{
static_cast<uint32_t>(FAULT_STATUS_REGISTERS),
static_cast<uint32_t>(FAULT_STATUS_REGISTERS + 5U * sizeof(uint32_t)),
CRASH_CATCHER_WORD
},
{UINT32_MAX, UINT32_MAX, CRASH_CATCHER_BYTE}
};
dump_memory_regions(regions);
}
void CrashCatcher_Entry(const CrashCatcherExceptionRegisters *exception_registers)
{
CrashCatcherObject object = initialise(exception_registers);
do {
g_crashCatcherStack[0] = CRASH_CATCHER_STACK_SENTINEL;
CrashCatcher_DumpStart(&object.info);
dump_signature();
CrashCatcher_DumpMemory(&object.flags, CRASH_CATCHER_BYTE, sizeof(object.flags));
dump_core_registers(object);
if ((object.flags & CRASH_CATCHER_FLAGS_FLOATING_POINT) != 0) {
dump_floating_point_registers(object);
}
dump_memory_regions(CrashCatcher_GetMemoryRegions());
dump_fault_status_registers();
if (g_crashCatcherStack[0] != CRASH_CATCHER_STACK_SENTINEL) {
static const uint8_t overflow_marker[] = {0xAC, 0xCE, 0x55, 0xED};
CrashCatcher_DumpMemory(overflow_marker, CRASH_CATCHER_BYTE, sizeof(overflow_marker));
}
} while (CrashCatcher_DumpEnd() == CRASH_CATCHER_TRY_AGAIN);
if (object.info.isBKPT) {
object.stacked_registers->pc += 2U;
}
}
#endif // AP_CRASHDUMP_ENABLED
+125
View File
@@ -0,0 +1,125 @@
/*
* Copyright (C) 2017-2019 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.
*
* Adapted for ArduPilot.
*/
#pragma once
#define CRASH_CATCHER_STACK_WORD_COUNT 192
#ifdef __ARM_ARCH_7EM__
#define CRASH_CATCHER_WITH_FPU 1
#else
#define CRASH_CATCHER_WITH_FPU 0
#endif
#if !defined(__ASSEMBLER__) || (!__ASSEMBLER__)
#include <stddef.h>
#include <stdint.h>
#define CRASH_CATCHER_SIGNATURE_BYTE0 'c'
#define CRASH_CATCHER_SIGNATURE_BYTE1 'C'
#define CRASH_CATCHER_VERSION_MAJOR 3
#define CRASH_CATCHER_VERSION_MINOR 0
#define CRASH_CATCHER_FLAGS_FLOATING_POINT (1U << 0)
#define CRASH_CATCHER_STACK_SENTINEL 0xACCE55EDU
typedef struct {
uint32_t sp;
int isBKPT;
} CrashCatcherInfo;
typedef struct {
uint32_t startAddress;
uint32_t endAddress;
} CrashCatcherMemoryRegionInfo;
typedef enum {
CRASH_CATCHER_BYTE = 1,
CRASH_CATCHER_HALFWORD = 2,
CRASH_CATCHER_WORD = 4
} CrashCatcherElementSizes;
typedef enum {
CRASH_CATCHER_TRY_AGAIN = 0,
CRASH_CATCHER_EXIT
} CrashCatcherReturnCodes;
typedef struct {
uint32_t startAddress;
uint32_t endAddress;
CrashCatcherElementSizes elementSize;
} CrashCatcherMemoryRegion;
typedef struct {
uint32_t r0;
uint32_t r1;
uint32_t r2;
uint32_t r3;
uint32_t r12;
uint32_t lr;
uint32_t pc;
uint32_t psr;
uint32_t floats[16];
uint32_t fpscr;
uint32_t reserved;
} CrashCatcherStackedRegisters;
typedef struct {
uint32_t msp;
uint32_t psp;
uint32_t exceptionPSR;
uint32_t r4;
uint32_t r5;
uint32_t r6;
uint32_t r7;
uint32_t r8;
uint32_t r9;
uint32_t r10;
uint32_t r11;
uint32_t exceptionLR;
} CrashCatcherExceptionRegisters;
#ifdef RUNNING_HOST_TESTS
#define CRASH_CATCHER_TEST_WRITEABLE
#else
#define CRASH_CATCHER_TEST_WRITEABLE static const
#endif
#ifdef __cplusplus
extern "C" {
#endif
void CrashCatcher_DumpStart(const CrashCatcherInfo *info);
const CrashCatcherMemoryRegion *CrashCatcher_GetMemoryRegions(void);
void CrashCatcher_DumpMemory(const void *memory, CrashCatcherElementSizes element_size, size_t element_count);
CrashCatcherReturnCodes CrashCatcher_DumpEnd(void);
int CrashCatcher_getc(void);
void CrashCatcher_putc(int character);
extern uint32_t g_crashCatcherStack[CRASH_CATCHER_STACK_WORD_COUNT];
void CrashCatcher_Entry(const CrashCatcherExceptionRegisters *exception_registers);
void CrashCatcher_CopyAllFloatingPointRegisters(uint32_t *buffer);
void CrashCatcher_CopyUpperFloatingPointRegisters(uint32_t *buffer);
#ifdef __cplusplus
}
#endif
#endif // !__ASSEMBLER__
+1 -1
View File
@@ -19,7 +19,7 @@
#if AP_CRASHDUMP_ENABLED
#include <CrashCatcher.h>
#include "CrashCatcher.h"
#include <ch.h>
#include <hal.h>
#include <string.h>
+1 -1
View File
@@ -41,7 +41,7 @@
#include <stddef.h>
#if AP_CRASHDUMP_FATFS_ENABLED || AP_CRASHDUMP_FLASH_ENABLED
#include <CrashCatcher.h>
#include "CrashCatcher.h"
#endif
#ifdef __cplusplus
+1 -1
View File
@@ -19,7 +19,7 @@
#if AP_CRASHDUMP_ENABLED && AP_CRASHDUMP_FLASH_ENABLED
#include <CrashCatcher.h>
#include "CrashCatcher.h"
#include <ch.h>
#include <hal.h>
#include <string.h>
@@ -0,0 +1,76 @@
/*
* Copyright (C) 2019 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.
*
* Adapted for ArduPilot.
*/
#include "CrashCatcher.h"
.text
.syntax unified
.arch armv7-m
.global HardFault_Handler
.type HardFault_Handler, %function
.thumb_func
HardFault_Handler:
/*
* Save the exception registers before switching MSP to the dedicated
* CrashCatcher stack. The resulting layout is CrashCatcherExceptionRegisters.
*/
mrs r3, xpsr
mrs r2, psp
mrs r1, msp
ldr sp, =(g_crashCatcherStack + 4 * CRASH_CATCHER_STACK_WORD_COUNT)
push.w {r1-r11,lr}
mov r0, sp
bl CrashCatcher_Entry
/* Only breakpoints which request CRASH_CATCHER_EXIT return here. */
pop.w {r1-r11,lr}
mov sp, r1
bx lr
.pool
.size HardFault_Handler, .-HardFault_Handler
.global CrashCatcher_CopyAllFloatingPointRegisters
.type CrashCatcher_CopyAllFloatingPointRegisters, %function
.thumb_func
CrashCatcher_CopyAllFloatingPointRegisters:
#if CRASH_CATCHER_WITH_FPU
vmrs r1, fpscr
vstmia.32 r0!, {s0-s31}
str r1, [r0]
#endif
bx lr
.pool
.size CrashCatcher_CopyAllFloatingPointRegisters, .-CrashCatcher_CopyAllFloatingPointRegisters
.global CrashCatcher_CopyUpperFloatingPointRegisters
.type CrashCatcher_CopyUpperFloatingPointRegisters, %function
.thumb_func
CrashCatcher_CopyUpperFloatingPointRegisters:
#if CRASH_CATCHER_WITH_FPU
vstmia.32 r0!, {s16-s31}
#endif
bx lr
.pool
.size CrashCatcher_CopyUpperFloatingPointRegisters, .-CrashCatcher_CopyUpperFloatingPointRegisters
.end
@@ -148,12 +148,6 @@ endif
# $(TESTSRC) \
# test.c
ifneq ($(CRASHCATCHER),)
LIBCC_CSRC = $(CRASHCATCHER)/Core/src/CrashCatcher.c
LIBCC_ASMXSRC = $(CRASHCATCHER)/Core/src/CrashCatcher_armv7m.S
endif
# C++ sources that can be compiled in ARM or THUMB mode depending on the global
# setting.
CPPSRC = $(sort $(ALLCPPSRC))
@@ -182,11 +176,15 @@ TCPPSRC =
ASMSRC = $(ALLASMSRC)
ASMXSRC = $(ALLXASMSRC)
ifeq ($(ENABLE_CRASHDUMP),yes)
CRASHCATCHER_ASMXSRC = $(HWDEF)/common/CrashCatcher_armv7m_asm.S
endif
INCDIR = $(CHIBIOS)/os/license \
$(ALLINC) $(HWDEF)/common
ifneq ($(CRASHCATCHER),)
INCDIR += $(CRASHCATCHER)/include
ifeq ($(ENABLE_CRASHDUMP),yes)
INCDIR += $(AP_HAL)
endif
ifeq ($(USE_USB_MSD),yes)
@@ -87,7 +87,7 @@ else
endif
ASRC := $(ACSRC) $(ACPPSRC)
TSRC := $(TCSRC) $(TCPPSRC)
SRCPATHS := $(sort $(dir $(ASMXSRC)) $(dir $(ASMSRC)) $(dir $(ASRC)) $(dir $(TSRC)) $(dir $(LIBCC_CSRC)) $(dir $(LIBCC_ASMXSRC)))
SRCPATHS := $(sort $(dir $(ASMXSRC)) $(dir $(ASMSRC)) $(dir $(ASRC)) $(dir $(TSRC)) $(dir $(CRASHCATCHER_ASMXSRC)))
# Various directories
OBJDIR := $(BUILDDIR)/obj
@@ -100,10 +100,8 @@ TCOBJS := $(addprefix $(OBJDIR)/, $(notdir $(TCSRC:.c=.o)))
TCPPOBJS := $(addprefix $(OBJDIR)/, $(notdir $(TCPPSRC:.cpp=.o)))
ASMOBJS := $(addprefix $(OBJDIR)/, $(notdir $(ASMSRC:.s=.o)))
ASMXOBJS := $(addprefix $(OBJDIR)/, $(notdir $(ASMXSRC:.S=.o)))
CRASHCATCHER_ASMXOBJS := $(addprefix $(OBJDIR)/, $(notdir $(CRASHCATCHER_ASMXSRC:.S=.o)))
OBJS := $(ASMXOBJS) $(ASMOBJS) $(ACOBJS) $(TCOBJS) $(ACPPOBJS) $(TCPPOBJS)
LIBCC_ASMXOBJS := $(addprefix $(OBJDIR)/, $(notdir $(LIBCC_ASMXSRC:.S=.o)))
LIBCC_TCOBJS := $(addprefix $(OBJDIR)/, $(notdir $(LIBCC_CSRC:.c=.o)))
LIBCC_OBJS := $(LIBCC_ASMXOBJS) $(LIBCC_TCOBJS)
# Paths
IINCDIR := $(patsubst %,-I%,$(INCDIR) $(DINCDIR) $(UINCDIR))
LLIBDIR := $(patsubst %,-L%,$(DLIBDIR) $(ULIBDIR))
@@ -122,12 +120,11 @@ ODFLAGS = -x --syms
ASFLAGS = $(MCFLAGS) $(ADEFS) $(ASOPT)
ASXFLAGS = $(MCFLAGS) $(ADEFS) $(ASXOPT)
ifneq ($(USE_FPU),no)
LIBCC_ASXFLAGS = $(ASXFLAGS) $(USE_FPU_OPT)
CRASHCATCHER_ASXFLAGS = $(ASXFLAGS) $(USE_FPU_OPT)
else
LIBCC_ASXFLAGS = $(ASXFLAGS)
CRASHCATCHER_ASXFLAGS = $(ASXFLAGS)
endif
CFLAGS = $(MCFLAGS) $(OPT) $(COPT) $(CWARN) $(DEFS)
LIBCC_CFLAGS = $(CFLAGS)
CPPFLAGS = $(MCFLAGS) $(OPT) $(CPPOPT) $(CPPWARN) $(DEFS)
LDFLAGS = $(MCFLAGS) $(OPT) -nostartfiles $(LLIBDIR) -Wl,-Map=$(BUILDDIR)/$(PROJECT).map,--cref,--no-warn-mismatch,--library-path=$(RULESPATH)/ld,--script=$(LDSCRIPT)$(LDOPT)
@@ -186,13 +183,13 @@ N := x
C = $(words $N)$(eval N := x $N)
ECHO = echo "[$C/$T] ChibiOS:"
endif
all: PRE_MAKE_ALL_RULE_HOOK $(OBJS) $(LIBCC_OBJS) $(OUTFILES) POST_MAKE_ALL_RULE_HOOK
all: PRE_MAKE_ALL_RULE_HOOK $(OBJS) $(CRASHCATCHER_ASMXOBJS) $(OUTFILES) POST_MAKE_ALL_RULE_HOOK
PRE_MAKE_ALL_RULE_HOOK:
POST_MAKE_ALL_RULE_HOOK:
$(LIBCC_OBJS) $(OBJS): | $(BUILDDIR) $(OBJDIR) $(LSTDIR)
$(OBJS) $(CRASHCATCHER_ASMXOBJS): | $(BUILDDIR) $(OBJDIR) $(LSTDIR)
$(BUILDDIR):
ifneq ($(USE_VERBOSE_COMPILE),yes)
@@ -244,15 +241,6 @@ else
@$(CC) -c $(CFLAGS) $(TOPT) -I. $(IINCDIR) $< -o $@
endif
$(LIBCC_TCOBJS) : $(OBJDIR)/%.o : %.c $(BUILDROOT)/chibios_flags.h
ifeq ($(USE_VERBOSE_COMPILE),yes)
@echo
$(CC) -c $(CFLAGS) $(TOPT) -I. $(IINCDIR) $< -o $@
else
@$(ECHO) Compiling $(<F)
@$(CC) -c $(CFLAGS) $(TOPT) -I. $(IINCDIR) $< -o $@
endif
$(ASMOBJS) : $(OBJDIR)/%.o : %.s $(BUILDROOT)/chibios_flags.h
ifeq ($(USE_VERBOSE_COMPILE),yes)
@echo
@@ -271,13 +259,13 @@ else
@$(CC) -c $(ASXFLAGS) $(TOPT) -I. $(IINCDIR) $< -o $@
endif
$(LIBCC_ASMXOBJS) : $(OBJDIR)/%.o : %.S $(BUILDROOT)/chibios_flags.h
$(CRASHCATCHER_ASMXOBJS) : $(OBJDIR)/%.o : %.S $(BUILDROOT)/chibios_flags.h
ifeq ($(USE_VERBOSE_COMPILE),yes)
@echo
$(CC) -c $(LIBCC_ASXFLAGS) $(TOPT) -I. $(IINCDIR) $< -o $@
$(CC) -c $(CRASHCATCHER_ASXFLAGS) $(TOPT) -I. $(IINCDIR) $< -o $@
else
@$(ECHO) Compiling $(<F)
@$(CC) -c $(LIBCC_ASXFLAGS) $(TOPT) -I. $(IINCDIR) $< -o $@
@$(CC) -c $(CRASHCATCHER_ASXFLAGS) $(TOPT) -I. $(IINCDIR) $< -o $@
endif
$(BUILDDIR)/$(PROJECT).elf: $(OBJS) $(LDSCRIPT)
@@ -336,23 +324,13 @@ else
@echo Done
endif
ifneq ($(CRASHCATCHER),)
lib: $(OBJS) $(LIBCC_OBJS) $(BUILDDIR)/lib$(PROJECT).a $(BUILDDIR)/libcc.a pass
else
lib: $(OBJS) $(BUILDDIR)/lib$(PROJECT).a pass
endif
lib: $(OBJS) $(CRASHCATCHER_ASMXOBJS) $(BUILDDIR)/lib$(PROJECT).a pass
$(BUILDDIR)/lib$(PROJECT).a: $(OBJS)
@$(AR) -r $@ $^
@echo
@echo ChibiOS: Done!
$(BUILDDIR)/libcc.a: $(LIBCC_OBJS) $(HWDEF)/common/chibios_board.mk
@rm -f $@
@$(AR) -r $@ $(LIBCC_OBJS)
@echo
@echo CrashCatcher: Done!
pass: $(BUILDDIR)
@echo $(foreach f,$(IINCDIR),"$(f);") > $(BUILDDIR)/include_dirs
+1 -1
View File
@@ -24,7 +24,7 @@
#include "hwdef/common/stm32_util.h"
#include <AP_Vehicle/AP_Vehicle_Type.h>
#if AP_CRASHDUMP_ENABLED
#include <CrashCatcher.h>
#include "CrashCatcher.h"
#endif
#include <ch.h>
#include "hal.h"