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 <daniel.leung@intel.com>
This commit is contained in:
parent
8fbb14ef50
commit
181d07321f
8 changed files with 180 additions and 0 deletions
|
@ -27,6 +27,7 @@ config ARC
|
||||||
config ARM
|
config ARM
|
||||||
bool
|
bool
|
||||||
select ARCH_IS_SET
|
select ARCH_IS_SET
|
||||||
|
select ARCH_SUPPORTS_COREDUMP if CPU_CORTEX_M
|
||||||
select HAS_DTS
|
select HAS_DTS
|
||||||
# FIXME: current state of the code for all ARM requires this, but
|
# FIXME: current state of the code for all ARM requires this, but
|
||||||
# is really only necessary for Cortex-M with ARM MPU!
|
# is really only necessary for Cortex-M with ARM MPU!
|
||||||
|
|
|
@ -13,6 +13,8 @@ zephyr_library_sources(
|
||||||
thread_abort.c
|
thread_abort.c
|
||||||
)
|
)
|
||||||
|
|
||||||
|
zephyr_library_sources_ifdef(CONFIG_DEBUG_COREDUMP coredump.c)
|
||||||
|
|
||||||
if (CONFIG_SW_VECTOR_RELAY)
|
if (CONFIG_SW_VECTOR_RELAY)
|
||||||
if (CONFIG_CPU_CORTEX_M_HAS_VTOR)
|
if (CONFIG_CPU_CORTEX_M_HAS_VTOR)
|
||||||
set(relay_vector_table_sort_key relay_vectors)
|
set(relay_vector_table_sort_key relay_vectors)
|
||||||
|
|
75
arch/arm/core/aarch32/cortex_m/coredump.c
Normal file
75
arch/arm/core/aarch32/cortex_m/coredump.c
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020 Intel Corporation.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <debug/coredump.h>
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
|
@ -953,6 +953,10 @@ void z_arm_fault(uint32_t msp, uint32_t psp, uint32_t exc_return)
|
||||||
__ASSERT(esf != NULL,
|
__ASSERT(esf != NULL,
|
||||||
"ESF could not be retrieved successfully. Shall never occur.");
|
"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);
|
reason = fault_handle(esf, fault, &recoverable);
|
||||||
if (recoverable) {
|
if (recoverable) {
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -91,6 +91,8 @@ struct __esf {
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
extern uint32_t z_arm_coredump_fault_sp;
|
||||||
|
|
||||||
typedef struct __esf z_arch_esf_t;
|
typedef struct __esf z_arch_esf_t;
|
||||||
|
|
||||||
#ifdef CONFIG_CPU_CORTEX_M
|
#ifdef CONFIG_CPU_CORTEX_M
|
||||||
|
|
|
@ -25,6 +25,7 @@ enum z_coredump_tgt_code {
|
||||||
COREDUMP_TGT_UNKNOWN = 0,
|
COREDUMP_TGT_UNKNOWN = 0,
|
||||||
COREDUMP_TGT_X86,
|
COREDUMP_TGT_X86,
|
||||||
COREDUMP_TGT_X86_64,
|
COREDUMP_TGT_X86_64,
|
||||||
|
COREDUMP_TGT_ARM_CORTEX_M,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Coredump header */
|
/* Coredump header */
|
||||||
|
|
|
@ -6,11 +6,13 @@
|
||||||
|
|
||||||
from gdbstubs.arch.x86 import GdbStub_x86
|
from gdbstubs.arch.x86 import GdbStub_x86
|
||||||
from gdbstubs.arch.x86_64 import GdbStub_x86_64
|
from gdbstubs.arch.x86_64 import GdbStub_x86_64
|
||||||
|
from gdbstubs.arch.arm_cortex_m import GdbStub_ARM_CortexM
|
||||||
|
|
||||||
class TgtCode:
|
class TgtCode:
|
||||||
UNKNOWN = 0
|
UNKNOWN = 0
|
||||||
X86 = 1
|
X86 = 1
|
||||||
X86_64 = 2
|
X86_64 = 2
|
||||||
|
ARM_CORTEX_M = 3
|
||||||
|
|
||||||
def get_gdbstub(logfile, elffile):
|
def get_gdbstub(logfile, elffile):
|
||||||
stub = None
|
stub = None
|
||||||
|
@ -21,5 +23,7 @@ def get_gdbstub(logfile, elffile):
|
||||||
stub = GdbStub_x86(logfile=logfile, elffile=elffile)
|
stub = GdbStub_x86(logfile=logfile, elffile=elffile)
|
||||||
elif tgt_code == TgtCode.X86_64:
|
elif tgt_code == TgtCode.X86_64:
|
||||||
stub = GdbStub_x86_64(logfile=logfile, elffile=elffile)
|
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
|
return stub
|
||||||
|
|
91
scripts/coredump/gdbstubs/arch/arm_cortex_m.py
Normal file
91
scripts/coredump/gdbstubs/arch/arm_cortex_m.py
Normal file
|
@ -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 = "<IIIIIIIII"
|
||||||
|
|
||||||
|
GDB_SIGNAL_DEFAULT = 7
|
||||||
|
|
||||||
|
GDB_G_PKT_NUM_REGS = 17
|
||||||
|
|
||||||
|
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.R0] = tu[0]
|
||||||
|
self.registers[RegNum.R1] = tu[1]
|
||||||
|
self.registers[RegNum.R2] = tu[2]
|
||||||
|
self.registers[RegNum.R3] = tu[3]
|
||||||
|
self.registers[RegNum.R12] = tu[4]
|
||||||
|
self.registers[RegNum.LR] = tu[5]
|
||||||
|
self.registers[RegNum.PC] = tu[6]
|
||||||
|
self.registers[RegNum.XPSR] = tu[7]
|
||||||
|
self.registers[RegNum.SP] = tu[8]
|
||||||
|
|
||||||
|
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 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)
|
Loading…
Add table
Add a link
Reference in a new issue