diff --git a/.github/workflows/CITest.yml b/.github/workflows/CITest.yml index 9f30d6b51..e252e0ff0 100644 --- a/.github/workflows/CITest.yml +++ b/.github/workflows/CITest.yml @@ -202,10 +202,13 @@ jobs: clang-format-20 --version cp ./include/capstone/arm64.h arm64_compat_current.h cp ./include/capstone/systemz_compatibility.h systemz_compat_current.h + cp ./include/capstone/riscv.h riscv_current.h ./suite/auto-sync/src/autosync/HeaderPatcher.py -C ./.clang-format -c --v6 ./include/capstone/aarch64.h --v5 ./include/capstone/arm64.h ./suite/auto-sync/src/autosync/HeaderPatcher.py -C ./.clang-format -c --v6 ./include/capstone/systemz.h --v5 ./include/capstone/systemz_compatibility.h + ./suite/auto-sync/src/autosync/HeaderPatcher.py --riscv-compat --header ./include/capstone/riscv.h diff ./include/capstone/arm64.h arm64_compat_current.h && - diff ./include/capstone/systemz_compatibility.h systemz_compat_current.h + diff ./include/capstone/systemz_compatibility.h systemz_compat_current.h && + diff ./include/capstone/riscv.h riscv_current.h Windows: runs-on: ${{ matrix.config.os }} diff --git a/bindings/python/capstone/__init__.py b/bindings/python/capstone/__init__.py index 9e4dcb04b..606dddfac 100755 --- a/bindings/python/capstone/__init__.py +++ b/bindings/python/capstone/__init__.py @@ -123,6 +123,7 @@ __all__ = [ "CS_MODE_RISCV32", "CS_MODE_RISCV64", "CS_MODE_RISCV_C", + "CS_MODE_RISCVC", "CS_MODE_RISCV_FD", "CS_MODE_RISCV_F", "CS_MODE_RISCV_D", @@ -471,6 +472,7 @@ CS_MODE_BPF_EXTENDED = 1 << 0 # Extended BPF mode CS_MODE_RISCV32 = 1 << 0 # RISCV32 mode CS_MODE_RISCV64 = 1 << 1 # RISCV64 mode CS_MODE_RISCV_C = 1 << 2 # RISCV compressed instructure mode +CS_MODE_RISCVC = CS_MODE_RISCV_C CS_MODE_RISCV_FD = 1 << 3 CS_MODE_RISCV_F = CS_MODE_RISCV_FD CS_MODE_RISCV_D = CS_MODE_RISCV_FD diff --git a/bindings/python/tests/test_compatibility_layer.py b/bindings/python/tests/test_compatibility_layer.py index b81697f78..83208c450 100644 --- a/bindings/python/tests/test_compatibility_layer.py +++ b/bindings/python/tests/test_compatibility_layer.py @@ -55,6 +55,12 @@ def test_compatibility(): print("systemz.SYSTEMZ_INS_LG = %d" % capstone.systemz.SYSTEMZ_INS_LG) assert capstone.systemz.SYSZ_INS_LG == capstone.systemz.SYSTEMZ_INS_LG + # Test RISC-V compressed-mode compatibility constant + print("CS_MODE_RISCVC = %d" % CS_MODE_RISCVC) + print("CS_MODE_RISCV_C = %d" % CS_MODE_RISCV_C) + assert CS_MODE_RISCVC == CS_MODE_RISCV_C + assert "CS_MODE_RISCVC" in capstone.__all__ + # Test ARM_CC_ constants print("arm.ARM_CC_MI = %d" % capstone.arm.ARM_CC_MI) print("arm.ARMCC_MI = %d" % capstone.arm.ARMCC_MI) diff --git a/docs/cs_v6_release_guide.md b/docs/cs_v6_release_guide.md index 532aa6820..1e2bfc4d7 100644 --- a/docs/cs_v6_release_guide.md +++ b/docs/cs_v6_release_guide.md @@ -489,7 +489,7 @@ Such an instruction is ill-defined in LLVM and should be fixed upstream. | `M68K_OP_MEM` storage | Memory operands now store base registers in `m68k_op_mem.base_reg` and absolute addresses in `m68k_op_mem.address`; `op->reg` and `op->imm` are only used for register and immediate operands. | Keeps memory-addressing details in `m68k_op_mem` consistently. | -### Notes about AArch64, SystemZ and ARM renaming +### Notes about AArch64, SystemZ, ARM and RISC-V renaming `ARM64` was everywhere renamed to `AArch64`. And `SYSZ` to `SYSTEMZ`. This is a necessity to ensure that the update scripts stay reasonably simple. Capstone was very inconsistent with the naming before (sometimes `AArch64` sometimes `ARM64`. Sometimes `SYSZ` sometimes `SYSTEMZ`). @@ -499,19 +499,21 @@ Because this would completely break maintaining Capstone `v6` and `pre-v6` in a 1. `arm64.h` is a compatibility header now, which merely maps every member to the one in the `aarch64.h` header. Defining `CAPSTONE_AARCH64_COMPAT_HEADER` before including `capstone.h` will include the headers in the right order. 2. The `systemz.h` header includes the `systemz_compatibility.h` header if `CAPSTONE_SYSTEMZ_COMPAT_HEADER` is defined. +3. Defining `CAPSTONE_RISCV_COMPAT_HEADER` before including `capstone.h` exposes the legacy RISC-V compressed-mode constant `CS_MODE_RISCVC` as an alias of `CS_MODE_RISCV_C`. -We will continue to maintain both headers. +We will continue to maintain both compatibility headers, `arm64.h` and `systemz_compatibility.h`. _Compatibility header_ -If you want to use the compatibility header and stick with the `ARM64`/`SYSZ` naming, you can define `CAPSTONE_AARCH64_COMPAT_HEADER` and `CAPSTONE_SYSTEMZ_COMPAT_HEADER` before including `capstone.h`. +If you want to use the compatibility header and stick with the `ARM64`/`SYSZ` naming, you can define `CAPSTONE_AARCH64_COMPAT_HEADER` and `CAPSTONE_SYSTEMZ_COMPAT_HEADER` before including `capstone.h`. For the legacy RISC-V compressed-mode spelling (`CS_MODE_RISCVC`), define `CAPSTONE_RISCV_COMPAT_HEADER` before including `capstone.h`. -**Note**: The `CAPSTONE_ARM_COMPAT_HEADER` will only define macros for the `ARM_CC -> ARMCC` and `arm_cc -> ARMCC_CondCodes` renaming. +**Note**: The `CAPSTONE_ARM_COMPAT_HEADER` will only define macros for the `ARM_CC -> ARMCC` and `arm_cc -> ARMCC_CondCodes` renaming. The `CAPSTONE_RISCV_COMPAT_HEADER` only defines `CS_MODE_RISCVC` for the `CS_MODE_RISCVC -> CS_MODE_RISCV_C` renaming. ```c #define CAPSTONE_SYSTEMZ_COMPAT_HEADER #define CAPSTONE_AARCH64_COMPAT_HEADER #define CAPSTONE_ARM_COMPAT_HEADER +#define CAPSTONE_RISCV_COMPAT_HEADER #include // Your code... diff --git a/include/capstone/riscv.h b/include/capstone/riscv.h index e8b394369..696e84d53 100644 --- a/include/capstone/riscv.h +++ b/include/capstone/riscv.h @@ -2878,6 +2878,14 @@ typedef enum riscv_insn_group { RISCV_GRP_ENDING, } riscv_insn_group; +// generated content begin +// clang-format off +#ifdef CAPSTONE_RISCV_COMPAT_HEADER +#define CS_MODE_RISCVC CS_MODE_RISCV_C +#endif +// clang-format on +// generated content end + #ifdef __cplusplus } #endif diff --git a/suite/auto-sync/src/autosync/ASUpdater.py b/suite/auto-sync/src/autosync/ASUpdater.py index d21240341..5565d8421 100755 --- a/suite/auto-sync/src/autosync/ASUpdater.py +++ b/suite/auto-sync/src/autosync/ASUpdater.py @@ -128,6 +128,8 @@ class ASUpdater: arch="systemz", ) builder.generate_v5_compat_header() + elif self.arch == "RISCV": + HeaderPatcher.patch_riscv_compat_macros(main_header) return patched def copy_files(self, path: Path, dest: Path) -> None: diff --git a/suite/auto-sync/src/autosync/HeaderPatcher.py b/suite/auto-sync/src/autosync/HeaderPatcher.py index bce6db8ee..312d810ba 100755 --- a/suite/auto-sync/src/autosync/HeaderPatcher.py +++ b/suite/auto-sync/src/autosync/HeaderPatcher.py @@ -10,6 +10,12 @@ import subprocess as sp from pathlib import Path +RISCV_COMPAT_MACROS = [ + "#ifdef CAPSTONE_RISCV_COMPAT_HEADER\n", + "#define CS_MODE_RISCVC CS_MODE_RISCV_C\n", + "#endif\n", +] + AARCH64_CC_MACROS = [ "\n", "#define arm64_cc AArch64CC_CondCode\n", @@ -68,6 +74,12 @@ def parse_args() -> argparse.Namespace: parser.add_argument( "-p", dest="patch", help="Patch inc file into header", action="store_true" ) + parser.add_argument( + "--riscv-compat", + dest="riscv_compat", + help="Patch the RISC-V compatibility macros into the RISC-V header", + action="store_true", + ) parser.add_argument( "-C", dest="clang_format", @@ -160,6 +172,35 @@ class HeaderPatcher: log.info(f"Patched {self.inc.name} into {self.header.name}") return True + @staticmethod + def patch_riscv_compat_macros(header: Path) -> bool: + if not (header.exists() or header.is_file()): + error_exit(f"header file {header.name} does not exist.") + + with open(header) as f: + header_content = f.read() + + regex = ( + r"\n// generated content begin.*(\n)" + r"(.*\n)*" + r"// generated content end.*(\n)" + ) + new_content = ( + "\n// generated content begin\n" + + "// clang-format off\n" + + "".join(RISCV_COMPAT_MACROS) + + "// clang-format on\n" + + "// generated content end\n" + ) + if not re.search(regex, header_content): + error_exit(f"Could not find RISCVCompat marker in {header.name}.") + header_content = re.sub(regex, new_content, header_content) + + with open(header, "w") as f: + f.write(header_content) + log.info(f"Patched RISC-V compatibility macros into {header.name}") + return True + @staticmethod def file_in_main_header(header: Path, filename: str) -> bool: with open(header) as f: @@ -347,8 +388,8 @@ class CompatHeaderBuilder: if __name__ == "__main__": args = parse_args() - if (not args.patch and not args.compat) or (args.patch and args.compat): - print("You need to specify either -c or -p") + if [args.patch, args.compat, args.riscv_compat].count(True) != 1: + print("You need to specify exactly one of -c, -p, or --riscv-compat") exit(1) if args.compat and not (args.v6 and args.v5): print("Generating the v5 compatibility header requires --v5 and --v6") @@ -356,6 +397,13 @@ if __name__ == "__main__": if args.patch and not (args.inc and args.header): print("Patching headers requires --inc and --header") exit(1) + if args.riscv_compat and not args.header: + print("Patching RISC-V compatibility macros requires --header") + exit(1) + + if args.riscv_compat: + HeaderPatcher.patch_riscv_compat_macros(args.header) + exit(0) if args.patch: patcher = HeaderPatcher(args.header, args.inc) diff --git a/tests/integration/compat_header/include/compat.h b/tests/integration/compat_header/include/compat.h index 3dd5b69fc..71e4ed330 100644 --- a/tests/integration/compat_header/include/compat.h +++ b/tests/integration/compat_header/include/compat.h @@ -3,3 +3,4 @@ int arm64(void); int sysz(void); +int riscv(void); diff --git a/tests/integration/compat_header/src/main.c b/tests/integration/compat_header/src/main.c index b124031c4..8fd4bee02 100644 --- a/tests/integration/compat_header/src/main.c +++ b/tests/integration/compat_header/src/main.c @@ -14,4 +14,8 @@ int main() printf("Failed the sysz compatibility header test.\n"); return -1; } + if (riscv() != 0) { + printf("Failed the riscv compatibility header test.\n"); + return -1; + } } diff --git a/tests/integration/compat_header/src/test_riscv_compatibility_header.c b/tests/integration/compat_header/src/test_riscv_compatibility_header.c new file mode 100644 index 000000000..71375da5e --- /dev/null +++ b/tests/integration/compat_header/src/test_riscv_compatibility_header.c @@ -0,0 +1,12 @@ +// SPDX-FileCopyrightText: 2026 moste00 +// SPDX-License-Identifier: BSD-3.0-Clause + +#define CAPSTONE_RISCV_COMPAT_HEADER +#include + +int riscv(void) +{ + return CS_MODE_RISCVC == CS_MODE_RISCV_C ? 0 : -1; +} + +#undef CAPSTONE_RISCV_COMPAT_HEADER