Skip to content

Commit 6622735

Browse files
Roberto Medinacarlescufi
Roberto Medina
authored andcommitted
arch: arm64: add support for coredump
* Add support for coredump on ARM64 architectures. * Add the script used for post-processing coredump output. Signed-off-by: Marcelo Ruaro <[email protected]> Signed-off-by: Rodrigo Cataldo <[email protected]> Signed-off-by: Roberto Medina <[email protected]>
1 parent 33e3ddd commit 6622735

File tree

6 files changed

+243
-0
lines changed

6 files changed

+243
-0
lines changed

arch/Kconfig

+1
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ config ARM64
4343
select ARCH_IS_SET
4444
select 64BIT
4545
select HAS_DTS
46+
select ARCH_SUPPORTS_COREDUMP
4647
select HAS_ARM_SMCCC
4748
select ARCH_HAS_THREAD_LOCAL_STORAGE
4849
select USE_SWITCH

arch/arm64/core/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ zephyr_library_sources_ifdef(CONFIG_THREAD_LOCAL_STORAGE tls.c)
3737
zephyr_library_sources_ifdef(CONFIG_HAS_ARM_SMCCC smccc-call.S)
3838
zephyr_library_sources_ifdef(CONFIG_AARCH64_IMAGE_HEADER header.S)
3939
zephyr_library_sources_ifdef(CONFIG_SEMIHOST semihost.c)
40+
zephyr_library_sources_ifdef(CONFIG_DEBUG_COREDUMP coredump.c)
4041
if ((CONFIG_MP_MAX_NUM_CPUS GREATER 1) OR (CONFIG_SMP))
4142
zephyr_library_sources(smp.c)
4243
endif ()

arch/arm64/core/coredump.c

+105
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
/*
2+
* Copyright (c) 2022 Huawei Technologies SASU
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#include <string.h>
8+
#include <zephyr/debug/coredump.h>
9+
10+
/* Identify the version of this block (in case of architecture changes).
11+
* To be interpreted by the target architecture specific block parser.
12+
*/
13+
#define ARCH_HDR_VER 1
14+
15+
/* Structure to store the architecture registers passed arch_coredump_info_dump
16+
* As callee saved registers are not provided in z_arch_esf_t structure in Zephyr
17+
* we just need 22 registers.
18+
*/
19+
struct arm64_arch_block {
20+
struct {
21+
uint64_t x0;
22+
uint64_t x1;
23+
uint64_t x2;
24+
uint64_t x3;
25+
uint64_t x4;
26+
uint64_t x5;
27+
uint64_t x6;
28+
uint64_t x7;
29+
uint64_t x8;
30+
uint64_t x9;
31+
uint64_t x10;
32+
uint64_t x11;
33+
uint64_t x12;
34+
uint64_t x13;
35+
uint64_t x14;
36+
uint64_t x15;
37+
uint64_t x16;
38+
uint64_t x17;
39+
uint64_t x18;
40+
uint64_t lr;
41+
uint64_t spsr;
42+
uint64_t elr;
43+
} r;
44+
} __packed;
45+
46+
47+
/*
48+
* Register block takes up too much stack space
49+
* if defined within function. So define it here.
50+
*/
51+
static struct arm64_arch_block arch_blk;
52+
53+
void arch_coredump_info_dump(const z_arch_esf_t *esf)
54+
{
55+
/* Target architecture information header */
56+
/* Information just relevant to the python parser */
57+
struct coredump_arch_hdr_t hdr = {
58+
.id = COREDUMP_ARCH_HDR_ID,
59+
.hdr_version = ARCH_HDR_VER,
60+
.num_bytes = sizeof(arch_blk),
61+
};
62+
63+
/* Nothing to process */
64+
if (esf == NULL) {
65+
return;
66+
}
67+
68+
(void)memset(&arch_blk, 0, sizeof(arch_blk));
69+
70+
/*
71+
* Copies the thread registers to a memory block that will be printed out
72+
* The thread registers are already provided by structure z_arch_esf_t
73+
*/
74+
arch_blk.r.x0 = esf->x0;
75+
arch_blk.r.x1 = esf->x1;
76+
arch_blk.r.x2 = esf->x2;
77+
arch_blk.r.x3 = esf->x3;
78+
arch_blk.r.x4 = esf->x4;
79+
arch_blk.r.x5 = esf->x5;
80+
arch_blk.r.x6 = esf->x6;
81+
arch_blk.r.x7 = esf->x7;
82+
arch_blk.r.x8 = esf->x8;
83+
arch_blk.r.x9 = esf->x9;
84+
arch_blk.r.x10 = esf->x10;
85+
arch_blk.r.x11 = esf->x11;
86+
arch_blk.r.x12 = esf->x12;
87+
arch_blk.r.x13 = esf->x13;
88+
arch_blk.r.x14 = esf->x14;
89+
arch_blk.r.x15 = esf->x15;
90+
arch_blk.r.x16 = esf->x16;
91+
arch_blk.r.x17 = esf->x17;
92+
arch_blk.r.x18 = esf->x18;
93+
arch_blk.r.lr = esf->lr;
94+
arch_blk.r.spsr = esf->spsr;
95+
arch_blk.r.elr = esf->elr;
96+
97+
/* Send for output */
98+
coredump_buffer_output((uint8_t *)&hdr, sizeof(hdr));
99+
coredump_buffer_output((uint8_t *)&arch_blk, sizeof(arch_blk));
100+
}
101+
102+
uint16_t arch_coredump_tgt_code_get(void)
103+
{
104+
return COREDUMP_TGT_ARM64;
105+
}

