mirror of
https://github.com/capstone-engine/capstone
synced 2026-08-11 16:26:07 -04:00
Xtensa: gate ESP32-S3 and HIFI3 ops behind CS_MODE_XTENSA_ESP32S3 (#2979)
The Xtensa disassembler enabled the ESP32-S3 SIMD/AI (ee.*) and HiFi3 ops for every target because the subtarget feature gates were stubbed to return true (Xtensa_getFeatureBits and hasDensity/hasESP32S3Ops/hasHIFI3). As a result, on a non-ESP32-S3 Xtensa config any instruction with op0=0xE/0xF was matched as a 4-byte ee.* op, so a base-ISA byte stream desynced. Make Xtensa_getFeatureBits map the mode to a feature set (mirroring the SystemZ precedent), thread MI->csh->mode into the three has*Ops gates, and add an opt-in CS_MODE_XTENSA_ESP32S3. Base/esp32/esp32s2/esp8266 no longer emit ESP32-S3 ops; CS_MODE_XTENSA_ESP32S3 preserves them. Concrete instance of issue #1992. The saved auto-sync patch hashes are updated so the fix survives the next LLVM re-sync. Adds tests/MC/Xtensa/esp32s3.s.yaml. Co-authored-by: Denys Melnyk <denys@com2cloud.com>
This commit is contained in:
parent
a0b10fee51
commit
4eb90672f3
11 changed files with 135 additions and 18 deletions
|
|
@ -235,8 +235,23 @@ static DecodeStatus DecodeMR23RegisterClass(MCInst *Inst, uint64_t RegNo,
|
|||
|
||||
bool Xtensa_getFeatureBits(unsigned int mode, unsigned int feature)
|
||||
{
|
||||
// we support everything
|
||||
return true;
|
||||
switch (feature) {
|
||||
case Xtensa_FeatureESP32S3Ops:
|
||||
// SIMD/AI "ee.*" ops only exist on the ESP32-S3.
|
||||
return (mode & CS_MODE_XTENSA_ESP32S3) != 0;
|
||||
case Xtensa_FeatureHIFI3:
|
||||
// HiFi3 DSP ops are gated behind the ESP32-S3 in this tree.
|
||||
return (mode & CS_MODE_XTENSA_ESP32S3) != 0;
|
||||
case Xtensa_FeatureDensity:
|
||||
// Code Density is a base Tensilica default option.
|
||||
return true;
|
||||
default:
|
||||
// Default case is the "allow all features", which is normal
|
||||
// Capstone behavior until
|
||||
// https://github.com/capstone-engine/capstone/issues/1992
|
||||
// is implemented.
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Verify SR and UR
|
||||
|
|
@ -1036,17 +1051,17 @@ DecodeToMCInst(decodeToMCInst_6, fieldFromInstruction_6, uint64_t);
|
|||
DecodeInstruction(decodeInstruction_6, fieldFromInstruction_6, decodeToMCInst_6,
|
||||
uint64_t);
|
||||
|
||||
static bool hasDensity()
|
||||
static bool hasDensity(MCInst *MI)
|
||||
{
|
||||
return true;
|
||||
return Xtensa_getFeatureBits(MI->csh->mode, Xtensa_FeatureDensity);
|
||||
}
|
||||
static bool hasESP32S3Ops()
|
||||
static bool hasESP32S3Ops(MCInst *MI)
|
||||
{
|
||||
return true;
|
||||
return Xtensa_getFeatureBits(MI->csh->mode, Xtensa_FeatureESP32S3Ops);
|
||||
}
|
||||
static bool hasHIFI3()
|
||||
static bool hasHIFI3(MCInst *MI)
|
||||
{
|
||||
return true;
|
||||
return Xtensa_getFeatureBits(MI->csh->mode, Xtensa_FeatureHIFI3);
|
||||
}
|
||||
|
||||
static DecodeStatus getInstruction(MCInst *MI, uint64_t *Size,
|
||||
|
|
@ -1058,7 +1073,7 @@ static DecodeStatus getInstruction(MCInst *MI, uint64_t *Size,
|
|||
bool IsLittleEndian = MI->csh->mode & CS_MODE_LITTLE_ENDIAN;
|
||||
|
||||
// Parse 16-bit instructions
|
||||
if (hasDensity()) {
|
||||
if (hasDensity(MI)) {
|
||||
Result = readInstruction16(MI, Bytes, BytesLen, Address, Size,
|
||||
&Insn, IsLittleEndian);
|
||||
if (Result == MCDisassembler_Fail)
|
||||
|
|
@ -1084,7 +1099,7 @@ static DecodeStatus getInstruction(MCInst *MI, uint64_t *Size,
|
|||
return Result;
|
||||
}
|
||||
|
||||
if (hasESP32S3Ops()) {
|
||||
if (hasESP32S3Ops(MI)) {
|
||||
// Parse ESP32S3 24-bit instructions
|
||||
Result = readInstruction24(MI, Bytes, BytesLen, Address, Size,
|
||||
&Insn, IsLittleEndian, true);
|
||||
|
|
@ -1111,7 +1126,7 @@ static DecodeStatus getInstruction(MCInst *MI, uint64_t *Size,
|
|||
}
|
||||
}
|
||||
|
||||
if (hasHIFI3()) {
|
||||
if (hasHIFI3(MI)) {
|
||||
Result = decodeInstruction_3(DecoderTableHIFI324, MI, Insn,
|
||||
Address, NULL);
|
||||
if (Result != MCDisassembler_Fail)
|
||||
|
|
|
|||
|
|
@ -217,6 +217,10 @@ __all__ = [
|
|||
"CS_MODE_SYSTEMZ_Z15",
|
||||
"CS_MODE_SYSTEMZ_Z16",
|
||||
"CS_MODE_SYSTEMZ_GENERIC",
|
||||
"CS_MODE_XTENSA_ESP32",
|
||||
"CS_MODE_XTENSA_ESP32S2",
|
||||
"CS_MODE_XTENSA_ESP8266",
|
||||
"CS_MODE_XTENSA_ESP32S3",
|
||||
"CS_OPT_SYNTAX",
|
||||
"CS_OPT_SYNTAX_DEFAULT",
|
||||
"CS_OPT_SYNTAX_INTEL",
|
||||
|
|
@ -568,6 +572,10 @@ CS_MODE_SYSTEMZ_Z14 = 1 << 12
|
|||
CS_MODE_SYSTEMZ_Z15 = 1 << 13
|
||||
CS_MODE_SYSTEMZ_Z16 = 1 << 14
|
||||
CS_MODE_SYSTEMZ_GENERIC = 1 << 15
|
||||
CS_MODE_XTENSA_ESP32 = 1 << 1 # Xtensa ESP32
|
||||
CS_MODE_XTENSA_ESP32S2 = 1 << 2 # Xtensa ESP32S2
|
||||
CS_MODE_XTENSA_ESP8266 = 1 << 3 # Xtensa ESP8266
|
||||
CS_MODE_XTENSA_ESP32S3 = 1 << 4 # Xtensa ESP32-S3 (SIMD/AI "ee.*" ops)
|
||||
|
||||
# Capstone option type
|
||||
CS_OPT_INVALID = 0 # No option specified
|
||||
|
|
|
|||
2
cs.c
2
cs.c
|
|
@ -262,7 +262,7 @@ typedef struct cs_arch_config {
|
|||
Xtensa_global_init, \
|
||||
Xtensa_option, \
|
||||
~(CS_MODE_XTENSA_ESP32 | CS_MODE_XTENSA_ESP32S2 | \
|
||||
CS_MODE_XTENSA_ESP8266), \
|
||||
CS_MODE_XTENSA_ESP8266 | CS_MODE_XTENSA_ESP32S3), \
|
||||
}
|
||||
|
||||
#define CS_ARCH_CONFIG_ARC \
|
||||
|
|
|
|||
|
|
@ -540,6 +540,7 @@ static struct {
|
|||
CS_MODE_LOONGARCH64 },
|
||||
{ "esp32", "Xtensa ESP32", CS_ARCH_XTENSA, CS_MODE_XTENSA_ESP32 },
|
||||
{ "esp32s2", "Xtensa ESP32S2", CS_ARCH_XTENSA, CS_MODE_XTENSA_ESP32S2 },
|
||||
{ "esp32s3", "Xtensa ESP32S3", CS_ARCH_XTENSA, CS_MODE_XTENSA_ESP32S3 },
|
||||
{ "esp8266", "Xtensa ESP8266", CS_ARCH_XTENSA, CS_MODE_XTENSA_ESP8266 },
|
||||
|
||||
{ "arc", "ARC Little-Endian", CS_ARCH_ARC, CS_MODE_LITTLE_ENDIAN },
|
||||
|
|
|
|||
|
|
@ -341,6 +341,7 @@ typedef enum cs_mode {
|
|||
CS_MODE_XTENSA_ESP32 = 1 << 1, ///< Xtensa ESP32
|
||||
CS_MODE_XTENSA_ESP32S2 = 1 << 2, ///< Xtensa ESP32S2
|
||||
CS_MODE_XTENSA_ESP8266 = 1 << 3, ///< Xtensa ESP328266
|
||||
CS_MODE_XTENSA_ESP32S3 = 1 << 4, ///< Xtensa ESP32S3
|
||||
} cs_mode;
|
||||
|
||||
typedef void *(CAPSTONE_API *cs_malloc_t)(size_t size);
|
||||
|
|
|
|||
|
|
@ -2372,7 +2372,7 @@
|
|||
},
|
||||
"Xtensa_getFeatureBits": {
|
||||
"apply_type": "OLD",
|
||||
"old_hash": "126cff581e1a79a655c62e3489e238f7bf00647749f619230ab77061d0423295",
|
||||
"old_hash": "54f9c8bb5264b1b92f2ebc7ba4bf70aaa7f203d537ca9e806ab6b4d69c397474",
|
||||
"new_hash": "",
|
||||
"edit": ""
|
||||
},
|
||||
|
|
@ -2390,19 +2390,19 @@
|
|||
},
|
||||
"hasDensity": {
|
||||
"apply_type": "OLD",
|
||||
"old_hash": "da63483f075aba3c9f8937fb1900c646cb15f01b6b2e25568e6dcaa940b4798b",
|
||||
"old_hash": "8bf85ed5fd8d904a43c0504ae5dedebaa8a4838be3c3d761f1c24e6625473d7e",
|
||||
"new_hash": "",
|
||||
"edit": ""
|
||||
},
|
||||
"hasESP32S3Ops": {
|
||||
"apply_type": "OLD",
|
||||
"old_hash": "464131365b24dec185e04d43154a85d9765a50a18214888c26014d8d85165a99",
|
||||
"old_hash": "87849edd4b0f36b2f057f384624847b1f2dccd52f4070f57795bcb3a46bd98cb",
|
||||
"new_hash": "",
|
||||
"edit": ""
|
||||
},
|
||||
"hasHIFI3": {
|
||||
"apply_type": "OLD",
|
||||
"old_hash": "e1fcb3c8f47f38e571d1a81e7e522efb5c67e0aea05fd7b3980aa1eb3e71c9ff",
|
||||
"old_hash": "7780479933da49a6e4b4c59d1cebbd6ba0c6cfa8877950d8b03e2b101f6d94dd",
|
||||
"new_hash": "",
|
||||
"edit": ""
|
||||
},
|
||||
|
|
|
|||
|
|
@ -255,6 +255,7 @@ static const cs_enum_id_map test_mode_map[] = {
|
|||
{ .str = "CS_MODE_V9", .val = CS_MODE_V9 },
|
||||
{ .str = "CS_MODE_XTENSA_ESP32", .val = CS_MODE_XTENSA_ESP32 },
|
||||
{ .str = "CS_MODE_XTENSA_ESP32S2", .val = CS_MODE_XTENSA_ESP32S2 },
|
||||
{ .str = "CS_MODE_XTENSA_ESP32S3", .val = CS_MODE_XTENSA_ESP32S3 },
|
||||
{ .str = "CS_MODE_XTENSA_ESP8266", .val = CS_MODE_XTENSA_ESP8266 },
|
||||
};
|
||||
|
||||
|
|
|
|||
58
tests/MC/Xtensa/esp32s3.s.yaml
Normal file
58
tests/MC/Xtensa/esp32s3.s.yaml
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
test_cases:
|
||||
# Positive: the ESP32-S3 SIMD/AI "ee.*" ops only decode when the
|
||||
# CS_MODE_XTENSA_ESP32S3 feature is selected. Vector taken from real
|
||||
# MT7961 firmware (it happens to also be a valid ESP32-S3 ee.vmulas).
|
||||
-
|
||||
input:
|
||||
name: "ee.vmulas decodes on ESP32-S3"
|
||||
bytes: [ 0x9e, 0x3e, 0x09, 0x40 ]
|
||||
arch: "CS_ARCH_XTENSA"
|
||||
options: [ "CS_MODE_XTENSA_ESP32S3" ]
|
||||
address: 0x0
|
||||
expected:
|
||||
insns:
|
||||
-
|
||||
asm_text: "ee.vmulas.u16.accx.ld.ip.qup q1, a9, 0xe0, q0, q6, q0, q1"
|
||||
size: 4
|
||||
|
||||
# Negative (ESP32): without the ESP32-S3 feature the 4-byte ee.* encoding
|
||||
# must NOT be produced. These bytes do not form a valid base/ESP32
|
||||
# instruction, so decoding fails (zero instructions).
|
||||
-
|
||||
input:
|
||||
name: "ee.vmulas must NOT decode on ESP32 (#1)"
|
||||
bytes: [ 0x9e, 0x3e, 0x09, 0x40 ]
|
||||
arch: "CS_ARCH_XTENSA"
|
||||
options: [ "CS_MODE_XTENSA_ESP32" ]
|
||||
address: 0x0
|
||||
expected:
|
||||
insns: []
|
||||
-
|
||||
input:
|
||||
name: "ee.vmulas must NOT decode on ESP32 (#2)"
|
||||
bytes: [ 0x3e, 0x19, 0x45, 0x48 ]
|
||||
arch: "CS_ARCH_XTENSA"
|
||||
options: [ "CS_MODE_XTENSA_ESP32" ]
|
||||
address: 0x0
|
||||
expected:
|
||||
insns: []
|
||||
|
||||
# Negative (base Tensilica, no vendor feature bits): same expectation.
|
||||
-
|
||||
input:
|
||||
name: "ee.vmulas must NOT decode on base Xtensa (#1)"
|
||||
bytes: [ 0x9e, 0x3e, 0x09, 0x40 ]
|
||||
arch: "CS_ARCH_XTENSA"
|
||||
options: [ "CS_MODE_LITTLE_ENDIAN" ]
|
||||
address: 0x0
|
||||
expected:
|
||||
insns: []
|
||||
-
|
||||
input:
|
||||
name: "ee.vmulas must NOT decode on base Xtensa (#2)"
|
||||
bytes: [ 0x3e, 0x19, 0x45, 0x48 ]
|
||||
arch: "CS_ARCH_XTENSA"
|
||||
options: [ "CS_MODE_LITTLE_ENDIAN" ]
|
||||
address: 0x0
|
||||
expected:
|
||||
insns: []
|
||||
|
|
@ -65,3 +65,35 @@ test_cases:
|
|||
- type: XTENSA_OP_IMM
|
||||
imm: -1
|
||||
access: CS_AC_READ
|
||||
# ee.* op, gated behind CS_MODE_XTENSA_ESP32S3 (MT7961 firmware bytes).
|
||||
- input:
|
||||
bytes: [ 0x9e, 0x3e, 0x09, 0x40 ]
|
||||
arch: "CS_ARCH_XTENSA"
|
||||
options: [ CS_MODE_XTENSA_ESP32S3, CS_OPT_DETAIL ]
|
||||
expected:
|
||||
insns:
|
||||
- asm_text: "ee.vmulas.u16.accx.ld.ip.qup q1, a9, 0xe0, q0, q6, q0, q1"
|
||||
details:
|
||||
xtensa:
|
||||
operands:
|
||||
- type: XTENSA_OP_REG
|
||||
reg: q1
|
||||
access: CS_AC_WRITE
|
||||
- type: XTENSA_OP_REG
|
||||
reg: a9
|
||||
access: CS_AC_READ
|
||||
- type: XTENSA_OP_IMM
|
||||
imm: 0xe0
|
||||
access: CS_AC_READ
|
||||
- type: XTENSA_OP_REG
|
||||
reg: q0
|
||||
access: CS_AC_READ
|
||||
- type: XTENSA_OP_REG
|
||||
reg: q6
|
||||
access: CS_AC_READ
|
||||
- type: XTENSA_OP_REG
|
||||
reg: q0
|
||||
access: CS_AC_READ
|
||||
- type: XTENSA_OP_REG
|
||||
reg: q1
|
||||
access: CS_AC_READ
|
||||
|
|
|
|||
|
|
@ -197,7 +197,8 @@ static void test_ub_isintn_xtensa_offset(void)
|
|||
static const uint8_t code[] = { 0x2f, 0x70, 0x44, 0x84 };
|
||||
|
||||
csh handle;
|
||||
if (cs_open(CS_ARCH_XTENSA, CS_MODE_XTENSA_ESP32, &handle) != CS_ERR_OK)
|
||||
if (cs_open(CS_ARCH_XTENSA, CS_MODE_XTENSA_ESP32S3, &handle) !=
|
||||
CS_ERR_OK)
|
||||
return;
|
||||
cs_option(handle, CS_OPT_DETAIL, CS_OPT_ON);
|
||||
|
||||
|
|
|
|||
|
|
@ -6239,7 +6239,7 @@ test_cases:
|
|||
name: "#2986 Xtensa decodeOffset_16_16Operand swapped isIntN arguments"
|
||||
bytes: [ 0x2f, 0x70, 0x44, 0x84 ]
|
||||
arch: "CS_ARCH_XTENSA"
|
||||
options: [ CS_MODE_XTENSA_ESP32, CS_OPT_DETAIL ]
|
||||
options: [ CS_MODE_XTENSA_ESP32S3, CS_OPT_DETAIL ]
|
||||
address: 0x0
|
||||
expected:
|
||||
insns:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue