coredump: add support for RISC-V
This adds the necessary bits in arch code, and Python scripts to enable coredump support for RISC-V Signed-off-by: Mark Holden <mholden@fb.com>
This commit is contained in:
parent
ed68ef5678
commit
1a697ccf59
8 changed files with 219 additions and 2 deletions
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
88
arch/riscv/core/coredump.c
Normal file
88
arch/riscv/core/coredump.c
Normal file
|
@ -0,0 +1,88 @@
|
|||
/*
|
||||
* Copyright (c) 2021 Facebook, Inc. and its affiliates
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <debug/coredump.h>
|
||||
|
||||
#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;
|
||||
}
|
|
@ -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 */
|
||||
|
|
|
@ -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
|
||||
|
|
114
scripts/coredump/gdbstubs/arch/risc_v.py
Normal file
114
scripts/coredump/gdbstubs/arch/risc_v.py
Normal file
|
@ -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 = "<IIIIIIIIIIIIIIIIII"
|
||||
|
||||
GDB_SIGNAL_DEFAULT = 7
|
||||
|
||||
GDB_G_PKT_NUM_REGS = 33
|
||||
|
||||
def __init__(self, logfile, elffile):
|
||||
super().__init__(logfile=logfile, elffile=elffile)
|
||||
self.registers = None
|
||||
self.gdb_signal = self.GDB_SIGNAL_DEFAULT
|
||||
|
||||
self.parse_arch_data_block()
|
||||
|
||||
def parse_arch_data_block(self):
|
||||
arch_data_blk = self.logfile.get_arch_data()['data']
|
||||
tu = struct.unpack(self.ARCH_DATA_BLK_STRUCT, arch_data_blk)
|
||||
|
||||
self.registers = dict()
|
||||
|
||||
self.registers[RegNum.RA] = tu[0]
|
||||
self.registers[RegNum.TP] = tu[1]
|
||||
self.registers[RegNum.T0] = tu[2]
|
||||
self.registers[RegNum.T1] = tu[3]
|
||||
self.registers[RegNum.T2] = tu[4]
|
||||
self.registers[RegNum.A0] = tu[5]
|
||||
self.registers[RegNum.A1] = tu[6]
|
||||
self.registers[RegNum.A2] = tu[7]
|
||||
self.registers[RegNum.A3] = tu[8]
|
||||
self.registers[RegNum.A4] = tu[9]
|
||||
self.registers[RegNum.A5] = tu[10]
|
||||
self.registers[RegNum.A6] = tu[11]
|
||||
self.registers[RegNum.A7] = tu[12]
|
||||
self.registers[RegNum.T3] = tu[13]
|
||||
self.registers[RegNum.T4] = tu[14]
|
||||
self.registers[RegNum.T5] = tu[15]
|
||||
self.registers[RegNum.T6] = tu[16]
|
||||
self.registers[RegNum.PC] = tu[17]
|
||||
|
||||
def handle_register_group_read_packet(self):
|
||||
reg_fmt = "<I"
|
||||
|
||||
idx = 0
|
||||
pkt = b''
|
||||
|
||||
while idx < self.GDB_G_PKT_NUM_REGS:
|
||||
if idx in self.registers:
|
||||
bval = struct.pack(reg_fmt, self.registers[idx])
|
||||
pkt += binascii.hexlify(bval)
|
||||
else:
|
||||
# Register not in coredump -> 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 "<unavailable>". '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)
|
|
@ -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;
|
||||
|
|
|
@ -6,10 +6,18 @@
|
|||
|
||||
#include <zephyr.h>
|
||||
#include <sys/printk.h>
|
||||
#include <debug/coredump.h>
|
||||
|
||||
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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue