From 181d07321fceefc99369704569e1ee92c3570f95 Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Tue, 18 Aug 2020 12:55:08 -0700 Subject: [PATCH] coredump: add support for ARM Cortex-M This adds the necessary bits in arch code, and Python scripts to enable coredump support for ARM Cortex-M. Signed-off-by: Daniel Leung --- arch/Kconfig | 1 + arch/arm/core/aarch32/cortex_m/CMakeLists.txt | 2 + arch/arm/core/aarch32/cortex_m/coredump.c | 75 +++++++++++++++ arch/arm/core/aarch32/cortex_m/fault.c | 4 + include/arch/arm/aarch32/exc.h | 2 + include/debug/coredump.h | 1 + scripts/coredump/gdbstubs/__init__.py | 4 + .../coredump/gdbstubs/arch/arm_cortex_m.py | 91 +++++++++++++++++++ 8 files changed, 180 insertions(+) create mode 100644 arch/arm/core/aarch32/cortex_m/coredump.c create mode 100644 scripts/coredump/gdbstubs/arch/arm_cortex_m.py diff --git a/arch/Kconfig b/arch/Kconfig index 57bdd213a60..8e19565fdfd 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -27,6 +27,7 @@ config ARC config ARM bool select ARCH_IS_SET + select ARCH_SUPPORTS_COREDUMP if CPU_CORTEX_M select HAS_DTS # FIXME: current state of the code for all ARM requires this, but # is really only necessary for Cortex-M with ARM MPU! diff --git a/arch/arm/core/aarch32/cortex_m/CMakeLists.txt b/arch/arm/core/aarch32/cortex_m/CMakeLists.txt index 2d6af46d19e..48550b750de 100644 --- a/arch/arm/core/aarch32/cortex_m/CMakeLists.txt +++ b/arch/arm/core/aarch32/cortex_m/CMakeLists.txt @@ -13,6 +13,8 @@ zephyr_library_sources( thread_abort.c ) +zephyr_library_sources_ifdef(CONFIG_DEBUG_COREDUMP coredump.c) + if (CONFIG_SW_VECTOR_RELAY) if (CONFIG_CPU_CORTEX_M_HAS_VTOR) set(relay_vector_table_sort_key relay_vectors) diff --git a/arch/arm/core/aarch32/cortex_m/coredump.c b/arch/arm/core/aarch32/cortex_m/coredump.c new file mode 100644 index 00000000000..58255e0327d --- /dev/null +++ b/arch/arm/core/aarch32/cortex_m/coredump.c @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2020 Intel Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#define ARCH_HDR_VER 1 + +uint32_t z_arm_coredump_fault_sp; + +struct arm_arch_block { + struct { + uint32_t r0; + uint32_t r1; + uint32_t r2; + uint32_t r3; + uint32_t r12; + uint32_t lr; + uint32_t pc; + uint32_t xpsr; + uint32_t sp; + } r; +} __packed; + +/* + * This might be too large for stack space if defined + * inside function. So do it here. + */ +static struct arm_arch_block arch_blk; + +void arch_coredump_info_dump(const z_arch_esf_t *esf) +{ + struct z_coredump_arch_hdr_t hdr = { + .id = Z_COREDUMP_ARCH_HDR_ID, + .hdr_version = ARCH_HDR_VER, + .num_bytes = sizeof(arch_blk), + }; + + /* Nothing to process */ + if (esf == NULL) { + return; + } + + (void)memset(&arch_blk, 0, sizeof(arch_blk)); + + /* + * 17 registers expected by GDB. + * Not all are in ESF but the GDB stub + * will need to send all 17 as one packet. + * The stub will need to send undefined + * for registers not presented in coredump. + */ + arch_blk.r.r0 = esf->basic.r0; + arch_blk.r.r1 = esf->basic.r1; + arch_blk.r.r2 = esf->basic.r2; + arch_blk.r.r3 = esf->basic.r3; + arch_blk.r.r12 = esf->basic.ip; + arch_blk.r.lr = esf->basic.lr; + arch_blk.r.pc = esf->basic.pc; + arch_blk.r.xpsr = esf->basic.xpsr; + + arch_blk.r.sp = z_arm_coredump_fault_sp; + + /* Send for output */ + z_coredump_buffer_output((uint8_t *)&hdr, sizeof(hdr)); + z_coredump_buffer_output((uint8_t *)&arch_blk, sizeof(arch_blk)); +} + +uint16_t arch_coredump_tgt_code_get(void) +{ + return COREDUMP_TGT_ARM_CORTEX_M; +} diff --git a/arch/arm/core/aarch32/cortex_m/fault.c b/arch/arm/core/aarch32/cortex_m/fault.c index ec7d75af8e7..4925e3b31bb 100644 --- a/arch/arm/core/aarch32/cortex_m/fault.c +++ b/arch/arm/core/aarch32/cortex_m/fault.c @@ -953,6 +953,10 @@ void z_arm_fault(uint32_t msp, uint32_t psp, uint32_t exc_return) __ASSERT(esf != NULL, "ESF could not be retrieved successfully. Shall never occur."); +#ifdef CONFIG_DEBUG_COREDUMP + z_arm_coredump_fault_sp = POINTER_TO_UINT(esf); +#endif + reason = fault_handle(esf, fault, &recoverable); if (recoverable) { return; diff --git a/include/arch/arm/aarch32/exc.h b/include/arch/arm/aarch32/exc.h index 2e74222bf92..dba2e877291 100644 --- a/include/arch/arm/aarch32/exc.h +++ b/include/arch/arm/aarch32/exc.h @@ -91,6 +91,8 @@ struct __esf { #endif }; +extern uint32_t z_arm_coredump_fault_sp; + typedef struct __esf z_arch_esf_t; #ifdef CONFIG_CPU_CORTEX_M diff --git a/include/debug/coredump.h b/include/debug/coredump.h index 03a608c1f70..73896b22f39 100644 --- a/include/debug/coredump.h +++ b/include/debug/coredump.h @@ -25,6 +25,7 @@ enum z_coredump_tgt_code { COREDUMP_TGT_UNKNOWN = 0, COREDUMP_TGT_X86, COREDUMP_TGT_X86_64, + COREDUMP_TGT_ARM_CORTEX_M, }; /* Coredump header */ diff --git a/scripts/coredump/gdbstubs/__init__.py b/scripts/coredump/gdbstubs/__init__.py index d71c8f23d2d..61f0aae24f7 100644 --- a/scripts/coredump/gdbstubs/__init__.py +++ b/scripts/coredump/gdbstubs/__init__.py @@ -6,11 +6,13 @@ from gdbstubs.arch.x86 import GdbStub_x86 from gdbstubs.arch.x86_64 import GdbStub_x86_64 +from gdbstubs.arch.arm_cortex_m import GdbStub_ARM_CortexM class TgtCode: UNKNOWN = 0 X86 = 1 X86_64 = 2 + ARM_CORTEX_M = 3 def get_gdbstub(logfile, elffile): stub = None @@ -21,5 +23,7 @@ def get_gdbstub(logfile, elffile): stub = GdbStub_x86(logfile=logfile, elffile=elffile) elif tgt_code == TgtCode.X86_64: stub = GdbStub_x86_64(logfile=logfile, elffile=elffile) + elif tgt_code == TgtCode.ARM_CORTEX_M: + stub = GdbStub_ARM_CortexM(logfile=logfile, elffile=elffile) return stub diff --git a/scripts/coredump/gdbstubs/arch/arm_cortex_m.py b/scripts/coredump/gdbstubs/arch/arm_cortex_m.py new file mode 100644 index 00000000000..168a719fac7 --- /dev/null +++ b/scripts/coredump/gdbstubs/arch/arm_cortex_m.py @@ -0,0 +1,91 @@ +#!/usr/bin/env python3 +# +# Copyright (c) 2020 Intel Corporation +# +# SPDX-License-Identifier: Apache-2.0 + +import binascii +import logging +import struct + +from gdbstubs.gdbstub import GdbStub + + +logger = logging.getLogger("gdbstub") + + +class RegNum(): + R0 = 0 + R1 = 1 + R2 = 2 + R3 = 3 + R4 = 4 + R5 = 5 + R6 = 6 + R7 = 7 + R8 = 8 + R9 = 9 + R10 = 10 + R11 = 11 + R12 = 12 + SP = 13 + LR = 14 + PC = 15 + XPSR = 16 + + +class GdbStub_ARM_CortexM(GdbStub): + ARCH_DATA_BLK_STRUCT = " unknown value + # Send in "xxxxxxxx" + pkt += b'x' * 8 + + idx += 1 + + self.put_gdb_packet(pkt) + + def handle_register_single_read_packet(self, pkt): + # Mark registers as "". + # 'p' packets are usually used for registers + # other than the general ones (e.g. eax, ebx) + # so we can safely reply "xxxxxxxx" here. + self.put_gdb_packet(b'x' * 8)