include/zephyr/debug/coredump.h

+1
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ enum coredump_tgt_code {
123123
COREDUMP_TGT_ARM_CORTEX_M,
124124
COREDUMP_TGT_RISC_V,
125125
COREDUMP_TGT_XTENSA,
126+
COREDUMP_TGT_ARM64,
126127
};
127128

128129
/* Coredump header */

scripts/coredump/gdbstubs/__init__.py

+4
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
from gdbstubs.arch.arm_cortex_m import GdbStub_ARM_CortexM
1010
from gdbstubs.arch.risc_v import GdbStub_RISC_V
1111
from gdbstubs.arch.xtensa import GdbStub_Xtensa
12+
from gdbstubs.arch.arm64 import GdbStub_ARM64
1213

1314
class TgtCode:
1415
UNKNOWN = 0
@@ -17,6 +18,7 @@ class TgtCode:
1718
ARM_CORTEX_M = 3
1819
RISC_V = 4
1920
XTENSA = 5
21+
ARM64 = 6
2022

2123
def get_gdbstub(logfile, elffile):
2224
stub = None
@@ -33,5 +35,7 @@ def get_gdbstub(logfile, elffile):
3335
stub = GdbStub_RISC_V(logfile=logfile, elffile=elffile)
3436
elif tgt_code == TgtCode.XTENSA:
3537
stub = GdbStub_Xtensa(logfile=logfile, elffile=elffile)
38+
elif tgt_code == TgtCode.ARM64:
39+
stub = GdbStub_ARM64(logfile=logfile, elffile=elffile)
3640

