zephyr/scripts/coredump/gdbstubs/arch/xtensa.py
Daniel Leung a819bfb2d5 xtensa: rename z_xtensa to simply xtensa
Rename the remaining z_xtensa stuff as these are (mostly)
under arch/xtensa.

Signed-off-by: Daniel Leung <daniel.leung@intel.com>
2023-12-13 09:41:24 +01:00

516 lines
14 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python3
#
# Copyright (c) 2021 Intel Corporation
#
# SPDX-License-Identifier: Apache-2.0
import binascii
import logging
import struct
import sys
from enum import Enum
from gdbstubs.gdbstub import GdbStub
logger = logging.getLogger("gdbstub")
# Matches same in coredump.c
XTENSA_BLOCK_HDR_DUMMY_SOC = 255
# Must match --soc arg options; see get_soc
class XtensaSoc(Enum):
UNKNOWN = 0
SAMPLE_CONTROLLER = 1
ESP32 = 2
INTEL_ADSP_CAVS = 3
ESP32S2 = 4
ESP32S3 = 5
DC233C = 6
# The previous version of this script didn't need to know
# what toolchain Zephyr was built with; it assumed sample_controller
# was built with the Zephyr SDK and ESP32 with Espressif's.
# However, if a SOC can be built by two separate toolchains,
# there is a chance that the GDBs provided by the toolchains will
# assign different indices to the same registers. For example, the
# Intel ADSP family of SOCs can be built with both Zephyr's
# SDK and Cadence's XCC toolchain. With the same SOC APL,
# the SDK's GDB assigns PC the index 0, while XCC's GDB assigns
# it the index 32.
#
# (The Espressif value isn't really required, since ESP32 can
# only be built with Espressif's toolchain, but it's included for
# completeness.)
class XtensaToolchain(Enum):
UNKNOWN = 0
ZEPHYR = 1
XCC = 2
ESPRESSIF = 3
def get_gdb_reg_definition(soc, toolchain):
if soc == XtensaSoc.SAMPLE_CONTROLLER:
return GdbRegDef_Sample_Controller
elif soc == XtensaSoc.ESP32:
return GdbRegDef_ESP32
elif soc == XtensaSoc.INTEL_ADSP_CAVS:
if toolchain == XtensaToolchain.ZEPHYR:
return GdbRegDef_Intel_Adsp_CAVS_Zephyr
elif toolchain == XtensaToolchain.XCC:
return GdbRegDef_Intel_Adsp_CAVS_XCC
elif toolchain == XtensaToolchain.ESPRESSIF:
logger.error("Can't use espressif toolchain with CAVS. " +
"Use zephyr or xcc instead. Exiting...")
sys.exit(1)
else:
raise NotImplementedError
elif soc == XtensaSoc.ESP32S2:
return GdbRegDef_ESP32S2
elif soc == XtensaSoc.ESP32S3:
return GdbRegDef_ESP32S3
elif soc == XtensaSoc.DC233C:
return GdbRegDef_DC233C
else:
raise NotImplementedError
class ExceptionCodes(Enum):
# Matches arch/xtensa/core/fatal.c->xtensa_exccause
ILLEGAL_INSTRUCTION = 0
# Syscall not fatal
INSTR_FETCH_ERROR = 2
LOAD_STORE_ERROR = 3
# Level-1 interrupt not fatal
ALLOCA = 5
DIVIDE_BY_ZERO = 6
PRIVILEGED = 8
LOAD_STORE_ALIGNMENT = 9
INSTR_PIF_DATA_ERROR = 12
LOAD_STORE_PIF_DATA_ERROR = 13
INSTR_PIF_ADDR_ERROR = 14
LOAD_STORE_PIF_ADDR_ERROR = 15
INSTR_TLB_MISS = 16
INSTR_TLB_MULTI_HIT = 17
INSTR_FETCH_PRIVILEGE = 18
INST_FETCH_PROHIBITED = 20
LOAD_STORE_TLB_MISS = 24
LOAD_STORE_TLB_MULTI_HIT = 25
LOAD_STORE_PRIVILEGE = 26
LOAD_PROHIBITED = 28
STORE_PROHIBITED = 29
# Coprocessor disabled spans 32 - 39
COPROCESSOR_DISABLED_START = 32
COPROCESSOR_DISABLED_END = 39
Z_EXCEPT_REASON = 63
# Others (reserved / unknown) map to default signal
class GdbStub_Xtensa(GdbStub):
GDB_SIGNAL_DEFAULT = 7
# Mapping based on section 4.4.1.5 of the
# Xtensa ISA Reference Manual (Table 464. Exception Causes)
# Somewhat arbitrary; included only because GDB requests it
GDB_SIGNAL_MAPPING = {
ExceptionCodes.ILLEGAL_INSTRUCTION: 4,
ExceptionCodes.INSTR_FETCH_ERROR: 7,
ExceptionCodes.LOAD_STORE_ERROR: 11,
ExceptionCodes.ALLOCA: 7,
ExceptionCodes.DIVIDE_BY_ZERO: 8,
ExceptionCodes.PRIVILEGED: 11,
ExceptionCodes.LOAD_STORE_ALIGNMENT: 7,
ExceptionCodes.INSTR_PIF_DATA_ERROR: 7,
ExceptionCodes.LOAD_STORE_PIF_DATA_ERROR: 7,
ExceptionCodes.INSTR_PIF_ADDR_ERROR: 11,
ExceptionCodes.LOAD_STORE_PIF_ADDR_ERROR: 11,
ExceptionCodes.INSTR_TLB_MISS: 11,
ExceptionCodes.INSTR_TLB_MULTI_HIT: 11,
ExceptionCodes.INSTR_FETCH_PRIVILEGE: 11,
ExceptionCodes.INST_FETCH_PROHIBITED: 11,
ExceptionCodes.LOAD_STORE_TLB_MISS: 11,
ExceptionCodes.LOAD_STORE_TLB_MULTI_HIT: 11,
ExceptionCodes.LOAD_STORE_PRIVILEGE: 11,
ExceptionCodes.LOAD_PROHIBITED: 11,
ExceptionCodes.STORE_PROHIBITED: 11,
ExceptionCodes.Z_EXCEPT_REASON: 6,
}
reg_fmt = "<I"
def __init__(self, logfile, elffile):
super().__init__(logfile=logfile, elffile=elffile)
self.registers = None
self.exception_code = None
self.gdb_signal = self.GDB_SIGNAL_DEFAULT
self.parse_arch_data_block()
self.compute_signal()
def parse_arch_data_block(self):
arch_data_blk = self.logfile.get_arch_data()['data']
self.version = struct.unpack('H', arch_data_blk[1:3])[0]
logger.debug("Xtensa GDB stub version: %d" % self.version)
# Get SOC and toolchain to get correct format for unpack
self.soc = XtensaSoc(bytearray(arch_data_blk)[0])
logger.debug("Xtensa SOC: %s" % self.soc.name)
if self.version >= 2:
self.toolchain = XtensaToolchain(bytearray(arch_data_blk)[3])
arch_data_blk_regs = arch_data_blk[4:]
else:
# v1 only supported ESP32 and sample_controller, each of which
# only build with one toolchain
if self.soc == XtensaSoc.ESP32:
self.toolchain = XtensaToolchain.ESPRESSIF
else:
self.toolchain = XtensaToolchain.ZEPHYR
arch_data_blk_regs = arch_data_blk[3:]
logger.debug("Xtensa toolchain: %s" % self.toolchain.name)
self.gdb_reg_def = get_gdb_reg_definition(self.soc, self.toolchain)
tu = struct.unpack(self.gdb_reg_def.ARCH_DATA_BLK_STRUCT_REGS,
arch_data_blk_regs)
self.registers = dict()
self.map_registers(tu)
def map_registers(self, tu):
i = 0
for r in self.gdb_reg_def.RegNum:
reg_num = r.value
# Dummy WINDOWBASE and WINDOWSTART to enable GDB
# without dumping them and all AR registers;
# avoids interfering with interrupts / exceptions
if r == self.gdb_reg_def.RegNum.WINDOWBASE:
self.registers[reg_num] = 0
elif r == self.gdb_reg_def.RegNum.WINDOWSTART:
self.registers[reg_num] = 1
else:
if r == self.gdb_reg_def.RegNum.EXCCAUSE:
self.exception_code = tu[i]
self.registers[reg_num] = tu[i]
i += 1
def compute_signal(self):
sig = self.GDB_SIGNAL_DEFAULT
code = ExceptionCodes(self.exception_code)
if code is None:
sig = self.GDB_SIGNAL_DEFAULT
if code in self.GDB_SIGNAL_MAPPING:
sig = self.GDB_SIGNAL_MAPPING[code]
elif ExceptionCodes.COPROCESSOR_DISABLED_START.value <= code <= \
ExceptionCodes.COPROCESSOR_DISABLED_END.value:
sig = 8
self.gdb_signal = sig
def handle_register_group_read_packet(self):
idx = 0
pkt = b''
GDB_G_PKT_MAX_REG = \
max([reg_num.value for reg_num in self.gdb_reg_def.RegNum])
# We try to send as many of the registers listed
# as possible, but we are constrained by the
# maximum length of the g packet
while idx <= GDB_G_PKT_MAX_REG and idx * 4 < self.gdb_reg_def.SOC_GDB_GPKT_BIN_SIZE:
if idx in self.registers:
bval = struct.pack(self.reg_fmt, self.registers[idx])
pkt += binascii.hexlify(bval)
else:
pkt += b'x' * 8
idx += 1
self.put_gdb_packet(pkt)
def handle_register_single_read_packet(self, pkt):
# format is pXX, where XX is the hex representation of the idx
regIdx = int('0x' + pkt[1:].decode('utf8'), 16)
try:
bval = struct.pack(self.reg_fmt, self.registers[regIdx])
self.put_gdb_packet(binascii.hexlify(bval))
except KeyError:
self.put_gdb_packet(b'x' * 8)
# The following classes map registers to their index used by
# the GDB of a specific SOC and toolchain. See xtensa_config.c.
# WARNING: IF YOU CHANGE THE ORDER OF THE REGISTERS IN ONE
# MAPPING, YOU MUST CHANGE THE ORDER TO MATCH IN THE OTHERS
# AND IN arch/xtensa/core/coredump.c's xtensa_arch_block.r.
# See map_registers.
# For the same reason, even though the WINDOWBASE and WINDOWSTART
# values are dummied by this script, they have to be last in the
# mapping below.
# sample_controller is unique to Zephyr SDK
# sdk-ng -> overlays/xtensa_sample_controller/gdb/gdb/xtensa-config.c
class GdbRegDef_Sample_Controller:
ARCH_DATA_BLK_STRUCT_REGS = '<IIIIIIIIIIIIIIIIIIIIII'
# This fits the maximum possible register index (110).
# Unlike on ESP32 GDB, there doesn't seem to be an
# actual hard limit to how big the g packet can be.
SOC_GDB_GPKT_BIN_SIZE = 444
class RegNum(Enum):
PC = 0
EXCCAUSE = 77
EXCVADDR = 83
SAR = 33
PS = 38
SCOMPARE1 = 39
A0 = 89
A1 = 90
A2 = 91
A3 = 92
A4 = 93
A5 = 94
A6 = 95
A7 = 96
A8 = 97
A9 = 98
A10 = 99
A11 = 100
A12 = 101
A13 = 102
A14 = 103
A15 = 104
# LBEG, LEND, and LCOUNT not on sample_controller
WINDOWBASE = 34
WINDOWSTART = 35
# ESP32 is unique to espressif toolchain
# espressif xtensa-overlays -> xtensa_esp32/gdb/gdb/xtensa-config.c
class GdbRegDef_ESP32:
ARCH_DATA_BLK_STRUCT_REGS = '<IIIIIIIIIIIIIIIIIIIIIIIII'
SOC_GDB_GPKT_BIN_SIZE = 420
class RegNum(Enum):
PC = 0
EXCCAUSE = 143
EXCVADDR = 149
SAR = 68
PS = 73
SCOMPARE1 = 76
A0 = 157
A1 = 158
A2 = 159
A3 = 160
A4 = 161
A5 = 162
A6 = 163
A7 = 164
A8 = 165
A9 = 166
A10 = 167
A11 = 168
A12 = 169
A13 = 170
A14 = 171
A15 = 172
LBEG = 65
LEND = 66
LCOUNT = 67
WINDOWBASE = 69
WINDOWSTART = 70
class GdbRegDef_ESP32S2:
ARCH_DATA_BLK_STRUCT_REGS = '<IIIIIIIIIIIIIIIIIIIII'
SOC_GDB_GPKT_BIN_SIZE = 420
class RegNum(Enum):
PC = 0
EXCCAUSE = 99
EXCVADDR = 115
SAR = 65
PS = 70
A0 = 155
A1 = 156
A2 = 157
A3 = 158
A4 = 159
A5 = 160
A6 = 161
A7 = 162
A8 = 163
A9 = 164
A10 = 165
A11 = 166
A12 = 167
A13 = 168
A14 = 169
A15 = 170
WINDOWBASE = 66
WINDOWSTART = 67
class GdbRegDef_ESP32S3:
ARCH_DATA_BLK_STRUCT_REGS = '<IIIIIIIIIIIIIIIIIIIIIIIII'
SOC_GDB_GPKT_BIN_SIZE = 420
class RegNum(Enum):
PC = 0
EXCCAUSE = 166
EXCVADDR = 172
SAR = 68
PS = 73
SCOMPARE1 = 76
A0 = 212
A1 = 213
A2 = 214
A3 = 215
A4 = 216
A5 = 217
A6 = 218
A7 = 219
A8 = 220
A9 = 221
A10 = 222
A11 = 223
A12 = 224
A13 = 225
A14 = 226
A15 = 227
LBEG = 65
LEND = 66
LCOUNT = 67
WINDOWBASE = 69
WINDOWSTART = 70
# sdk-ng -> overlays/xtensa_intel_apl/gdb/gdb/xtensa-config.c
class GdbRegDef_Intel_Adsp_CAVS_Zephyr:
ARCH_DATA_BLK_STRUCT_REGS = '<IIIIIIIIIIIIIIIIIIIIIIIII'
# If you send all the registers below (up to index 173)
# GDB incorrectly assigns 0 to EXCCAUSE / EXCVADDR... for some
# reason. Since APL GDB sends p packets for every An register
# even if it was sent in the g packet, I arbitrarily shrunk the
# G packet to include up to A1, which fixed the issue.
SOC_GDB_GPKT_BIN_SIZE = 640
class RegNum(Enum):
PC = 0
EXCCAUSE = 148
EXCVADDR = 154
SAR = 68
PS = 74
SCOMPARE1 = 77
A0 = 158
A1 = 159
A2 = 160
A3 = 161
A4 = 162
A5 = 163
A6 = 164
A7 = 165
A8 = 166
A9 = 167
A10 = 168
A11 = 169
A12 = 170
A13 = 171
A14 = 172
A15 = 173
LBEG = 65
LEND = 66
LCOUNT = 67
WINDOWBASE = 70
WINDOWSTART = 71
# Reverse-engineered from:
# sof -> src/debug/gdb/gdb.c
# sof -> src/arch/xtensa/include/xtensa/specreg.h
class GdbRegDef_Intel_Adsp_CAVS_XCC:
ARCH_DATA_BLK_STRUCT_REGS = '<IIIIIIIIIIIIIIIIIIIIIIIII'
# xt-gdb doesn't use the g packet at all
SOC_GDB_GPKT_BIN_SIZE = 0
class RegNum(Enum):
PC = 32
EXCCAUSE = 744
EXCVADDR = 750
SAR = 515
PS = 742
SCOMPARE1 = 524
A0 = 256
A1 = 257
A2 = 258
A3 = 259
A4 = 260
A5 = 261
A6 = 262
A7 = 263
A8 = 264
A9 = 265
A10 = 266
A11 = 267
A12 = 268
A13 = 269
A14 = 270
A15 = 271
LBEG = 512
LEND = 513
LCOUNT = 514
WINDOWBASE = 584
WINDOWSTART = 585
# sdk-ng -> overlays/xtensa_dc233c/gdb/gdb/xtensa-config.c
class GdbRegDef_DC233C:
ARCH_DATA_BLK_STRUCT_REGS = '<IIIIIIIIIIIIIIIIIIIIIIIII'
SOC_GDB_GPKT_BIN_SIZE = 568
class RegNum(Enum):
PC = 0
EXCCAUSE = 93
EXCVADDR = 99
SAR = 36
PS = 42
SCOMPARE1 = 44
A0 = 105
A1 = 106
A2 = 107
A3 = 108
A4 = 109
A5 = 110
A6 = 111
A7 = 112
A8 = 113
A9 = 114
A10 = 115
A11 = 116
A12 = 117
A13 = 118
A14 = 119
A15 = 120
LBEG = 33
LEND = 34
LCOUNT = 35
WINDOWBASE = 38
WINDOWSTART = 39