Skip to content

Commit

Permalink
arch: arm64: add support for coredump
Browse files Browse the repository at this point in the history
* Add support for coredump on ARM64 architectures.
* Add the script used for post-processing coredump output.

Signed-off-by: Marcelo Ruaro <marcelo.ruaro@huawei.com>
Signed-off-by: Rodrigo Cataldo <rodrigo.cataldo@huawei.com>
Signed-off-by: Roberto Medina <roberto.medina@huawei.com>
  • Loading branch information
Roberto Medina authored and carlescufi committed Jul 3, 2023
1 parent 33e3ddd commit 6622735
Show file tree
Hide file tree
Showing 6 changed files with 243 additions and 0 deletions.
1 change: 1 addition & 0 deletions arch/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ config ARM64
select ARCH_IS_SET
select 64BIT
select HAS_DTS
select ARCH_SUPPORTS_COREDUMP
select HAS_ARM_SMCCC
select ARCH_HAS_THREAD_LOCAL_STORAGE
select USE_SWITCH
Expand Down
1 change: 1 addition & 0 deletions arch/arm64/core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ zephyr_library_sources_ifdef(CONFIG_THREAD_LOCAL_STORAGE tls.c)
zephyr_library_sources_ifdef(CONFIG_HAS_ARM_SMCCC smccc-call.S)
zephyr_library_sources_ifdef(CONFIG_AARCH64_IMAGE_HEADER header.S)
zephyr_library_sources_ifdef(CONFIG_SEMIHOST semihost.c)
zephyr_library_sources_ifdef(CONFIG_DEBUG_COREDUMP coredump.c)
if ((CONFIG_MP_MAX_NUM_CPUS GREATER 1) OR (CONFIG_SMP))
zephyr_library_sources(smp.c)
endif ()
Expand Down
105 changes: 105 additions & 0 deletions arch/arm64/core/coredump.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
/*
* Copyright (c) 2022 Huawei Technologies SASU
*
* SPDX-License-Identifier: Apache-2.0
*/

#include <string.h>
#include <zephyr/debug/coredump.h>

/* Identify the version of this block (in case of architecture changes).
* To be interpreted by the target architecture specific block parser.
*/
#define ARCH_HDR_VER 1

/* Structure to store the architecture registers passed arch_coredump_info_dump
* As callee saved registers are not provided in z_arch_esf_t structure in Zephyr
* we just need 22 registers.
*/
struct arm64_arch_block {
struct {
uint64_t x0;
uint64_t x1;
uint64_t x2;
uint64_t x3;
uint64_t x4;
uint64_t x5;
uint64_t x6;
uint64_t x7;
uint64_t x8;
uint64_t x9;
uint64_t x10;
uint64_t x11;
uint64_t x12;
uint64_t x13;
uint64_t x14;
uint64_t x15;
uint64_t x16;
uint64_t x17;
uint64_t x18;
uint64_t lr;
uint64_t spsr;
uint64_t elr;
} r;
} __packed;


/*
* Register block takes up too much stack space
* if defined within function. So define it here.
*/
static struct arm64_arch_block arch_blk;

void arch_coredump_info_dump(const z_arch_esf_t *esf)
{
/* Target architecture information header */
/* Information just relevant to the python parser */
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));

/*
* Copies the thread registers to a memory block that will be printed out
* The thread registers are already provided by structure z_arch_esf_t
*/
arch_blk.r.x0 = esf->x0;
arch_blk.r.x1 = esf->x1;
arch_blk.r.x2 = esf->x2;
arch_blk.r.x3 = esf->x3;
arch_blk.r.x4 = esf->x4;
arch_blk.r.x5 = esf->x5;
arch_blk.r.x6 = esf->x6;
arch_blk.r.x7 = esf->x7;
arch_blk.r.x8 = esf->x8;
arch_blk.r.x9 = esf->x9;
arch_blk.r.x10 = esf->x10;
arch_blk.r.x11 = esf->x11;
arch_blk.r.x12 = esf->x12;
arch_blk.r.x13 = esf->x13;
arch_blk.r.x14 = esf->x14;
arch_blk.r.x15 = esf->x15;
arch_blk.r.x16 = esf->x16;
arch_blk.r.x17 = esf->x17;
arch_blk.r.x18 = esf->x18;
arch_blk.r.lr = esf->lr;
arch_blk.r.spsr = esf->spsr;
arch_blk.r.elr = esf->elr;