3741
return stub
+131
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
#!/usr/bin/env python3
2+
#
3+
# Copyright (c) 2022 Huawei Technologies SASU
4+
#
5+
# SPDX-License-Identifier: Apache-2.0
6+
7+
import binascii
8+
import logging
9+
import struct
10+
11+
from gdbstubs.gdbstub import GdbStub
12+
13+
14+
logger = logging.getLogger("gdbstub")
15+
16+
17+
class RegNum():
18+
X0 = 0 # X0-X29 - 30 GP registers
19+
X1 = 1
20+
X2 = 2
21+
X3 = 3
22+
X4 = 4
23+
X5 = 5
24+
X6 = 6
25+
X7 = 7
26+
X8 = 8
27+
X9 = 9
28+
X10 = 10
29+
X11 = 11
30+
X12 = 12
31+
X13 = 13
32+
X14 = 14
33+
X15 = 15
34+
X16 = 16
35+
X17 = 17
36+
X18 = 18
37+
X19 = 19
38+
X20 = 20
39+
X21 = 21
40+
X22 = 22
41+
X23 = 23
42+
X24 = 24
43+
X25 = 25
44+
X26 = 26
45+
X27 = 27
46+
X28 = 28
47+
X29 = 29 # Frame pointer register
48+
LR = 30 # X30 Link Register(LR)
49+
SP_EL0 = 31 # Stack pointer EL0 (SP_EL0)
50+
PC = 32 # Program Counter (PC)
51+
52+
53+
class GdbStub_ARM64(GdbStub):
54+
ARCH_DATA_BLK_STRUCT = "<QQQQQQQQQQQQQQQQQQQQQQ"
55+
56+
# Default signal used by all other script, just using the same
57+
GDB_SIGNAL_DEFAULT = 7
58+
59+
# The number of registers expected by GDB
60+
GDB_G_PKT_NUM_REGS = 33
61+
62+
63+
def __init__(self, logfile, elffile):
64+
super().__init__(logfile=logfile, elffile=elffile)
65+
self.registers = None
66+
self.gdb_signal = self.GDB_SIGNAL_DEFAULT
67+
68+
self.parse_arch_data_block()
69+
70+
def parse_arch_data_block(self):
71+
72+
arch_data_blk = self.logfile.get_arch_data()['data']
73+
74+
tu = struct.unpack(self.ARCH_DATA_BLK_STRUCT, arch_data_blk)
75+
76+
self.registers = dict()
77+
78+
self.registers[RegNum.X0] = tu[0]
79+
self.registers[RegNum.X1] = tu[1]
80+
self.registers[RegNum.X2] = tu[2]
81+
self.registers[RegNum.X3] = tu[3]
82+
self.registers[RegNum.X4] = tu[4]
83+
self.registers[RegNum.X5] = tu[5]
84+
self.registers[RegNum.X6] = tu[6]
85+
self.registers[RegNum.X7] = tu[7]
86+
self.registers[RegNum.X8] = tu[8]
87+
self.registers[RegNum.X9] = tu[9]
88+
self.registers[RegNum.X10] = tu[10]
89+
self.registers[RegNum.X11] = tu[11]
90+
self.registers[RegNum.X12] = tu[12]
91+
self.registers[RegNum.X13] = tu[13]
92+
self.registers[RegNum.X14] = tu[14]
93+
self.registers[RegNum.X15] = tu[15]
94+
self.registers[RegNum.X16] = tu[16]
95+
self.registers[RegNum.X17] = tu[17]
96+
self.registers[RegNum.X18] = tu[18]
97+
98+
# Callee saved registers are not provided in __esf structure
99+
# So they will be omitted (set to undefined) when stub generates the
100+
# packet in handle_register_group_read_packet.
101+
102+
self.registers[RegNum.LR] = tu[19]
103+
self.registers[RegNum.SP_EL0] = tu[20]
104+
self.registers[RegNum.PC] = tu[21]
105+
106+
107+
def handle_register_group_read_packet(self):
108+
reg_fmt = "<Q"
109+
110+
idx = 0
111+
pkt = b''
112+
113+
while idx < self.GDB_G_PKT_NUM_REGS:
114+
if idx in self.registers:
115+
bval = struct.pack(reg_fmt, self.registers[idx])
116+
pkt += binascii.hexlify(bval)
117+
else:
118+
# Register not in coredump -> unknown value
119+
# Send in "xxxxxxxx"
120+
pkt += b'x' * 16
121+
122+
idx += 1
123+
124+
self.put_gdb_packet(pkt)
125+
126+
def handle_register_single_read_packet(self, pkt):
127+
# Mark registers as "<unavailable>".
128+
# 'p' packets are usually used for registers
129+
# other than the general ones (e.g. eax, ebx)
130+
# so we can safely reply "xxxxxxxx" here.
131+
self.put_gdb_packet(b'x' * 16)

0 commit comments

Comments
 (0)