Rename the remaining z_xtensa stuff as these are (mostly) under arch/xtensa. Signed-off-by: Daniel Leung <daniel.leung@intel.com>
516 lines
14 KiB
Python
516 lines
14 KiB
Python
#!/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 4–64. 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
|