/* 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_ARM64;
}
1 change: 1 addition & 0 deletions include/zephyr/debug/coredump.h
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ enum coredump_tgt_code {
COREDUMP_TGT_ARM_CORTEX_M,
COREDUMP_TGT_RISC_V,
COREDUMP_TGT_XTENSA,
COREDUMP_TGT_ARM64,
};

/* Coredump header */
Expand Down
4 changes: 4 additions & 0 deletions scripts/coredump/gdbstubs/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from gdbstubs.arch.arm_cortex_m import GdbStub_ARM_CortexM
from gdbstubs.arch.risc_v import GdbStub_RISC_V
from gdbstubs.arch.xtensa import GdbStub_Xtensa
from gdbstubs.arch.arm64 import GdbStub_ARM64

class TgtCode:
UNKNOWN = 0
Expand All @@ -17,6 +18,7 @@ class TgtCode:
ARM_CORTEX_M = 3
RISC_V = 4
XTENSA = 5
ARM64 = 6

def get_gdbstub(logfile, elffile):
stub = None
Expand All @@ -33,5 +35,7 @@ def get_gdbstub(logfile, elffile):
stub = GdbStub_RISC_V(logfile=logfile, elffile=elffile)
elif tgt_code == TgtCode.XTENSA:
stub = GdbStub_Xtensa(logfile=logfile, elffile=elffile)
elif tgt_code == TgtCode.ARM64:
stub = GdbStub_ARM64(logfile=logfile, elffile=elffile)

return stub
131 changes: 131 additions & 0 deletions scripts/coredump/gdbstubs/arch/arm64.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
#!/usr/bin/env python3
#
# Copyright (c) 2022 Huawei Technologies SASU
#
# SPDX-License-Identifier: Apache-2.0

import binascii
import logging
import struct

from gdbstubs.gdbstub import GdbStub


logger = logging.getLogger("gdbstub")


class RegNum():
X0 = 0 # X0-X29 - 30 GP registers
X1 = 1
X2 = 2
X3 = 3
X4 = 4
X5 = 5
X6 = 6
X7 = 7
X8 = 8
X9 = 9
X10 = 10
X11 = 11
X12 = 12
X13 = 13
X14 = 14
X15 = 15
X16 = 16
X17 = 17
X18 = 18
X19 = 19
X20 = 20
X21 = 21
X22 = 22
X23 = 23
X24 = 24
X25 = 25
X26 = 26
X27 = 27
X28 = 28
X29 = 29 # Frame pointer register
LR = 30 # X30 Link Register(LR)
SP_EL0 = 31 # Stack pointer EL0 (SP_EL0)
PC = 32 # Program Counter (PC)


class GdbStub_ARM64(GdbStub):
ARCH_DATA_BLK_STRUCT = "<QQQQQQQQQQQQQQQQQQQQQQ"

# Default signal used by all other script, just using the same
GDB_SIGNAL_DEFAULT = 7

# The number of registers expected by GDB
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.X0] = tu[0]
self.registers[RegNum.X1] = tu[1]
self.registers[RegNum.X2] = tu[2]
self.registers[RegNum.X3] = tu[3]
self.registers[RegNum.X4] = tu[4]
self.registers[RegNum.X5] = tu[5]
self.registers[RegNum.X6] = tu[6]
self.registers[RegNum.X7] = tu[7]
self.registers[RegNum.X8] = tu[8]
self.registers[RegNum.X9] = tu[9]
self.registers[RegNum.X10] = tu[10]
self.registers[RegNum.X11] = tu[11]
self.registers[RegNum.X12] = tu[12]
self.registers[RegNum.X13] = tu[13]
self.registers[RegNum.X14] = tu[14]
self.registers[RegNum.X15] = tu[15]
self.registers[RegNum.X16] = tu[16]
self.registers[RegNum.X17] = tu[17]
self.registers[RegNum.X18] = tu[18]

# Callee saved registers are not provided in __esf structure
# So they will be omitted (set to undefined) when stub generates the
# packet in handle_register_group_read_packet.

self.registers[RegNum.LR] = tu[19]
self.registers[RegNum.SP_EL0] = tu[20]
self.registers[RegNum.PC] = tu[21]


def handle_register_group_read_packet(self):
reg_fmt = "<Q"

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' * 16

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' * 16)

0 comments on commit 6622735

Please sign in to comment.