diff --git a/arch/Kconfig b/arch/Kconfig index de365d9a26f..1c907c9ec1f 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -96,6 +96,7 @@ config RISCV bool select ARCH_IS_SET select HAS_DTS + select ARCH_SUPPORTS_COREDUMP select ARCH_HAS_THREAD_LOCAL_STORAGE imply XIP help diff --git a/arch/riscv/core/CMakeLists.txt b/arch/riscv/core/CMakeLists.txt index 7ef8383ef94..b94bb3e903f 100644 --- a/arch/riscv/core/CMakeLists.txt +++ b/arch/riscv/core/CMakeLists.txt @@ -16,6 +16,7 @@ zephyr_library_sources( thread.c ) +zephyr_library_sources_ifdef(CONFIG_DEBUG_COREDUMP coredump.c) zephyr_library_sources_ifdef(CONFIG_IRQ_OFFLOAD irq_offload.c) zephyr_library_sources_ifdef(CONFIG_THREAD_LOCAL_STORAGE tls.c) zephyr_library_sources_ifdef(CONFIG_USERSPACE userspace.S) diff --git a/arch/riscv/core/coredump.c b/arch/riscv/core/coredump.c new file mode 100644 index 00000000000..656cba274ad --- /dev/null +++ b/arch/riscv/core/coredump.c @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2021 Facebook, Inc. and its affiliates + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#define ARCH_HDR_VER 1 + +struct riscv_arch_block { + struct { + uint32_t ra; + uint32_t tp; + uint32_t t0; + uint32_t t1; + uint32_t t2; + uint32_t a0; + uint32_t a1; + uint32_t a2; + uint32_t a3; + uint32_t a4; + uint32_t a5; + uint32_t a6; + uint32_t a7; + uint32_t t3; + uint32_t t4; + uint32_t t5; + uint32_t t6; + uint32_t pc; + } r; +} __packed; + +/* + * This might be too large for stack space if defined + * inside function. So do it here. + */ +static struct riscv_arch_block arch_blk; + +void arch_coredump_info_dump(const z_arch_esf_t *esf) +{ + struct coredump_arch_hdr_t hdr = { + .id = 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)); + + /* + * 33 registers expected by GDB. Not all are in ESF but the GDB stub will need + * to send all 33 as one packet. The stub will need to send undefined for + * registers not presented in coredump. + */ + arch_blk.r.ra = esf->ra; + arch_blk.r.tp = esf->tp; + arch_blk.r.t0 = esf->t0; + arch_blk.r.t1 = esf->t1; + arch_blk.r.t2 = esf->t2; + arch_blk.r.t3 = esf->t3; + arch_blk.r.t4 = esf->t4; + arch_blk.r.t5 = esf->t5; + arch_blk.r.t6 = esf->t6; + arch_blk.r.a0 = esf->a0; + arch_blk.r.a1 = esf->a1; + arch_blk.r.a2 = esf->a2; + arch_blk.r.a3 = esf->a3; + arch_blk.r.a4 = esf->a4; + arch_blk.r.a5 = esf->a5; + arch_blk.r.a6 = esf->a6; + arch_blk.r.a7 = esf->a7; + arch_blk.r.pc = esf->mepc; + + /* Send for output */ + coredump_buffer_output((uint8_t *)&hdr, sizeof(hdr)); + coredump_buffer_output((uint8_t *)&arch_blk, sizeof(arch_blk)); +} + +uint16_t arch_coredump_tgt_code_get(void) +{ + return COREDUMP_TGT_RISC_V; +} diff --git a/include/debug/coredump.h b/include/debug/coredump.h index 628af94945b..0f2e3b2a433 100644 --- a/include/debug/coredump.h +++ b/include/debug/coredump.h @@ -77,6 +77,7 @@ enum coredump_tgt_code { COREDUMP_TGT_X86, COREDUMP_TGT_X86_64, COREDUMP_TGT_ARM_CORTEX_M, + COREDUMP_TGT_RISC_V, }; /* Coredump header */ diff --git a/scripts/coredump/gdbstubs/__init__.py b/scripts/coredump/gdbstubs/__init__.py index 61f0aae24f7..b52065e85bd 100644 --- a/scripts/coredump/gdbstubs/__init__.py +++ b/scripts/coredump/gdbstubs/__init__.py @@ -7,12 +7,14 @@ 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 +from gdbstubs.arch.risc_v import GdbStub_RISC_V class TgtCode: UNKNOWN = 0 X86 = 1 X86_64 = 2 ARM_CORTEX_M = 3 + RISC_V = 4 def get_gdbstub(logfile, elffile): stub = None @@ -25,5 +27,7 @@ def get_gdbstub(logfile, elffile): stub = GdbStub_x86_64(logfile=logfile, elffile=elffile) elif tgt_code == TgtCode.ARM_CORTEX_M: stub = GdbStub_ARM_CortexM(logfile=logfile, elffile=elffile) + elif tgt_code == TgtCode.RISC_V: + stub = GdbStub_RISC_V(logfile=logfile, elffile=elffile) return stub diff --git a/scripts/coredump/gdbstubs/arch/risc_v.py b/scripts/coredump/gdbstubs/arch/risc_v.py new file mode 100644 index 00000000000..7eb4b924316 --- /dev/null +++ b/scripts/coredump/gdbstubs/arch/risc_v.py @@ -0,0 +1,114 @@ +#!/usr/bin/env python3 +# +# Copyright (c) 2021 Facebook, Inc. and its affiliates +# +# SPDX-License-Identifier: Apache-2.0 + +import binascii +import logging +import struct + +from gdbstubs.gdbstub import GdbStub + + +logger = logging.getLogger("gdbstub") + + +class RegNum(): + ZERO = 0 + RA = 1 + SP = 2 + GP = 3 + TP = 4 + T0 = 5 + T1 = 6 + T2 = 7 + FP = 8 + S1 = 9 + A0 = 10 + A1 = 11 + A2 = 12 + A3 = 13 + A4 = 14 + A5 = 15 + A6 = 16 + A7 = 17 + S2 = 18 + S3 = 19 + S4 = 20 + S5 = 21 + S6 = 22 + S7 = 23 + S8 = 24 + S9 = 25 + S10 = 26 + S11 = 27 + T3 = 28 + T4 = 29 + T5 = 30 + T6 = 31 + PC = 32 + + +class GdbStub_RISC_V(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 not sent for the registers + # currently handled in this file so we can safely reply "xxxxxxxx" here. + self.put_gdb_packet(b'x' * 8) diff --git a/tests/subsys/cpp/libcxx/src/main.cpp b/tests/subsys/cpp/libcxx/src/main.cpp index 9fa6120e4f2..feb6896382c 100644 --- a/tests/subsys/cpp/libcxx/src/main.cpp +++ b/tests/subsys/cpp/libcxx/src/main.cpp @@ -67,7 +67,7 @@ static void test_make_unique(void) zassert_equal(make_unique_data::dtors, 1, "dtor count not incremented"); } -#if defined(CONFIG_EXCEPTIONS) +#if defined(CONFIG_EXCEPTIONS) && !defined(CONFIG_BOARD_M2GL025_MIV) static void throw_exception(void) { throw 42; diff --git a/tests/subsys/debug/coredump/src/main.c b/tests/subsys/debug/coredump/src/main.c index f18cb66ef30..471a6196c5e 100644 --- a/tests/subsys/debug/coredump/src/main.c +++ b/tests/subsys/debug/coredump/src/main.c @@ -6,10 +6,18 @@ #include #include +#include void func_3(uint32_t *addr) { -#if !defined(CONFIG_CPU_CORTEX_M) +#if defined(CONFIG_BOARD_M2GL025_MIV) || defined(CONFIG_BOARD_HIFIVE1) + ARG_UNUSED(addr); + /* Call coredump() directly so Renode doesn't pause execution */ + z_arch_esf_t esf; + struct k_thread kthread; + + coredump(1, &esf, &kthread); +#elif !defined(CONFIG_CPU_CORTEX_M) /* For null pointer reference */ *addr = 0; #else