diff --git a/.github/workflows/vcpkg.yml b/.github/workflows/vcpkg.yml index e83f497d9..5111c9806 100644 --- a/.github/workflows/vcpkg.yml +++ b/.github/workflows/vcpkg.yml @@ -42,7 +42,7 @@ jobs: name: Get vcpkg with: repository: 'microsoft/vcpkg' - ref: '2022.04.12' + ref: '2024.05.24' path: '${{ github.workspace }}/_vcpkg' fetch-depth: 0 @@ -64,7 +64,7 @@ jobs: - name: Configure (Windows) if: ${{ matrix.platform == 'windows' }} run: | - cmake --preset=${{ matrix.cmake-preset }} -DBUILD_SHARED_LIBS:BOOL=ON -DVCPKG_OVERLAY_TRIPLETS:PATH=${{ github.workspace }}\vcpkg\triplets -DVCPKG_TARGET_TRIPLET:STRING=${{ matrix.vcpkg-triplet }} + cmake --preset=${{ matrix.cmake-preset }} -DBUILD_SHARED_LIBS:BOOL=ON -DCS_VERSION_MAJOR:STRING=5 -DVCPKG_OVERLAY_TRIPLETS:PATH=${{ github.workspace }}\vcpkg\triplets -DVCPKG_TARGET_TRIPLET:STRING=${{ matrix.vcpkg-triplet }} env: # capstone 4.0.2 does not produce a CMake Config, hence the need to point directly to include directories and libraries CAPSTONE_INCLUDE_DIRS: ${{ github.workspace }}/build/${{ matrix.cmake-preset }}/vcpkg_installed/${{ matrix.vcpkg-triplet }}/include @@ -76,7 +76,7 @@ jobs: if: ${{ matrix.platform != 'windows' }} run: | python -m pip install importlib-resources - cmake --preset=${{ matrix.cmake-preset }} -DBUILD_SHARED_LIBS:BOOL=ON -DVCPKG_OVERLAY_TRIPLETS:PATH=${{ github.workspace }}/vcpkg/triplets -DVCPKG_TARGET_TRIPLET:STRING=${{ matrix.vcpkg-triplet }} + cmake --preset=${{ matrix.cmake-preset }} -DBUILD_SHARED_LIBS:BOOL=ON -DCS_VERSION_MAJOR:STRING=5 -DVCPKG_OVERLAY_TRIPLETS:PATH=${{ github.workspace }}/vcpkg/triplets -DVCPKG_TARGET_TRIPLET:STRING=${{ matrix.vcpkg-triplet }} env: # capstone 4.0.2 does not produce a CMake Config, hence the need to point directly to include directories and libraries CAPSTONE_INCLUDE_DIRS: ${{ github.workspace }}/build/${{ matrix.cmake-preset }}/vcpkg_installed/${{ matrix.vcpkg-triplet }}/include @@ -86,7 +86,7 @@ jobs: - name: Build run: | - cmake --build --preset build-${{ matrix.cmake-preset }} --config Release + cmake --build --preset build-${{ matrix.cmake-preset }} --config Release -DCS_VERSION_MAJOR:STRING=5 - name: Test # Test disabled on Windows `pip install lief` fails as there is no ready to use .whl and compilation fails @@ -98,7 +98,7 @@ jobs: - name: Install run: | - cmake --build --preset build-${{ matrix.cmake-preset }} --config Release --target install + cmake --build --preset build-${{ matrix.cmake-preset }} --config Release --target install -DCS_VERSION_MAJOR:STRING=5 - name: Upload uses: actions/upload-artifact@v3 diff --git a/CMakeLists.txt b/CMakeLists.txt index 3ccb41617..9a529b2af 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -194,6 +194,9 @@ endif() message(STATUS "Compiling with Capstone") find_package(CAPSTONE 5 REQUIRED) message(STATUS "CAPSTONE version: ${CAPSTONE_VERSION}") +if(${CS_VERSION_MAJOR} GREATER_EQUAL 5) + add_definitions(-DCOMPILE_RISCV) +endif() if(TARGET capstone::capstone) link_libraries(capstone::capstone) elseif(DEFINED CAPSTONE_INCLUDE_DIRS) diff --git a/Dockerfile b/Dockerfile index 1fd598a46..f5f18809e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -9,10 +9,11 @@ COPY . /Triton # cmake >= 3.20 RUN apt update && apt upgrade -y && apt install -y build-essential clang curl git libboost-all-dev libgmp-dev libpython3-dev libpython3-stdlib llvm-12 llvm-12-dev python3-pip tar ninja-build pkg-config && apt-get clean && pip install --upgrade pip && pip3 install Cython lief cmake meson -# libcapstone >= 4.0.x +# libcapstone >= 5.0.x RUN cd /tmp && \ curl -o cap.tgz -L https://github.com/aquynh/capstone/archive/5.0.1.tar.gz && \ - tar xvf cap.tgz && cd capstone-5.0.1/ && ./make.sh && make install && rm -rf /tmp/cap* \ + tar xvf cap.tgz && cd capstone-5.0.1/ && CAPSTONE_ARCHS="arm aarch64 riscv x86" ./make.sh && \ + make install && rm -rf /tmp/cap* \ && ln -s /usr/lib/libcapstone.so.5 /usr/lib/x86_64-linux-gnu/libcapstone.so # libbitwuzla >= 0.4.0 diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt index 5b79f22c5..9adeaf0d7 100644 --- a/doc/CMakeLists.txt +++ b/doc/CMakeLists.txt @@ -24,20 +24,54 @@ add_custom_target(gen_arm32_doc_from_spec DEPENDS ${TRITON_ROOT}/src/libtriton/includes/triton/arm32.spec ) -add_custom_target(doc - COMMAND doxygen ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile - DEPENDS gen_x86_doc_from_spec - DEPENDS gen_aarch64_doc_from_spec - DEPENDS gen_arm32_doc_from_spec +add_custom_target(gen_rv64_doc_from_spec + COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/extract_doc.py ${TRITON_ROOT}/src/libtriton/includes/triton/riscv64.spec "${CMAKE_CURRENT_BINARY_DIR}" + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/extract_doc.py + DEPENDS ${TRITON_ROOT}/src/libtriton/includes/triton/riscv64.spec +) + +add_custom_target(gen_rv32_doc_from_spec + COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/extract_doc.py ${TRITON_ROOT}/src/libtriton/includes/triton/riscv32.spec "${CMAKE_CURRENT_BINARY_DIR}" + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/extract_doc.py + DEPENDS ${TRITON_ROOT}/src/libtriton/includes/triton/riscv32.spec ) +if(${CS_VERSION_MAJOR} GREATER_EQUAL 5) + add_custom_target(doc + COMMAND doxygen ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile + DEPENDS gen_x86_doc_from_spec + DEPENDS gen_aarch64_doc_from_spec + DEPENDS gen_arm32_doc_from_spec + DEPENDS gen_rv64_doc_from_spec + DEPENDS gen_rv32_doc_from_spec + ) +else() + add_custom_target(doc + COMMAND doxygen ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile + DEPENDS gen_x86_doc_from_spec + DEPENDS gen_aarch64_doc_from_spec + DEPENDS gen_arm32_doc_from_spec + ) +endif() + if(PYTHON_BINDINGS_AUTOCOMPLETE) - add_custom_target(python_autocomplete + if(${CS_VERSION_MAJOR} GREATER_EQUAL 5) + add_custom_target(python_autocomplete COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_LIST_DIR}/autocomplete/generate_autocomplete.py "--basedir" "${CMAKE_CURRENT_BINARY_DIR}" "$<$:--bitwuzla>" "$<$:--z3>" DEPENDS gen_x86_doc_from_spec DEPENDS gen_aarch64_doc_from_spec DEPENDS gen_arm32_doc_from_spec + DEPENDS gen_rv64_doc_from_spec + DEPENDS gen_rv32_doc_from_spec ) + else() + add_custom_target(python_autocomplete + COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_LIST_DIR}/autocomplete/generate_autocomplete.py "--basedir" "${CMAKE_CURRENT_BINARY_DIR}" "$<$:--bitwuzla>" "$<$:--z3>" + DEPENDS gen_x86_doc_from_spec + DEPENDS gen_aarch64_doc_from_spec + DEPENDS gen_arm32_doc_from_spec + ) + endif() if (NOT DEFINED PYTHON_SITE_PACKAGES) execute_process(COMMAND ${PYTHON_EXECUTABLE} -c "from sysconfig import get_path; print(get_path('platlib'))" OUTPUT_VARIABLE PYTHON_SITE_PACKAGES OUTPUT_STRIP_TRAILING_WHITESPACE) endif() diff --git a/doc/extract_doc.py b/doc/extract_doc.py index c42220ed0..3346c5d94 100644 --- a/doc/extract_doc.py +++ b/doc/extract_doc.py @@ -6,6 +6,8 @@ x86_regs = list() aarch64_regs = list() arm32_regs = list() +rv64_regs = list() +rv32_regs = list() ############################################################################## @@ -58,3 +60,33 @@ for name in arm32_regs: out.write("
  • REG.ARM32.{}
  • \n".format(name)) out.write('\n') + +############################################################################## + +elif SPEC.find('riscv64') >= 0: + with open(SPEC, "r") as f: + for line in f.readlines(): + if line.startswith("REG_SPEC") or line.startswith("SYS_REG_SPEC"): + args = line[line.find("(") + 1: line.find(")")].split(", ") + rv64_regs.append(args[0]) + + with open(os.path.join(BUILD_DIR, "rv64_reg"), "w") as out: + out.write('
      \n') + for name in rv64_regs: + out.write("
    • REG.RISCV64.{}
    • \n".format(name)) + out.write('
    \n') + +############################################################################## + +elif SPEC.find('riscv32') >= 0: + with open(SPEC, "r") as f: + for line in f.readlines(): + if line.startswith("REG_SPEC") or line.startswith("SYS_REG_SPEC"): + args = line[line.find("(") + 1: line.find(")")].split(", ") + rv32_regs.append(args[0]) + + with open(os.path.join(BUILD_DIR, "rv32_reg"), "w") as out: + out.write('
      \n') + for name in rv32_regs: + out.write("
    • REG.RISCV32.{}
    • \n".format(name)) + out.write('
    \n') diff --git a/src/examples/python/ctf-writeups/custom-crackmes/riscv32-hash/crackme_hash b/src/examples/python/ctf-writeups/custom-crackmes/riscv32-hash/crackme_hash new file mode 100755 index 000000000..e3dd2f017 Binary files /dev/null and b/src/examples/python/ctf-writeups/custom-crackmes/riscv32-hash/crackme_hash differ diff --git a/src/examples/python/ctf-writeups/custom-crackmes/riscv32-hash/crackme_hash.c b/src/examples/python/ctf-writeups/custom-crackmes/riscv32-hash/crackme_hash.c new file mode 100644 index 000000000..3b2f54417 --- /dev/null +++ b/src/examples/python/ctf-writeups/custom-crackmes/riscv32-hash/crackme_hash.c @@ -0,0 +1,33 @@ + +#include +#include + +char *serial = "\x31\x3e\x3d\x26\x31"; + +int check(char *ptr) +{ + int i; + int hash = 0xABCD; + + for (i = 0; ptr[i]; i++) + hash += ptr[i] ^ serial[i % 5]; + + return hash; +} + +int main(int ac, char **av) +{ + int ret; + + if (ac != 2) + return -1; + + ret = check(av[1]); + if (ret == 0xad6d) + printf("Win\n"); + else + printf("fail\n"); + + return 0; +} + diff --git a/src/examples/python/ctf-writeups/custom-crackmes/riscv32-hash/solve-with-abv-logic.py b/src/examples/python/ctf-writeups/custom-crackmes/riscv32-hash/solve-with-abv-logic.py new file mode 100755 index 000000000..a94d7b425 --- /dev/null +++ b/src/examples/python/ctf-writeups/custom-crackmes/riscv32-hash/solve-with-abv-logic.py @@ -0,0 +1,402 @@ +#!/usr/bin/env python3 +## -*- coding: utf-8 -*- +## +## May 2024. Based on Jonathan Salwan - 2018-12-26 +## +## A custom crackme to test the RISCV64 architecture. The goal is to find a hash +## collision to take the 'Win' branch. First we run the binary with a random +## seed, then we calculate the hash collision and run a second time the binary with +## the good input to take the 'Win' branch. +## +## Output: +## +## $ time ./solve-with-abv-logic.py +## [+] Loading 0x010034 - 0x010174 +## [+] Loading 0x010174 - 0x010196 +## [+] Loading 0x000000 - 0x000053 +## [+] Loading 0x010000 - 0x010554 +## [+] Loading 0x011ef8 - 0x012010 +## [+] Loading 0x011f04 - 0x011ff4 +## [+] Loading 0x010198 - 0x0101b8 +## [+] Loading 0x01044c - 0x010490 +## [+] Loading 0x000000 - 0x000000 +## [+] Loading 0x011ef8 - 0x012000 +## [+] Hooking __libc_start_main +## [+] Hooking puts +## [+] Hooking __libc_start_main +## [+] Hooking puts +## [+] Starting emulation. +## [+] __libc_start_main hooked +## [+] argv[0] = b'./crackme_hash' +## [+] argv[1] = b'riscv' +## [+] Please wait, calculating hash collisions... +## [+] Found several hash collisions: +## {0: "0x69, 'i'", 4: "0x65, 'e'", 3: "0x62, 'b'", 1: "0x61, 'a'", 2: "0x6c, 'l'"} +## {0: "0x71, 'q'", 1: "0x63, 'c'", 4: "0x64, 'd'", 3: "0x78, 'x'", 2: "0x6d, 'm'"} +## {0: "0x71, 'q'", 1: "0x6b, 'k'", 4: "0x6c, 'l'", 3: "0x78, 'x'", 2: "0x6d, 'm'"} +## {0: "0x71, 'q'", 1: "0x6a, 'j'", 4: "0x6c, 'l'", 3: "0x79, 'y'", 2: "0x6d, 'm'"} +## {0: "0x71, 'q'", 1: "0x6b, 'k'", 4: "0x6d, 'm'", 3: "0x79, 'y'", 2: "0x6d, 'm'"} +## {0: "0x71, 'q'", 1: "0x61, 'a'", 4: "0x6d, 'm'", 3: "0x73, 's'", 2: "0x6d, 'm'"} +## {0: "0x75, 'u'", 1: "0x61, 'a'", 4: "0x6d, 'm'", 3: "0x73, 's'", 2: "0x71, 'q'"} +## {0: "0x79, 'y'", 1: "0x61, 'a'", 4: "0x6d, 'm'", 3: "0x73, 's'", 2: "0x75, 'u'"} +## {0: "0x74, 't'", 1: "0x61, 'a'", 4: "0x6d, 'm'", 3: "0x73, 's'", 2: "0x76, 'v'"} +## {0: "0x70, 'p'", 1: "0x61, 'a'", 4: "0x6d, 'm'", 3: "0x73, 's'", 2: "0x72, 'r'"} +## {0: "0x70, 'p'", 1: "0x71, 'q'", 4: "0x6d, 'm'", 3: "0x73, 's'", 2: "0x62, 'b'"} +## {0: "0x70, 'p'", 1: "0x70, 'p'", 4: "0x6d, 'm'", 3: "0x70, 'p'", 2: "0x62, 'b'"} +## {0: "0x74, 't'", 1: "0x70, 'p'", 4: "0x6d, 'm'", 3: "0x70, 'p'", 2: "0x66, 'f'"} +## {0: "0x74, 't'", 1: "0x70, 'p'", 4: "0x6f, 'o'", 3: "0x72, 'r'", 2: "0x66, 'f'"} +## {0: "0x74, 't'", 1: "0x64, 'd'", 4: "0x63, 'c'", 3: "0x72, 'r'", 2: "0x66, 'f'"} +## {0: "0x70, 'p'", 1: "0x64, 'd'", 4: "0x63, 'c'", 3: "0x72, 'r'", 2: "0x62, 'b'"} +## {0: "0x70, 'p'", 1: "0x64, 'd'", 4: "0x65, 'e'", 3: "0x74, 't'", 2: "0x62, 'b'"} +## {0: "0x74, 't'", 1: "0x64, 'd'", 4: "0x65, 'e'", 3: "0x74, 't'", 2: "0x66, 'f'"} +## {0: "0x74, 't'", 1: "0x64, 'd'", 4: "0x61, 'a'", 3: "0x70, 'p'", 2: "0x66, 'f'"} +## {0: "0x70, 'p'", 1: "0x64, 'd'", 4: "0x61, 'a'", 3: "0x70, 'p'", 2: "0x62, 'b'"} +## [+] Pick up the first serial: qcmxd +## [+] puts hooked +## fail +## [+] Instruction executed: 92 +## [+] Emulation done. +## [+] Start a second emulation with the good serial to validate the chall +## [+] Loading 0x010034 - 0x010174 +## [+] Loading 0x010174 - 0x010196 +## [+] Loading 0x000000 - 0x000053 +## [+] Loading 0x010000 - 0x010554 +## [+] Loading 0x011ef8 - 0x012010 +## [+] Loading 0x011f04 - 0x011ff4 +## [+] Loading 0x010198 - 0x0101b8 +## [+] Loading 0x01044c - 0x010490 +## [+] Loading 0x000000 - 0x000000 + + +from __future__ import print_function +from triton import * + +import random +import string +import sys +import lief +import os + + +DEBUG = True +MY_INPUT = 'riscv' +SERIAL = None +TARGET = os.path.join(os.path.dirname(__file__), 'crackme_hash') +VALID = False + +# The debug function +def debug(s): + if DEBUG: print(s) + +# Memory mapping +BASE_PLT = 0x10000000 +BASE_ARGV = 0x20000000 +BASE_SERIAL = 0x30000000 +BASE_SERIAL_ADDR = 0x1200c +BASE_STACK = 0x9fffffff + + +def getMemoryString(ctx, addr): + s = str() + index = 0 + + while ctx.getConcreteMemoryValue(addr+index): + c = chr(ctx.getConcreteMemoryValue(addr+index)) + if c not in string.printable: c = "" + s += c + index += 1 + + return s + + +# Simulate the puts() function +def putsHandler(ctx): + debug('[+] puts hooked') + + # Get arguments + arg1 = getMemoryString(ctx, ctx.getConcreteRegisterValue(ctx.registers.x10)) + sys.stdout.write(arg1 + '\n') + + # Return value + return len(arg1) + 1 + + +def exitHandler(ctx): + debug('[+] exit hooked') + sys.exit(0) + + +def libcMainHandler(ctx): + global MY_INPUT + debug('[+] __libc_start_main hooked') + + # Setup argc / argv + ctx.concretizeRegister(ctx.registers.x10) + ctx.concretizeRegister(ctx.registers.x11) + + argvs = [ + bytes(TARGET.encode('utf-8')), # argv[0] + bytes(MY_INPUT.encode('utf-8')) + ] + + # Define argc / argv + base = BASE_ARGV + addrs = list() + + index = 0 + for argv in argvs: + addrs.append(base) + ctx.setConcreteMemoryAreaValue(base, argv+b'\x00\x00\x00') + if index == 1: + # Only symbolized argv[1] + for indexCell in range(len(argv)): + var = ctx.symbolizeMemory(MemoryAccess(base+indexCell, CPUSIZE.BYTE)) + var.setComment('argv[%d][%d]' %(index, indexCell)) + debug('[+] argv[%d] = %s' %(index, argv)) + base += len(argv)+1 + index += 1 + + argc = len(argvs) + argv = base + for addr in addrs: + ctx.setConcreteMemoryValue(MemoryAccess(base, CPUSIZE.DWORD), addr) + base += CPUSIZE.DWORD + + ctx.setConcreteRegisterValue(ctx.registers.x10, argc) + ctx.setConcreteRegisterValue(ctx.registers.x11, argv) + + return None + + +# Functions to emulate +customRelocation = [ + ('__libc_start_main', libcMainHandler, BASE_PLT + 0), + ('exit', exitHandler, BASE_PLT + 1 << 2), + ('puts', putsHandler, BASE_PLT + 2 << 2), +] + + +def hookingHandler(ctx): + pc = ctx.getConcreteRegisterValue(ctx.registers.pc) + for rel in customRelocation: + if rel[2] == pc: + # Emulate the routine and the return value + x10 = ctx.getConcreteRegisterValue(ctx.registers.x10) + ret_value = rel[1](ctx) + if ret_value is not None: + ctx.setConcreteRegisterValue(ctx.registers.x10, ret_value) + + # Get the return address + ret_addr = ctx.getConcreteRegisterValue(ctx.registers.x1) + # Set ret_addr to main() address when __libc_start_main is hooked + if pc == BASE_PLT: + ret_addr = x10 + + # Hijack RIP to skip the call + ctx.setConcreteRegisterValue(ctx.registers.pc, ret_addr) + + # Restore RSP (simulate the ret) + ctx.setConcreteRegisterValue(ctx.registers.x2, ctx.getConcreteRegisterValue(ctx.registers.x2)+CPUSIZE.DWORD) + return + +# Emulate the binary. +def emulate(ctx, pc): + global SERIAL + global VALID + # Set serial string address loaded by: + # 10404: 00c7a883 lw a7,12(a5) # 1200c + + ctx.setConcreteMemoryAreaValue(BASE_SERIAL_ADDR, b"\x00\x00\x00\x30\x00\x00\x00\x00") + # Set serial string content + ctx.setConcreteMemoryAreaValue(BASE_SERIAL, '1>=&1'.encode('utf-8')+b'\x00\x00\x00') + + ctx.setConcreteRegisterValue(ctx.registers.pc, pc) + count = 0 + while pc: + # Fetch opcodes + opcodes = ctx.getConcreteMemoryAreaValue(pc, 4) + + # Create the Triton instruction + + instruction = Instruction() + instruction.setOpcode(opcodes) + instruction.setAddress(pc) + + # Process + if ctx.processing(instruction) == EXCEPTION.FAULT_UD: + debug('[-] Instruction not supported: %s' %(str(instruction))) + break + #else: + # debug('[~] Instruction processing: %s' %(str(instruction))) + + # 10358: 6541 lui a0,0x10 + # 1035a: 43850513 addi a0,a0,1080 # 10438 <_IO_stdin_used+0x4> + # 1035e: 37c9 jal 10320 + # ... + # 10438: 006e6957 .4byte 0x6e6957 # "Win" + + + if pc == 0x1035e: + # We validated the crackme + VALID = True + + # 10400: 67c9 lui a5,0x12 + # 10402: 652d lui a0,0xb + # 10404: 00c7a883 lw a7,12(a5) # 1200c + # 10408: bcd50513 addi a0,a0,-1075 # abcd <__abi_tag-0x55cb> + + # 10344: 00f50a63 beq a0,a5,10358 # jump to Win puts if equal + if pc == 0x10344 and SERIAL is None: + print('[+] Please wait, calculating hash collisions...') + + SymVar_0 = ctx.getSymbolicVariable('SymVar_0') + SymVar_1 = ctx.getSymbolicVariable('SymVar_1') + SymVar_2 = ctx.getSymbolicVariable('SymVar_2') + SymVar_3 = ctx.getSymbolicVariable('SymVar_3') + SymVar_4 = ctx.getSymbolicVariable('SymVar_4') + + astCtxt = ctx.getAstContext() + + # We want printable characters + a0 = ctx.getSymbolicRegister(ctx.registers.x10) + expr = astCtxt.land([ + astCtxt.bvugt(astCtxt.variable(SymVar_0), astCtxt.bv(96, CPUSIZE.BYTE_BIT)), + astCtxt.bvult(astCtxt.variable(SymVar_0), astCtxt.bv(123, CPUSIZE.BYTE_BIT)), + astCtxt.bvugt(astCtxt.variable(SymVar_1), astCtxt.bv(96, CPUSIZE.BYTE_BIT)), + astCtxt.bvult(astCtxt.variable(SymVar_1), astCtxt.bv(123, CPUSIZE.BYTE_BIT)), + astCtxt.bvugt(astCtxt.variable(SymVar_2), astCtxt.bv(96, CPUSIZE.BYTE_BIT)), + astCtxt.bvult(astCtxt.variable(SymVar_2), astCtxt.bv(123, CPUSIZE.BYTE_BIT)), + astCtxt.bvugt(astCtxt.variable(SymVar_3), astCtxt.bv(96, CPUSIZE.BYTE_BIT)), + astCtxt.bvult(astCtxt.variable(SymVar_3), astCtxt.bv(123, CPUSIZE.BYTE_BIT)), + astCtxt.bvugt(astCtxt.variable(SymVar_4), astCtxt.bv(96, CPUSIZE.BYTE_BIT)), + astCtxt.bvult(astCtxt.variable(SymVar_4), astCtxt.bv(123, CPUSIZE.BYTE_BIT)), + astCtxt.equal(a0.getAst(), astCtxt.bv(0xad6d, CPUSIZE.DWORD_BIT)) # collision: (assert (= a4 0xad6d) + ]) + + # Get max 20 different models + models = ctx.getModels(expr, 20) + if len(models) == 0: + print('OOOPS! No models') + return + print('[+] Found several hash collisions:') + for model in models: + print({k: "0x%x, '%c'" % (v.getValue(), v.getValue()) for k, v in list(model.items())}) + + SERIAL = str() + for _, v in list(sorted(models[1].items())): + # NOTE only readable allowed + SERIAL += "%c" % (v.getValue()) + + print('[+] Pick up the first serial: %s' %(SERIAL)) + + # Return from main + if pc == 0x10364: + break + + # Inc the number of instructions exected + count += 1 + + # Simulate routines + hookingHandler(ctx) + + # Next + pc = ctx.getConcreteRegisterValue(ctx.registers.pc) + + debug('[+] Instruction executed: %d' %(count)) + return + + +def loadBinary(ctx, binary): + # Map the binary into the memory + phdrs = binary.segments + for phdr in phdrs: + size = phdr.physical_size + vaddr = phdr.virtual_address + debug('[+] Loading 0x%06x - 0x%06x' %(vaddr, vaddr+size)) + ctx.setConcreteMemoryAreaValue(vaddr, list(phdr.content)) + return + + +def makeRelocation(ctx, binary): + # Perform our own relocations + try: + for rel in binary.pltgot_relocations: + symbolName = rel.symbol.name + symbolRelo = rel.address + for crel in customRelocation: + if symbolName == crel[0]: + debug('[+] Hooking %s' %(symbolName)) + ctx.setConcreteMemoryValue(MemoryAccess(symbolRelo, CPUSIZE.DWORD), crel[2]) + except: + pass + + # Perform our own relocations + try: + for rel in binary.dynamic_relocations: + symbolName = rel.symbol.name + symbolRelo = rel.address + for crel in customRelocation: + if symbolName == crel[0]: + debug('[+] Hooking %s' %(symbolName)) + ctx.setConcreteMemoryValue(MemoryAccess(symbolRelo, CPUSIZE.DWORD), crel[2]) + except: + pass + return + + +def run(ctx, binary): + # Concretize previous context + ctx.concretizeAllMemory() + ctx.concretizeAllRegister() + + # Load the binary + loadBinary(ctx, binary) + + # Perform our own relocations + makeRelocation(ctx, binary) + + # Define a fake stack + ctx.setConcreteRegisterValue(ctx.registers.x2, BASE_STACK) + + # Let's emulate the binary from the entry point + debug('[+] Starting emulation.') + emulate(ctx, binary.entrypoint) + debug('[+] Emulation done.') + return + + +def main(): + global MY_INPUT + global SERIAL + SERIAL = None + + # Get a Triton context + ctx = TritonContext() + + # Set the architecture + ctx.setArchitecture(ARCH.RV32) + + # Set optimization + ctx.setMode(MODE.MEMORY_ARRAY, True) + ctx.setMode(MODE.CONSTANT_FOLDING, True) + ctx.setMode(MODE.AST_OPTIMIZATIONS, True) + + # Parse the binary + binary = lief.parse(TARGET) + + # First emulation + run(ctx, binary) + + # Replace the input with the good serial to validate the chall + MY_INPUT = SERIAL + + # Second emulation + print('[+] Start a second emulation with the good serial to validate the chall') + run(ctx, binary) + + return not VALID == True + + +if __name__ == '__main__': + retValue = main() + sys.exit(retValue) diff --git a/src/examples/python/ctf-writeups/custom-crackmes/riscv32-hash/solve.py b/src/examples/python/ctf-writeups/custom-crackmes/riscv32-hash/solve.py new file mode 100755 index 000000000..33ca2c83c --- /dev/null +++ b/src/examples/python/ctf-writeups/custom-crackmes/riscv32-hash/solve.py @@ -0,0 +1,402 @@ +#!/usr/bin/env python3 +## -*- coding: utf-8 -*- +## +## May 2024. Based on Jonathan Salwan - 2018-12-26 +## +## A custom crackme to test the RISCV64 architecture. The goal is to find a hash +## collision to take the 'Win' branch. First we run the binary with a random +## seed, then we calculate the hash collision and run a second time the binary with +## the good input to take the 'Win' branch. +## +## Output: +## +## $ time ./solve.py +## [+] Loading 0x010034 - 0x010174 +## [+] Loading 0x010174 - 0x010196 +## [+] Loading 0x000000 - 0x000053 +## [+] Loading 0x010000 - 0x010554 +## [+] Loading 0x011ef8 - 0x012010 +## [+] Loading 0x011f04 - 0x011ff4 +## [+] Loading 0x010198 - 0x0101b8 +## [+] Loading 0x01044c - 0x010490 +## [+] Loading 0x000000 - 0x000000 +## [+] Loading 0x011ef8 - 0x012000 +## [+] Hooking __libc_start_main +## [+] Hooking puts +## [+] Hooking __libc_start_main +## [+] Hooking puts +## [+] Starting emulation. +## [+] __libc_start_main hooked +## [+] argv[0] = b'./crackme_hash' +## [+] argv[1] = b'riscv' +## [+] Please wait, calculating hash collisions... +## [+] Found several hash collisions: +## {0: "0x69, 'i'", 4: "0x65, 'e'", 3: "0x62, 'b'", 1: "0x61, 'a'", 2: "0x6c, 'l'"} +## {0: "0x70, 'p'", 1: "0x62, 'b'", 4: "0x78, 'x'", 3: "0x78, 'x'", 2: "0x61, 'a'"} +## {0: "0x78, 'x'", 1: "0x62, 'b'", 4: "0x78, 'x'", 3: "0x70, 'p'", 2: "0x61, 'a'"} +## {0: "0x70, 'p'", 1: "0x6a, 'j'", 4: "0x68, 'h'", 3: "0x70, 'p'", 2: "0x61, 'a'"} +## {0: "0x70, 'p'", 1: "0x66, 'f'", 4: "0x68, 'h'", 3: "0x74, 't'", 2: "0x61, 'a'"} +## {0: "0x78, 'x'", 1: "0x66, 'f'", 4: "0x68, 'h'", 3: "0x6c, 'l'", 2: "0x61, 'a'"} +## {0: "0x78, 'x'", 1: "0x62, 'b'", 4: "0x68, 'h'", 3: "0x6c, 'l'", 2: "0x65, 'e'"} +## {0: "0x78, 'x'", 1: "0x66, 'f'", 4: "0x68, 'h'", 3: "0x68, 'h'", 2: "0x65, 'e'"} +## {0: "0x62, 'b'", 1: "0x66, 'f'", 4: "0x68, 'h'", 3: "0x62, 'b'", 2: "0x65, 'e'"} +## {0: "0x7a, 'z'", 1: "0x66, 'f'", 4: "0x68, 'h'", 3: "0x6a, 'j'", 2: "0x65, 'e'"} +## {0: "0x78, 'x'", 1: "0x66, 'f'", 4: "0x68, 'h'", 3: "0x6a, 'j'", 2: "0x67, 'g'"} +## {0: "0x70, 'p'", 1: "0x66, 'f'", 4: "0x68, 'h'", 3: "0x72, 'r'", 2: "0x67, 'g'"} +## {0: "0x70, 'p'", 1: "0x66, 'f'", 4: "0x6a, 'j'", 3: "0x72, 'r'", 2: "0x65, 'e'"} +## {0: "0x70, 'p'", 1: "0x62, 'b'", 4: "0x64, 'd'", 3: "0x72, 'r'", 2: "0x67, 'g'"} +## {0: "0x70, 'p'", 1: "0x62, 'b'", 4: "0x64, 'd'", 3: "0x70, 'p'", 2: "0x65, 'e'"} +## {0: "0x68, 'h'", 1: "0x66, 'f'", 4: "0x64, 'd'", 3: "0x64, 'd'", 2: "0x65, 'e'"} +## {0: "0x68, 'h'", 1: "0x6a, 'j'", 4: "0x64, 'd'", 3: "0x64, 'd'", 2: "0x61, 'a'"} +## {0: "0x68, 'h'", 1: "0x66, 'f'", 4: "0x61, 'a'", 3: "0x65, 'e'", 2: "0x61, 'a'"} +## {0: "0x68, 'h'", 1: "0x66, 'f'", 4: "0x61, 'a'", 3: "0x67, 'g'", 2: "0x63, 'c'"} +## {0: "0x68, 'h'", 1: "0x6a, 'j'", 4: "0x65, 'e'", 3: "0x67, 'g'", 2: "0x63, 'c'"} +## [+] Pick up the first serial: pbaxx +## [+] puts hooked +## fail +## [+] Instruction executed: 92 +## [+] Emulation done. +## [+] Start a second emulation with the good serial to validate the chall +## [+] Starting emulation. +## [+] __libc_start_main hooked +## [+] argv[0] = b'./crackme_hash' +## [+] argv[1] = b'pbaxx' +## [+] puts hooked +## Win +## [+] Instruction executed: 93 +## [+] Emulation done. +## ./solve.py 0,08s user 0,02s system 99% cpu 0,094 total + + +from __future__ import print_function +from triton import * + +import random +import string +import sys +import lief +import os + + +DEBUG = True +MY_INPUT = 'riscv' +SERIAL = None +TARGET = os.path.join(os.path.dirname(__file__), 'crackme_hash') +VALID = False + +# The debug function +def debug(s): + if DEBUG: print(s) + +# Memory mapping +BASE_PLT = 0x10000000 +BASE_ARGV = 0x20000000 +BASE_SERIAL = 0x30000000 +BASE_SERIAL_ADDR = 0x1200c +BASE_STACK = 0x9fffffff + + +def getMemoryString(ctx, addr): + s = str() + index = 0 + + while ctx.getConcreteMemoryValue(addr+index): + c = chr(ctx.getConcreteMemoryValue(addr+index)) + if c not in string.printable: c = "" + s += c + index += 1 + + return s + + +# Simulate the puts() function +def putsHandler(ctx): + debug('[+] puts hooked') + + # Get arguments + arg1 = getMemoryString(ctx, ctx.getConcreteRegisterValue(ctx.registers.x10)) + sys.stdout.write(arg1 + '\n') + + # Return value + return len(arg1) + 1 + + +def exitHandler(ctx): + debug('[+] exit hooked') + sys.exit(0) + + +def libcMainHandler(ctx): + global MY_INPUT + debug('[+] __libc_start_main hooked') + + # Setup argc / argv + ctx.concretizeRegister(ctx.registers.x10) + ctx.concretizeRegister(ctx.registers.x11) + + argvs = [ + bytes(TARGET.encode('utf-8')), # argv[0] + bytes(MY_INPUT.encode('utf-8')) + ] + + # Define argc / argv + base = BASE_ARGV + addrs = list() + + index = 0 + for argv in argvs: + addrs.append(base) + ctx.setConcreteMemoryAreaValue(base, argv+b'\x00\x00\x00') + if index == 1: + # Only symbolized argv[1] + for indexCell in range(len(argv)): + var = ctx.symbolizeMemory(MemoryAccess(base+indexCell, CPUSIZE.BYTE)) + var.setComment('argv[%d][%d]' %(index, indexCell)) + debug('[+] argv[%d] = %s' %(index, argv)) + base += len(argv)+1 + index += 1 + + argc = len(argvs) + argv = base + for addr in addrs: + ctx.setConcreteMemoryValue(MemoryAccess(base, CPUSIZE.DWORD), addr) + base += CPUSIZE.DWORD + + ctx.setConcreteRegisterValue(ctx.registers.x10, argc) + ctx.setConcreteRegisterValue(ctx.registers.x11, argv) + + return None + + +# Functions to emulate +customRelocation = [ + ('__libc_start_main', libcMainHandler, BASE_PLT + 0), + ('exit', exitHandler, BASE_PLT + 1 << 2), + ('puts', putsHandler, BASE_PLT + 2 << 2), +] + + +def hookingHandler(ctx): + pc = ctx.getConcreteRegisterValue(ctx.registers.pc) + for rel in customRelocation: + if rel[2] == pc: + # Emulate the routine and the return value + x10 = ctx.getConcreteRegisterValue(ctx.registers.x10) + ret_value = rel[1](ctx) + if ret_value is not None: + ctx.setConcreteRegisterValue(ctx.registers.x10, ret_value) + + # Get the return address + ret_addr = ctx.getConcreteRegisterValue(ctx.registers.x1) + # Set ret_addr to main() address when __libc_start_main is hooked + if pc == BASE_PLT: + ret_addr = x10 + + # Hijack RIP to skip the call + ctx.setConcreteRegisterValue(ctx.registers.pc, ret_addr) + + # Restore RSP (simulate the ret) + ctx.setConcreteRegisterValue(ctx.registers.x2, ctx.getConcreteRegisterValue(ctx.registers.x2)+CPUSIZE.DWORD) + return + +# Emulate the binary. +def emulate(ctx, pc): + global SERIAL + global VALID + # Set serial string address loaded by: + # 10404: 00c7a883 lw a7,12(a5) # 1200c + + ctx.setConcreteMemoryAreaValue(BASE_SERIAL_ADDR, b"\x00\x00\x00\x30\x00\x00\x00\x00") + # Set serial string content + ctx.setConcreteMemoryAreaValue(BASE_SERIAL, '1>=&1'.encode('utf-8')+b'\x00\x00\x00') + + ctx.setConcreteRegisterValue(ctx.registers.pc, pc) + count = 0 + while pc: + # Fetch opcodes + opcodes = ctx.getConcreteMemoryAreaValue(pc, 4) + + # Create the Triton instruction + + instruction = Instruction() + instruction.setOpcode(opcodes) + instruction.setAddress(pc) + + # Process + if ctx.processing(instruction) == EXCEPTION.FAULT_UD: + debug('[-] Instruction not supported: %s' %(str(instruction))) + break + #else: + # debug('[~] Instruction processing: %s' %(str(instruction))) + + # 10358: 6541 lui a0,0x10 + # 1035a: 43850513 addi a0,a0,1080 # 10438 <_IO_stdin_used+0x4> + # 1035e: 37c9 jal 10320 + # ... + # 10438: 006e6957 .4byte 0x6e6957 # "Win" + + + if pc == 0x1035e: + # We validated the crackme + VALID = True + + # 10400: 67c9 lui a5,0x12 + # 10402: 652d lui a0,0xb + # 10404: 00c7a883 lw a7,12(a5) # 1200c + # 10408: bcd50513 addi a0,a0,-1075 # abcd <__abi_tag-0x55cb> + + # 10344: 00f50a63 beq a0,a5,10358 # jump to Win puts if equal + if pc == 0x10344 and SERIAL is None: + print('[+] Please wait, calculating hash collisions...') + + SymVar_0 = ctx.getSymbolicVariable('SymVar_0') + SymVar_1 = ctx.getSymbolicVariable('SymVar_1') + SymVar_2 = ctx.getSymbolicVariable('SymVar_2') + SymVar_3 = ctx.getSymbolicVariable('SymVar_3') + SymVar_4 = ctx.getSymbolicVariable('SymVar_4') + + astCtxt = ctx.getAstContext() + + # We want printable characters + a0 = ctx.getSymbolicRegister(ctx.registers.x10) + expr = astCtxt.land([ + astCtxt.bvugt(astCtxt.variable(SymVar_0), astCtxt.bv(96, CPUSIZE.BYTE_BIT)), + astCtxt.bvult(astCtxt.variable(SymVar_0), astCtxt.bv(123, CPUSIZE.BYTE_BIT)), + astCtxt.bvugt(astCtxt.variable(SymVar_1), astCtxt.bv(96, CPUSIZE.BYTE_BIT)), + astCtxt.bvult(astCtxt.variable(SymVar_1), astCtxt.bv(123, CPUSIZE.BYTE_BIT)), + astCtxt.bvugt(astCtxt.variable(SymVar_2), astCtxt.bv(96, CPUSIZE.BYTE_BIT)), + astCtxt.bvult(astCtxt.variable(SymVar_2), astCtxt.bv(123, CPUSIZE.BYTE_BIT)), + astCtxt.bvugt(astCtxt.variable(SymVar_3), astCtxt.bv(96, CPUSIZE.BYTE_BIT)), + astCtxt.bvult(astCtxt.variable(SymVar_3), astCtxt.bv(123, CPUSIZE.BYTE_BIT)), + astCtxt.bvugt(astCtxt.variable(SymVar_4), astCtxt.bv(96, CPUSIZE.BYTE_BIT)), + astCtxt.bvult(astCtxt.variable(SymVar_4), astCtxt.bv(123, CPUSIZE.BYTE_BIT)), + astCtxt.equal(a0.getAst(), astCtxt.bv(0xad6d, CPUSIZE.DWORD_BIT)) # collision: (assert (= a4 0xad6d) + ]) + + # Get max 20 different models + models = ctx.getModels(expr, 20) + if len(models) == 0: + print('OOOPS! No models') + return + print('[+] Found several hash collisions:') + for model in models: + print({k: "0x%x, '%c'" % (v.getValue(), v.getValue()) for k, v in list(model.items())}) + + SERIAL = str() + for _, v in list(sorted(models[1].items())): + # NOTE only readable allowed + SERIAL += "%c" % (v.getValue()) + + print('[+] Pick up the first serial: %s' %(SERIAL)) + + # Return from main + if pc == 0x10364: + break + + # Inc the number of instructions exected + count += 1 + + # Simulate routines + hookingHandler(ctx) + + # Next + pc = ctx.getConcreteRegisterValue(ctx.registers.pc) + + debug('[+] Instruction executed: %d' %(count)) + return + + +def loadBinary(ctx, binary): + # Map the binary into the memory + phdrs = binary.segments + for phdr in phdrs: + size = phdr.physical_size + vaddr = phdr.virtual_address + debug('[+] Loading 0x%06x - 0x%06x' %(vaddr, vaddr+size)) + ctx.setConcreteMemoryAreaValue(vaddr, list(phdr.content)) + return + + +def makeRelocation(ctx, binary): + # Perform our own relocations + try: + for rel in binary.pltgot_relocations: + symbolName = rel.symbol.name + symbolRelo = rel.address + for crel in customRelocation: + if symbolName == crel[0]: + debug('[+] Hooking %s' %(symbolName)) + ctx.setConcreteMemoryValue(MemoryAccess(symbolRelo, CPUSIZE.DWORD), crel[2]) + except: + pass + + # Perform our own relocations + try: + for rel in binary.dynamic_relocations: + symbolName = rel.symbol.name + symbolRelo = rel.address + for crel in customRelocation: + if symbolName == crel[0]: + debug('[+] Hooking %s' %(symbolName)) + ctx.setConcreteMemoryValue(MemoryAccess(symbolRelo, CPUSIZE.DWORD), crel[2]) + except: + pass + return + + +def run(ctx, binary): + # Concretize previous context + ctx.concretizeAllMemory() + ctx.concretizeAllRegister() + + # Define a fake stack + ctx.setConcreteRegisterValue(ctx.registers.x2, BASE_STACK) + + # Let's emulate the binary from the entry point + debug('[+] Starting emulation.') + emulate(ctx, binary.entrypoint) + debug('[+] Emulation done.') + return + + +def main(): + global MY_INPUT + global SERIAL + SERIAL = None + + # Get a Triton context + ctx = TritonContext() + + # Set the architecture + ctx.setArchitecture(ARCH.RV32) + + # Set optimization + ctx.setMode(MODE.ALIGNED_MEMORY, True) + ctx.setMode(MODE.ONLY_ON_SYMBOLIZED, True) + #ctx.setMode(MODE.AST_OPTIMIZATIONS, True) + + # Parse the binary + binary = lief.parse(TARGET) + + # Load the binary + loadBinary(ctx, binary) + + # Perform our own relocations + makeRelocation(ctx, binary) + + # First emulation + run(ctx, binary) + + # Replace the input with the good serial to validate the chall + MY_INPUT = SERIAL + + # Second emulation + print('[+] Start a second emulation with the good serial to validate the chall') + run(ctx, binary) + + return not VALID == True + + +if __name__ == '__main__': + retValue = main() + sys.exit(retValue) diff --git a/src/examples/python/ctf-writeups/custom-crackmes/riscv64-hash/crackme_hash b/src/examples/python/ctf-writeups/custom-crackmes/riscv64-hash/crackme_hash new file mode 100755 index 000000000..375aebd41 Binary files /dev/null and b/src/examples/python/ctf-writeups/custom-crackmes/riscv64-hash/crackme_hash differ diff --git a/src/examples/python/ctf-writeups/custom-crackmes/riscv64-hash/crackme_hash.c b/src/examples/python/ctf-writeups/custom-crackmes/riscv64-hash/crackme_hash.c new file mode 100644 index 000000000..3b2f54417 --- /dev/null +++ b/src/examples/python/ctf-writeups/custom-crackmes/riscv64-hash/crackme_hash.c @@ -0,0 +1,33 @@ + +#include +#include + +char *serial = "\x31\x3e\x3d\x26\x31"; + +int check(char *ptr) +{ + int i; + int hash = 0xABCD; + + for (i = 0; ptr[i]; i++) + hash += ptr[i] ^ serial[i % 5]; + + return hash; +} + +int main(int ac, char **av) +{ + int ret; + + if (ac != 2) + return -1; + + ret = check(av[1]); + if (ret == 0xad6d) + printf("Win\n"); + else + printf("fail\n"); + + return 0; +} + diff --git a/src/examples/python/ctf-writeups/custom-crackmes/riscv64-hash/solve-with-abv-logic.py b/src/examples/python/ctf-writeups/custom-crackmes/riscv64-hash/solve-with-abv-logic.py new file mode 100755 index 000000000..a5191edcc --- /dev/null +++ b/src/examples/python/ctf-writeups/custom-crackmes/riscv64-hash/solve-with-abv-logic.py @@ -0,0 +1,418 @@ +#!/usr/bin/env python3 +## -*- coding: utf-8 -*- +## +## May 2024. Based on Jonathan Salwan - 2018-12-26 +## +## A custom crackme to test the RISCV64 architecture. The goal is to find a hash +## collision to take the 'Win' branch. First we run the binary with a random +## seed, then we calculate the hash collision and run a second time the binary with +## the good input to take the 'Win' branch. +## +## Output: +## +## $ time ./solve-with-abv-logic.py +## [+] Loading 0x000040 - 0x000270 +## [+] Loading 0x000270 - 0x000291 +## [+] Loading 0x000000 - 0x00003c +## [+] Loading 0x000000 - 0x0007b4 +## [+] Loading 0x001df8 - 0x002058 +## [+] Loading 0x001e10 - 0x002000 +## [+] Loading 0x000294 - 0x0002d8 +## [+] Loading 0x000770 - 0x000784 +## [+] Loading 0x000000 - 0x000000 +## [+] Loading 0x001df8 - 0x002000 +## [+] Hooking __libc_start_main +## [+] Hooking puts +## [+] Hooking __libc_start_main +## [+] Hooking puts +## [+] Starting emulation. +## [+] __libc_start_main hooked +## [+] argv[0] = b'./crackme_hash' +## [+] argv[1] = b'riscv' +## [+] Please wait, calculating hash collisions... +## [+] Found several hash collisions: +## {0: "0x69, 'i'", 4: "0x65, 'e'", 3: "0x62, 'b'", 1: "0x61, 'a'", 2: "0x6c, 'l'"} +## {0: "0x61, 'a'", 4: "0x6a, 'j'", 1: "0x62, 'b'", 3: "0x6a, 'j'", 2: "0x70, 'p'"} +## {0: "0x71, 'q'", 4: "0x6e, 'n'", 1: "0x62, 'b'", 3: "0x6a, 'j'", 2: "0x64, 'd'"} +## {0: "0x71, 'q'", 4: "0x6e, 'n'", 1: "0x63, 'c'", 3: "0x6c, 'l'", 2: "0x67, 'g'"} +## {0: "0x75, 'u'", 4: "0x6a, 'j'", 1: "0x63, 'c'", 3: "0x6c, 'l'", 2: "0x67, 'g'"} +## {0: "0x75, 'u'", 4: "0x6e, 'n'", 1: "0x67, 'g'", 3: "0x6c, 'l'", 2: "0x67, 'g'"} +## {0: "0x75, 'u'", 4: "0x6e, 'n'", 1: "0x6f, 'o'", 3: "0x74, 't'", 2: "0x67, 'g'"} +## {0: "0x65, 'e'", 4: "0x6e, 'n'", 1: "0x6f, 'o'", 3: "0x64, 'd'", 2: "0x67, 'g'"} +## {0: "0x6d, 'm'", 4: "0x6e, 'n'", 1: "0x6f, 'o'", 3: "0x64, 'd'", 2: "0x6f, 'o'"} +## {0: "0x6d, 'm'", 4: "0x68, 'h'", 1: "0x6f, 'o'", 3: "0x64, 'd'", 2: "0x65, 'e'"} +## {0: "0x6d, 'm'", 4: "0x69, 'i'", 1: "0x6f, 'o'", 3: "0x64, 'd'", 2: "0x64, 'd'"} +## {0: "0x6d, 'm'", 4: "0x69, 'i'", 1: "0x6c, 'l'", 3: "0x64, 'd'", 2: "0x65, 'e'"} +## {0: "0x6d, 'm'", 4: "0x69, 'i'", 1: "0x6e, 'n'", 3: "0x64, 'd'", 2: "0x67, 'g'"} +## {0: "0x65, 'e'", 4: "0x6d, 'm'", 1: "0x6a, 'j'", 3: "0x64, 'd'", 2: "0x67, 'g'"} +## {0: "0x65, 'e'", 4: "0x69, 'i'", 1: "0x6e, 'n'", 3: "0x6c, 'l'", 2: "0x67, 'g'"} +## {0: "0x6d, 'm'", 4: "0x69, 'i'", 1: "0x6e, 'n'", 3: "0x6c, 'l'", 2: "0x6f, 'o'"} +## {0: "0x65, 'e'", 4: "0x6d, 'm'", 1: "0x6e, 'n'", 3: "0x6c, 'l'", 2: "0x6b, 'k'"} +## {0: "0x65, 'e'", 4: "0x69, 'i'", 1: "0x6a, 'j'", 3: "0x6c, 'l'", 2: "0x6b, 'k'"} +## {0: "0x6d, 'm'", 4: "0x6d, 'm'", 1: "0x6a, 'j'", 3: "0x64, 'd'", 2: "0x6f, 'o'"} +## {0: "0x6d, 'm'", 4: "0x6d, 'm'", 1: "0x6b, 'k'", 3: "0x64, 'd'", 2: "0x6c, 'l'"} +## [+] Pick up the first serial: qcgln +## [+] puts hooked +## fail +## [+] Instruction executed: 93 +## [+] Emulation done. +## [+] Start a second emulation with the good serial to validate the chall +## [+] Loading 0x000040 - 0x000270 +## [+] Loading 0x000270 - 0x000291 +## [+] Loading 0x000000 - 0x00003c +## [+] Loading 0x000000 - 0x0007b4 +## [+] Loading 0x001df8 - 0x002058 +## [+] Loading 0x001e10 - 0x002000 +## [+] Loading 0x000294 - 0x0002d8 +## [+] Loading 0x000770 - 0x000784 +## [+] Loading 0x000000 - 0x000000 +## [+] Loading 0x001df8 - 0x002000 +## [+] Hooking __libc_start_main +## [+] Hooking puts +## [+] Hooking __libc_start_main +## [+] Hooking puts +## [+] Starting emulation. +## [+] __libc_start_main hooked +## [+] argv[0] = b'./crackme_hash' +## [+] argv[1] = b'qcgln' +## [+] puts hooked +## Win +## [+] Instruction executed: 94 +## [+] Emulation done. +## ./solve-with-abv-logic.py 0,91s user 0,22s system 98% cpu 1,137 total + +from __future__ import print_function +from triton import * + +import random +import string +import sys +import lief +import os + + +DEBUG = True +MY_INPUT = 'riscv' +SERIAL = None +TARGET = os.path.join(os.path.dirname(__file__), 'crackme_hash') +VALID = False + +# The debug function +def debug(s): + if DEBUG: print(s) + +# Memory mapping +BASE_PLT = 0x10000000 +BASE_ARGV = 0x20000000 +BASE_SERIAL = 0x30000000 +BASE_SERIAL_ADDR = 0x2008 +BASE_STACK = 0x9fffffff + + +def getMemoryString(ctx, addr): + s = str() + index = 0 + + while ctx.getConcreteMemoryValue(addr+index): + c = chr(ctx.getConcreteMemoryValue(addr+index)) + if c not in string.printable: c = "" + s += c + index += 1 + + return s + + +# Simulate the puts() function +def putsHandler(ctx): + debug('[+] puts hooked') + + # Get arguments + arg1 = getMemoryString(ctx, ctx.getConcreteRegisterValue(ctx.registers.x10)) + sys.stdout.write(arg1 + '\n') + + # Return value + return len(arg1) + 1 + + +def exitHandler(ctx): + debug('[+] exit hooked') + sys.exit(0) + + +def libcMainHandler(ctx): + global MY_INPUT + debug('[+] __libc_start_main hooked') + + # Setup argc / argv + ctx.concretizeRegister(ctx.registers.x10) + ctx.concretizeRegister(ctx.registers.x11) + + argvs = [ + bytes(TARGET.encode('utf-8')), # argv[0] + bytes(MY_INPUT.encode('utf-8')) + ] + + # Define argc / argv + base = BASE_ARGV + addrs = list() + + index = 0 + for argv in argvs: + addrs.append(base) + ctx.setConcreteMemoryAreaValue(base, argv+b'\x00\x00\x00') + if index == 1: + # Only symbolized argv[1] + for indexCell in range(len(argv)): + var = ctx.symbolizeMemory(MemoryAccess(base+indexCell, CPUSIZE.BYTE)) + var.setComment('argv[%d][%d]' %(index, indexCell)) + debug('[+] argv[%d] = %s' %(index, argv)) + base += len(argv)+1 + index += 1 + + argc = len(argvs) + argv = base + for addr in addrs: + ctx.setConcreteMemoryValue(MemoryAccess(base, CPUSIZE.QWORD), addr) + base += CPUSIZE.QWORD + + ctx.setConcreteRegisterValue(ctx.registers.x10, argc) + ctx.setConcreteRegisterValue(ctx.registers.x11, argv) + + return None + + +# Functions to emulate +customRelocation = [ + ('__libc_start_main', libcMainHandler, BASE_PLT + 0), + ('exit', exitHandler, BASE_PLT + 1 << 2), + ('puts', putsHandler, BASE_PLT + 2 << 2), +] + + +def hookingHandler(ctx): + pc = ctx.getConcreteRegisterValue(ctx.registers.pc) + for rel in customRelocation: + if rel[2] == pc: + # Emulate the routine and the return value + x10 = ctx.getConcreteRegisterValue(ctx.registers.x10) + ret_value = rel[1](ctx) + if ret_value is not None: + ctx.setConcreteRegisterValue(ctx.registers.x10, ret_value) + + # Get the return address + ret_addr = ctx.getConcreteRegisterValue(ctx.registers.x1) + # Set ret_addr to main() address when __libc_start_main is hooked + if pc == BASE_PLT: + ret_addr = x10 + + # Hijack RIP to skip the call + ctx.setConcreteRegisterValue(ctx.registers.pc, ret_addr) + + # Restore RSP (simulate the ret) + ctx.setConcreteRegisterValue(ctx.registers.x2, ctx.getConcreteRegisterValue(ctx.registers.x2)+CPUSIZE.QWORD) + return + +# Emulate the binary. +def emulate(ctx, pc): + global SERIAL + global VALID + # Set serial string address loaded by: + # 6c8: 94483803 ld a6,-1724(a6) # 2008 + ctx.setConcreteMemoryAreaValue(BASE_SERIAL_ADDR, b"\x00\x00\x00\x30\x00\x00\x00\x00") + # Set serial string content + ctx.setConcreteMemoryAreaValue(BASE_SERIAL, '1>=&1'.encode('utf-8')+b'\x00\x00\x00') + + ctx.setConcreteRegisterValue(ctx.registers.pc, pc) + count = 0 + while pc: + # Fetch opcodes + opcodes = ctx.getConcreteMemoryAreaValue(pc, 4) + + # Create the Triton instruction + + instruction = Instruction() + instruction.setOpcode(opcodes) + instruction.setAddress(pc) + + # Process + if ctx.processing(instruction) == EXCEPTION.FAULT_UD: + debug('[-] Instruction not supported: %s' %(str(instruction))) + break + #else: + # debug('[~] Instruction processing: %s' %(str(instruction))) + + # Load main() address + # 5fe: a4653503 ld a0,-1466(a0) # 2040 <_GLOBAL_OFFSET_TABLE_+0x10> + if pc == 0x5fe: + ctx.setConcreteRegisterValue(ctx.registers.x10, 0x5b0) + + # 5de: 00000517 auipc a0,0x0 + # 5e2: 17a50513 addi a0,a0,378 # 758 <_IO_stdin_used+0x8> + # 5e6: fbbff0ef jal ra,5a0 + # ... + # 758: 006e6957 .4byte 0x6e6957 # "Win" + + if pc == 0x5e6: + # We validated the crackme + VALID = True + + # 6c2: 652d lui a0,0xb + # 6c4: 00002817 auipc a6,0x2 + # 6c8: 94483803 ld a6,-1724(a6) # 2008 + # 6cc: bcd50513 addi a0,a0,-1075 # abcd <__global_pointer$+0x83cd> + + # 5c6: 00f50c63 beq a0,a5,5de # jump to Win puts if equal + if pc == 0x5c6 and SERIAL is None: + print('[+] Please wait, calculating hash collisions...') + + SymVar_0 = ctx.getSymbolicVariable('SymVar_0') + SymVar_1 = ctx.getSymbolicVariable('SymVar_1') + SymVar_2 = ctx.getSymbolicVariable('SymVar_2') + SymVar_3 = ctx.getSymbolicVariable('SymVar_3') + SymVar_4 = ctx.getSymbolicVariable('SymVar_4') + + astCtxt = ctx.getAstContext() + + # We want printable characters + a0 = ctx.getSymbolicRegister(ctx.registers.x10) + expr = astCtxt.land([ + astCtxt.bvugt(astCtxt.variable(SymVar_0), astCtxt.bv(96, CPUSIZE.BYTE_BIT)), + astCtxt.bvult(astCtxt.variable(SymVar_0), astCtxt.bv(123, CPUSIZE.BYTE_BIT)), + astCtxt.bvugt(astCtxt.variable(SymVar_1), astCtxt.bv(96, CPUSIZE.BYTE_BIT)), + astCtxt.bvult(astCtxt.variable(SymVar_1), astCtxt.bv(123, CPUSIZE.BYTE_BIT)), + astCtxt.bvugt(astCtxt.variable(SymVar_2), astCtxt.bv(96, CPUSIZE.BYTE_BIT)), + astCtxt.bvult(astCtxt.variable(SymVar_2), astCtxt.bv(123, CPUSIZE.BYTE_BIT)), + astCtxt.bvugt(astCtxt.variable(SymVar_3), astCtxt.bv(96, CPUSIZE.BYTE_BIT)), + astCtxt.bvult(astCtxt.variable(SymVar_3), astCtxt.bv(123, CPUSIZE.BYTE_BIT)), + astCtxt.bvugt(astCtxt.variable(SymVar_4), astCtxt.bv(96, CPUSIZE.BYTE_BIT)), + astCtxt.bvult(astCtxt.variable(SymVar_4), astCtxt.bv(123, CPUSIZE.BYTE_BIT)), + astCtxt.equal(a0.getAst(), astCtxt.bv(0xad6d, CPUSIZE.QWORD_BIT)) # collision: (assert (= a4 0xad6d) + ]) + + # Get max 20 different models + models = ctx.getModels(expr, 20) + if len(models) == 0: + print('OOOPS! No models') + return + print('[+] Found several hash collisions:') + for model in models: + print({k: "0x%x, '%c'" % (v.getValue(), v.getValue()) for k, v in list(model.items())}) + + SERIAL = str() + for _, v in list(sorted(models[3].items())): + # NOTE only readable allowed + SERIAL += "%c" % (v.getValue()) + + print('[+] Pick up the first serial: %s' %(SERIAL)) + + # Return from main + if pc == 0x5f0: + break + + # Inc the number of instructions exected + count += 1 + + # Simulate routines + hookingHandler(ctx) + + # Next + pc = ctx.getConcreteRegisterValue(ctx.registers.pc) + + debug('[+] Instruction executed: %d' %(count)) + return + + +def loadBinary(ctx, binary): + # Map the binary into the memory + phdrs = binary.segments + for phdr in phdrs: + size = phdr.physical_size + vaddr = phdr.virtual_address + debug('[+] Loading 0x%06x - 0x%06x' %(vaddr, vaddr+size)) + ctx.setConcreteMemoryAreaValue(vaddr, list(phdr.content)) + return + + +def makeRelocation(ctx, binary): + # Perform our own relocations + try: + for rel in binary.pltgot_relocations: + symbolName = rel.symbol.name + symbolRelo = rel.address + for crel in customRelocation: + if symbolName == crel[0]: + debug('[+] Hooking %s' %(symbolName)) + ctx.setConcreteMemoryValue(MemoryAccess(symbolRelo, CPUSIZE.QWORD), crel[2]) + except: + pass + + # Perform our own relocations + try: + for rel in binary.dynamic_relocations: + symbolName = rel.symbol.name + symbolRelo = rel.address + for crel in customRelocation: + if symbolName == crel[0]: + debug('[+] Hooking %s' %(symbolName)) + ctx.setConcreteMemoryValue(MemoryAccess(symbolRelo, CPUSIZE.QWORD), crel[2]) + except: + pass + return + + +def run(ctx, binary): + # Concretize previous context + ctx.concretizeAllMemory() + ctx.concretizeAllRegister() + + # Load the binary + loadBinary(ctx, binary) + + # Perform our own relocations + makeRelocation(ctx, binary) + + # Define a fake stack + ctx.setConcreteRegisterValue(ctx.registers.x2, BASE_STACK) + + # Let's emulate the binary from the entry point + debug('[+] Starting emulation.') + emulate(ctx, binary.entrypoint) + debug('[+] Emulation done.') + return + + +def main(): + global MY_INPUT + global SERIAL + SERIAL = None + + # Get a Triton context + ctx = TritonContext() + + # Set the architecture + ctx.setArchitecture(ARCH.RV64) + + # Set optimization + ctx.setMode(MODE.MEMORY_ARRAY, True) + ctx.setMode(MODE.CONSTANT_FOLDING, True) + ctx.setMode(MODE.AST_OPTIMIZATIONS, True) + + # Parse the binary + binary = lief.parse(TARGET) + + # First emulation + run(ctx, binary) + + # Replace the input with the good serial to validate the chall + MY_INPUT = SERIAL + + # Second emulation + print('[+] Start a second emulation with the good serial to validate the chall') + run(ctx, binary) + + return not VALID == True + + +if __name__ == '__main__': + retValue = main() + sys.exit(retValue) diff --git a/src/examples/python/ctf-writeups/custom-crackmes/riscv64-hash/solve.py b/src/examples/python/ctf-writeups/custom-crackmes/riscv64-hash/solve.py new file mode 100755 index 000000000..40d7ca2e5 --- /dev/null +++ b/src/examples/python/ctf-writeups/custom-crackmes/riscv64-hash/solve.py @@ -0,0 +1,405 @@ +#!/usr/bin/env python3 +## -*- coding: utf-8 -*- +## +## May 2024. Based on Jonathan Salwan - 2018-12-26 +## +## A custom crackme to test the RISCV64 architecture. The goal is to find a hash +## collision to take the 'Win' branch. First we run the binary with a random +## seed, then we calculate the hash collision and run a second time the binary with +## the good input to take the 'Win' branch. +## +## Output: +## +## $ time ./solve.py +## [+] Loading 0x000040 - 0x000270 +## [+] Loading 0x000270 - 0x000291 +## [+] Loading 0x000000 - 0x00003c +## [+] Loading 0x000000 - 0x0007b4 +## [+] Loading 0x001df8 - 0x002058 +## [+] Loading 0x001e10 - 0x002000 +## [+] Loading 0x000294 - 0x0002d8 +## [+] Loading 0x000770 - 0x000784 +## [+] Loading 0x000000 - 0x000000 +## [+] Loading 0x001df8 - 0x002000 +## [+] Hooking __libc_start_main +## [+] Hooking puts +## [+] Hooking __libc_start_main +## [+] Hooking puts +## [+] Starting emulation. +## [+] __libc_start_main hooked +## [+] argv[0] = b'./crackme_hash' +## [+] argv[1] = b'riscv' +## [+] Please wait, calculating hash collisions... +## [+] Found several hash collisions: +## {0: "0x69, 'i'", 4: "0x65, 'e'", 3: "0x62, 'b'", 1: "0x61, 'a'", 2: "0x6c, 'l'"} +## {0: "0x69, 'i'", 1: "0x6a, 'j'", 4: "0x65, 'e'", 3: "0x62, 'b'", 2: "0x61, 'a'"} +## {0: "0x6d, 'm'", 1: "0x6e, 'n'", 4: "0x65, 'e'", 3: "0x62, 'b'", 2: "0x61, 'a'"} +## {0: "0x6d, 'm'", 1: "0x6e, 'n'", 4: "0x67, 'g'", 3: "0x64, 'd'", 2: "0x61, 'a'"} +## {0: "0x65, 'e'", 1: "0x6e, 'n'", 4: "0x6f, 'o'", 3: "0x64, 'd'", 2: "0x61, 'a'"} +## {0: "0x65, 'e'", 1: "0x6e, 'n'", 4: "0x6d, 'm'", 3: "0x64, 'd'", 2: "0x63, 'c'"} +## {0: "0x65, 'e'", 1: "0x6e, 'n'", 4: "0x6d, 'm'", 3: "0x74, 't'", 2: "0x73, 's'"} +## {0: "0x69, 'i'", 1: "0x6e, 'n'", 4: "0x69, 'i'", 3: "0x74, 't'", 2: "0x73, 's'"} +## {0: "0x6d, 'm'", 1: "0x6e, 'n'", 4: "0x6d, 'm'", 3: "0x6c, 'l'", 2: "0x73, 's'"} +## {0: "0x6d, 'm'", 1: "0x6c, 'l'", 4: "0x6b, 'k'", 3: "0x6c, 'l'", 2: "0x73, 's'"} +## {0: "0x6d, 'm'", 1: "0x6d, 'm'", 4: "0x6b, 'k'", 3: "0x6c, 'l'", 2: "0x70, 'p'"} +## {0: "0x69, 'i'", 1: "0x6f, 'o'", 4: "0x69, 'i'", 3: "0x6c, 'l'", 2: "0x68, 'h'"} +## {0: "0x69, 'i'", 1: "0x6d, 'm'", 4: "0x69, 'i'", 3: "0x6e, 'n'", 2: "0x68, 'h'"} +## {0: "0x65, 'e'", 1: "0x6d, 'm'", 4: "0x6d, 'm'", 3: "0x6e, 'n'", 2: "0x68, 'h'"} +## {0: "0x65, 'e'", 1: "0x6f, 'o'", 4: "0x6d, 'm'", 3: "0x6c, 'l'", 2: "0x68, 'h'"} +## {0: "0x6d, 'm'", 1: "0x6d, 'm'", 4: "0x6d, 'm'", 3: "0x6e, 'n'", 2: "0x70, 'p'"} +## {0: "0x6d, 'm'", 1: "0x6f, 'o'", 4: "0x6d, 'm'", 3: "0x6c, 'l'", 2: "0x70, 'p'"} +## {0: "0x6d, 'm'", 1: "0x6f, 'o'", 4: "0x65, 'e'", 3: "0x6c, 'l'", 2: "0x68, 'h'"} +## {0: "0x6d, 'm'", 1: "0x6d, 'm'", 4: "0x65, 'e'", 3: "0x6e, 'n'", 2: "0x68, 'h'"} +## {0: "0x6d, 'm'", 1: "0x6e, 'n'", 4: "0x65, 'e'", 3: "0x6d, 'm'", 2: "0x68, 'h'"} +## [+] Pick up the first serial: mnadg +## [+] puts hooked +## fail +## [+] Instruction executed: 93 +## [+] Emulation done. +## [+] Start a second emulation with the good serial to validate the chall +## [+] Starting emulation. +## [+] __libc_start_main hooked +## [+] argv[0] = b'./crackme_hash' +## [+] argv[1] = b'mnadg' +## [+] puts hooked +## Win +## [+] Instruction executed: 94 +## [+] Emulation done. +## ./solve.py 0,07s user 0,00s system 90% cpu 0,078 total + + +from __future__ import print_function +from triton import * + +import random +import string +import sys +import lief +import os + + +DEBUG = True +MY_INPUT = 'riscv' +SERIAL = None +TARGET = os.path.join(os.path.dirname(__file__), 'crackme_hash') +VALID = False + +# The debug function +def debug(s): + if DEBUG: print(s) + +# Memory mapping +BASE_PLT = 0x10000000 +BASE_ARGV = 0x20000000 +BASE_SERIAL = 0x30000000 +BASE_SERIAL_ADDR = 0x2008 +BASE_STACK = 0x9fffffff + + +def getMemoryString(ctx, addr): + s = str() + index = 0 + + while ctx.getConcreteMemoryValue(addr+index): + c = chr(ctx.getConcreteMemoryValue(addr+index)) + if c not in string.printable: c = "" + s += c + index += 1 + + return s + + +# Simulate the puts() function +def putsHandler(ctx): + debug('[+] puts hooked') + + # Get arguments + arg1 = getMemoryString(ctx, ctx.getConcreteRegisterValue(ctx.registers.x10)) + sys.stdout.write(arg1 + '\n') + + # Return value + return len(arg1) + 1 + + +def exitHandler(ctx): + debug('[+] exit hooked') + sys.exit(0) + + +def libcMainHandler(ctx): + global MY_INPUT + debug('[+] __libc_start_main hooked') + + # Setup argc / argv + ctx.concretizeRegister(ctx.registers.x10) + ctx.concretizeRegister(ctx.registers.x11) + + argvs = [ + bytes(TARGET.encode('utf-8')), # argv[0] + bytes(MY_INPUT.encode('utf-8')) + ] + + # Define argc / argv + base = BASE_ARGV + addrs = list() + + index = 0 + for argv in argvs: + addrs.append(base) + ctx.setConcreteMemoryAreaValue(base, argv+b'\x00\x00\x00') + if index == 1: + # Only symbolized argv[1] + for indexCell in range(len(argv)): + var = ctx.symbolizeMemory(MemoryAccess(base+indexCell, CPUSIZE.BYTE)) + var.setComment('argv[%d][%d]' %(index, indexCell)) + debug('[+] argv[%d] = %s' %(index, argv)) + base += len(argv)+1 + index += 1 + + argc = len(argvs) + argv = base + for addr in addrs: + ctx.setConcreteMemoryValue(MemoryAccess(base, CPUSIZE.QWORD), addr) + base += CPUSIZE.QWORD + + ctx.setConcreteRegisterValue(ctx.registers.x10, argc) + ctx.setConcreteRegisterValue(ctx.registers.x11, argv) + + return None + + +# Functions to emulate +customRelocation = [ + ('__libc_start_main', libcMainHandler, BASE_PLT + 0), + ('exit', exitHandler, BASE_PLT + 1 << 2), + ('puts', putsHandler, BASE_PLT + 2 << 2), +] + + +def hookingHandler(ctx): + pc = ctx.getConcreteRegisterValue(ctx.registers.pc) + for rel in customRelocation: + if rel[2] == pc: + # Emulate the routine and the return value + x10 = ctx.getConcreteRegisterValue(ctx.registers.x10) + ret_value = rel[1](ctx) + if ret_value is not None: + ctx.setConcreteRegisterValue(ctx.registers.x10, ret_value) + + # Get the return address + ret_addr = ctx.getConcreteRegisterValue(ctx.registers.x1) + # Set ret_addr to main() address when __libc_start_main is hooked + if pc == BASE_PLT: + ret_addr = x10 + + # Hijack RIP to skip the call + ctx.setConcreteRegisterValue(ctx.registers.pc, ret_addr) + + # Restore RSP (simulate the ret) + ctx.setConcreteRegisterValue(ctx.registers.x2, ctx.getConcreteRegisterValue(ctx.registers.x2)+CPUSIZE.QWORD) + return + +# Emulate the binary. +def emulate(ctx, pc): + global SERIAL + global VALID + # Set serial string address loaded by: + # 6c8: 94483803 ld a6,-1724(a6) # 2008 + ctx.setConcreteMemoryAreaValue(BASE_SERIAL_ADDR, b"\x00\x00\x00\x30\x00\x00\x00\x00") + # Set serial string content + ctx.setConcreteMemoryAreaValue(BASE_SERIAL, '1>=&1'.encode('utf-8')+b'\x00\x00\x00') + + ctx.setConcreteRegisterValue(ctx.registers.pc, pc) + count = 0 + while pc: + # Fetch opcodes + opcodes = ctx.getConcreteMemoryAreaValue(pc, 4) + + # Create the Triton instruction + + instruction = Instruction() + instruction.setOpcode(opcodes) + instruction.setAddress(pc) + + # Process + if ctx.processing(instruction) == EXCEPTION.FAULT_UD: + debug('[-] Instruction not supported: %s' %(str(instruction))) + break + #else: + # debug('[~] Instruction processing: %s' %(str(instruction))) + + # Load main() address + # 5fe: a4653503 ld a0,-1466(a0) # 2040 <_GLOBAL_OFFSET_TABLE_+0x10> + if pc == 0x5fe: + ctx.setConcreteRegisterValue(ctx.registers.x10, 0x5b0) + + # 5de: 00000517 auipc a0,0x0 + # 5e2: 17a50513 addi a0,a0,378 # 758 <_IO_stdin_used+0x8> + # 5e6: fbbff0ef jal ra,5a0 + # ... + # 758: 006e6957 .4byte 0x6e6957 # "Win" + + if pc == 0x5e6: + # We validated the crackme + VALID = True + + # 6c2: 652d lui a0,0xb + # 6c4: 00002817 auipc a6,0x2 + # 6c8: 94483803 ld a6,-1724(a6) # 2008 + # 6cc: bcd50513 addi a0,a0,-1075 # abcd <__global_pointer$+0x83cd> + + # 5c6: 00f50c63 beq a0,a5,5de # jump to Win puts if equal + if pc == 0x5c6 and SERIAL is None: + print('[+] Please wait, calculating hash collisions...') + + SymVar_0 = ctx.getSymbolicVariable('SymVar_0') + SymVar_1 = ctx.getSymbolicVariable('SymVar_1') + SymVar_2 = ctx.getSymbolicVariable('SymVar_2') + SymVar_3 = ctx.getSymbolicVariable('SymVar_3') + SymVar_4 = ctx.getSymbolicVariable('SymVar_4') + + astCtxt = ctx.getAstContext() + + # We want printable characters + a0 = ctx.getSymbolicRegister(ctx.registers.x10) + expr = astCtxt.land([ + astCtxt.bvugt(astCtxt.variable(SymVar_0), astCtxt.bv(96, CPUSIZE.BYTE_BIT)), + astCtxt.bvult(astCtxt.variable(SymVar_0), astCtxt.bv(123, CPUSIZE.BYTE_BIT)), + astCtxt.bvugt(astCtxt.variable(SymVar_1), astCtxt.bv(96, CPUSIZE.BYTE_BIT)), + astCtxt.bvult(astCtxt.variable(SymVar_1), astCtxt.bv(123, CPUSIZE.BYTE_BIT)), + astCtxt.bvugt(astCtxt.variable(SymVar_2), astCtxt.bv(96, CPUSIZE.BYTE_BIT)), + astCtxt.bvult(astCtxt.variable(SymVar_2), astCtxt.bv(123, CPUSIZE.BYTE_BIT)), + astCtxt.bvugt(astCtxt.variable(SymVar_3), astCtxt.bv(96, CPUSIZE.BYTE_BIT)), + astCtxt.bvult(astCtxt.variable(SymVar_3), astCtxt.bv(123, CPUSIZE.BYTE_BIT)), + astCtxt.bvugt(astCtxt.variable(SymVar_4), astCtxt.bv(96, CPUSIZE.BYTE_BIT)), + astCtxt.bvult(astCtxt.variable(SymVar_4), astCtxt.bv(123, CPUSIZE.BYTE_BIT)), + astCtxt.equal(a0.getAst(), astCtxt.bv(0xad6d, CPUSIZE.QWORD_BIT)) # collision: (assert (= a4 0xad6d) + ]) + + # Get max 20 different models + models = ctx.getModels(expr, 20) + if len(models) == 0: + print('OOOPS! No models') + return + print('[+] Found several hash collisions:') + for model in models: + print({k: "0x%x, '%c'" % (v.getValue(), v.getValue()) for k, v in list(model.items())}) + + SERIAL = str() + for _, v in list(sorted(models[3].items())): + # NOTE only readable allowed + SERIAL += "%c" % (v.getValue()) + + print('[+] Pick up the first serial: %s' %(SERIAL)) + + # Return from main + if pc == 0x5f0: + break + + # Inc the number of instructions exected + count += 1 + + # Simulate routines + hookingHandler(ctx) + + # Next + pc = ctx.getConcreteRegisterValue(ctx.registers.pc) + + debug('[+] Instruction executed: %d' %(count)) + return + + +def loadBinary(ctx, binary): + # Map the binary into the memory + phdrs = binary.segments + for phdr in phdrs: + size = phdr.physical_size + vaddr = phdr.virtual_address + debug('[+] Loading 0x%06x - 0x%06x' %(vaddr, vaddr+size)) + ctx.setConcreteMemoryAreaValue(vaddr, list(phdr.content)) + return + + +def makeRelocation(ctx, binary): + # Perform our own relocations + try: + for rel in binary.pltgot_relocations: + symbolName = rel.symbol.name + symbolRelo = rel.address + for crel in customRelocation: + if symbolName == crel[0]: + debug('[+] Hooking %s' %(symbolName)) + ctx.setConcreteMemoryValue(MemoryAccess(symbolRelo, CPUSIZE.QWORD), crel[2]) + except: + pass + + # Perform our own relocations + try: + for rel in binary.dynamic_relocations: + symbolName = rel.symbol.name + symbolRelo = rel.address + for crel in customRelocation: + if symbolName == crel[0]: + debug('[+] Hooking %s' %(symbolName)) + ctx.setConcreteMemoryValue(MemoryAccess(symbolRelo, CPUSIZE.QWORD), crel[2]) + except: + pass + return + + +def run(ctx, binary): + # Concretize previous context + ctx.concretizeAllMemory() + ctx.concretizeAllRegister() + + # Define a fake stack + ctx.setConcreteRegisterValue(ctx.registers.x2, BASE_STACK) + + # Let's emulate the binary from the entry point + debug('[+] Starting emulation.') + emulate(ctx, binary.entrypoint) + debug('[+] Emulation done.') + return + + +def main(): + global MY_INPUT + global SERIAL + SERIAL = None + + # Get a Triton context + ctx = TritonContext() + + # Set the architecture + ctx.setArchitecture(ARCH.RV64) + + # Set optimization + ctx.setMode(MODE.ALIGNED_MEMORY, True) + ctx.setMode(MODE.ONLY_ON_SYMBOLIZED, True) + #ctx.setMode(MODE.AST_OPTIMIZATIONS, True) + + # Parse the binary + binary = lief.parse(TARGET) + + # Load the binary + loadBinary(ctx, binary) + + # Perform our own relocations + makeRelocation(ctx, binary) + + # First emulation + run(ctx, binary) + + # Replace the input with the good serial to validate the chall + MY_INPUT = SERIAL + + # Second emulation + print('[+] Start a second emulation with the good serial to validate the chall') + run(ctx, binary) + + return not VALID == True + + +if __name__ == '__main__': + retValue = main() + sys.exit(retValue) diff --git a/src/libtriton/CMakeLists.txt b/src/libtriton/CMakeLists.txt index 44d7f66d3..07502c816 100644 --- a/src/libtriton/CMakeLists.txt +++ b/src/libtriton/CMakeLists.txt @@ -147,6 +147,24 @@ set(LIBTRITON_HEADER_FILES includes/triton/z3ToTriton.hpp ) +# Add riscv source and header files +if(${CS_VERSION_MAJOR} GREATER_EQUAL 5) + list(APPEND LIBTRITON_SOURCE_FILES + arch/riscv/riscv32Cpu.cpp + arch/riscv/riscv64Cpu.cpp + arch/riscv/riscvSemantics.cpp + arch/riscv/riscvSpecifications.cpp + ) + list(APPEND LIBTRITON_HEADER_FILES + includes/triton/riscv32.spec + includes/triton/riscv64.spec + includes/triton/riscv32Cpu.hpp + includes/triton/riscv64Cpu.hpp + includes/triton/riscvSemantics.hpp + includes/triton/riscvSpecifications.hpp + ) +endif() + # Define all resource files set(LIBTRITON_RESOURCE_FILES includes/triton/version.hpp.in diff --git a/src/libtriton/arch/architecture.cpp b/src/libtriton/arch/architecture.cpp index d94e5f2b8..58cf93bb4 100644 --- a/src/libtriton/arch/architecture.cpp +++ b/src/libtriton/arch/architecture.cpp @@ -13,6 +13,11 @@ #include #include #include +#ifdef COMPILE_RISCV +#include +#include +#include +#endif #include #include #include @@ -54,6 +59,10 @@ namespace triton { case triton::arch::ARCH_X86: this->cpu.reset(new(std::nothrow) triton::arch::x86::x86Cpu(this->callbacks)); break; case triton::arch::ARCH_AARCH64: this->cpu.reset(new(std::nothrow) triton::arch::arm::aarch64::AArch64Cpu(this->callbacks)); break; case triton::arch::ARCH_ARM32: this->cpu.reset(new(std::nothrow) triton::arch::arm::arm32::Arm32Cpu(this->callbacks)); break; + #ifdef COMPILE_RISCV + case triton::arch::ARCH_RV64: this->cpu.reset(new(std::nothrow) triton::arch::riscv::riscv64Cpu(this->callbacks)); break; + case triton::arch::ARCH_RV32: this->cpu.reset(new(std::nothrow) triton::arch::riscv::riscv32Cpu(this->callbacks)); break; + #endif default: throw triton::exceptions::Architecture("Architecture::setArchitecture(): Architecture not supported."); } @@ -400,6 +409,12 @@ namespace triton { case triton::arch::ARCH_X86_64: return triton::arch::x86::nop; + #ifdef COMPILE_RISCV + case triton::arch::ARCH_RV64: + case triton::arch::ARCH_RV32: + return triton::arch::riscv::nop; + #endif + default: throw triton::exceptions::Architecture("Architecture::getNopInstruction(): Invalid architecture."); } diff --git a/src/libtriton/arch/irBuilder.cpp b/src/libtriton/arch/irBuilder.cpp index 771026397..7ed560d39 100644 --- a/src/libtriton/arch/irBuilder.cpp +++ b/src/libtriton/arch/irBuilder.cpp @@ -16,7 +16,9 @@ #include #include #include - +#ifdef COMPILE_RISCV +#include +#endif namespace triton { @@ -44,8 +46,15 @@ namespace triton { this->aarch64Isa = new(std::nothrow) triton::arch::arm::aarch64::AArch64Semantics(architecture, symbolicEngine, taintEngine, astCtxt); this->arm32Isa = new(std::nothrow) triton::arch::arm::arm32::Arm32Semantics(architecture, symbolicEngine, taintEngine, astCtxt); this->x86Isa = new(std::nothrow) triton::arch::x86::x86Semantics(architecture, symbolicEngine, taintEngine, modes, astCtxt); - - if (this->x86Isa == nullptr || this->aarch64Isa == nullptr || this->arm32Isa == nullptr) + #ifdef COMPILE_RISCV + this->riscvIsa = new(std::nothrow) triton::arch::riscv::riscvSemantics(architecture, symbolicEngine, taintEngine, modes, astCtxt); + #endif + + if (this->x86Isa == nullptr || this->aarch64Isa == nullptr || this->arm32Isa == nullptr + #ifdef COMPILE_RISCV + || this->riscvIsa == nullptr + #endif + ) throw triton::exceptions::IrBuilder("IrBuilder::IrBuilder(): Not enough memory."); } @@ -54,6 +63,9 @@ namespace triton { delete this->aarch64Isa; delete this->arm32Isa; delete this->x86Isa; + #ifdef COMPILE_RISCV + delete this->riscvIsa; + #endif } @@ -89,6 +101,13 @@ namespace triton { ret = this->x86Isa->buildSemantics(inst); break; + #ifdef COMPILE_RISCV + case triton::arch::ARCH_RV64: + case triton::arch::ARCH_RV32: + ret = this->riscvIsa->buildSemantics(inst); + break; + #endif + default: throw triton::exceptions::IrBuilder("IrBuilder::buildSemantics(): Architecture not supported."); break; diff --git a/src/libtriton/arch/riscv/riscv32Cpu.cpp b/src/libtriton/arch/riscv/riscv32Cpu.cpp new file mode 100644 index 000000000..54ebf5b95 --- /dev/null +++ b/src/libtriton/arch/riscv/riscv32Cpu.cpp @@ -0,0 +1,741 @@ +//! \file +/* +** Copyright (C) - Triton +** +** This program is under the terms of the Apache License 2.0. +*/ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + + + +namespace triton { + namespace arch { + namespace riscv { + + riscv32Cpu::riscv32Cpu(triton::callbacks::Callbacks* callbacks) : riscvSpecifications(ARCH_RV32) { + this->callbacks = callbacks; + this->handle = 0; + + this->clear(); + this->disassInit(); + } + + + riscv32Cpu::riscv32Cpu(const riscv32Cpu& other) : riscvSpecifications(ARCH_RV32) { + this->copy(other); + } + + + riscv32Cpu::~riscv32Cpu() { + this->memory.clear(); + if (this->handle) { + triton::extlibs::capstone::cs_close(&this->handle); + } + } + + void riscv32Cpu::disassInit(void) { + if (this->handle) { + triton::extlibs::capstone::cs_close(&this->handle); + } + + // CS_MODE_RISCV32 | CS_MODE_RISCVC + auto rv_mode = static_cast((1 << 0) | (1 << 2)); + if (triton::extlibs::capstone::cs_open(triton::extlibs::capstone::CS_ARCH_RISCV, rv_mode, &this->handle) != triton::extlibs::capstone::CS_ERR_OK) + throw triton::exceptions::Disassembly("riscv32Cpu::disassInit(): Cannot open capstone."); + + triton::extlibs::capstone::cs_option(this->handle, triton::extlibs::capstone::CS_OPT_DETAIL, triton::extlibs::capstone::CS_OPT_ON); + } + + + void riscv32Cpu::copy(const riscv32Cpu& other) { + this->callbacks = other.callbacks; + this->memory = other.memory; + + std::memcpy(this->x0, other.x0, sizeof(this->x0)); + std::memcpy(this->x1, other.x1, sizeof(this->x1)); + std::memcpy(this->sp, other.sp, sizeof(this->sp)); + std::memcpy(this->x3, other.x3, sizeof(this->x3)); + std::memcpy(this->x4, other.x4, sizeof(this->x4)); + std::memcpy(this->x5, other.x5, sizeof(this->x5)); + std::memcpy(this->x6, other.x6, sizeof(this->x6)); + std::memcpy(this->x7, other.x7, sizeof(this->x7)); + std::memcpy(this->x8, other.x8, sizeof(this->x8)); + std::memcpy(this->x9, other.x9, sizeof(this->x9)); + std::memcpy(this->x10, other.x10, sizeof(this->x10)); + std::memcpy(this->x11, other.x11, sizeof(this->x11)); + std::memcpy(this->x12, other.x12, sizeof(this->x12)); + std::memcpy(this->x13, other.x13, sizeof(this->x13)); + std::memcpy(this->x14, other.x14, sizeof(this->x14)); + std::memcpy(this->x15, other.x15, sizeof(this->x15)); + std::memcpy(this->x16, other.x16, sizeof(this->x16)); + std::memcpy(this->x17, other.x17, sizeof(this->x17)); + std::memcpy(this->x18, other.x18, sizeof(this->x18)); + std::memcpy(this->x19, other.x19, sizeof(this->x19)); + std::memcpy(this->x20, other.x20, sizeof(this->x20)); + std::memcpy(this->x21, other.x21, sizeof(this->x21)); + std::memcpy(this->x22, other.x22, sizeof(this->x22)); + std::memcpy(this->x23, other.x23, sizeof(this->x23)); + std::memcpy(this->x24, other.x24, sizeof(this->x24)); + std::memcpy(this->x25, other.x25, sizeof(this->x25)); + std::memcpy(this->x26, other.x26, sizeof(this->x26)); + std::memcpy(this->x27, other.x27, sizeof(this->x27)); + std::memcpy(this->x28, other.x28, sizeof(this->x28)); + std::memcpy(this->x29, other.x29, sizeof(this->x29)); + std::memcpy(this->x30, other.x30, sizeof(this->x30)); + std::memcpy(this->x31, other.x31, sizeof(this->x31)); + std::memcpy(this->pc, other.pc, sizeof(this->pc)); + std::memcpy(this->f0, other.f0, sizeof(this->f0)); + std::memcpy(this->f1, other.f1, sizeof(this->f1)); + std::memcpy(this->f2, other.f2, sizeof(this->f2)); + std::memcpy(this->f3, other.f3, sizeof(this->f3)); + std::memcpy(this->f4, other.f4, sizeof(this->f4)); + std::memcpy(this->f5, other.f5, sizeof(this->f5)); + std::memcpy(this->f6, other.f6, sizeof(this->f6)); + std::memcpy(this->f7, other.f7, sizeof(this->f7)); + std::memcpy(this->f8, other.f8, sizeof(this->f8)); + std::memcpy(this->f9, other.f9, sizeof(this->f9)); + std::memcpy(this->f10, other.f10, sizeof(this->f10)); + std::memcpy(this->f11, other.f11, sizeof(this->f11)); + std::memcpy(this->f12, other.f12, sizeof(this->f12)); + std::memcpy(this->f13, other.f13, sizeof(this->f13)); + std::memcpy(this->f14, other.f14, sizeof(this->f14)); + std::memcpy(this->f15, other.f15, sizeof(this->f15)); + std::memcpy(this->f16, other.f16, sizeof(this->f16)); + std::memcpy(this->f17, other.f17, sizeof(this->f17)); + std::memcpy(this->f18, other.f18, sizeof(this->f18)); + std::memcpy(this->f19, other.f19, sizeof(this->f19)); + std::memcpy(this->f20, other.f20, sizeof(this->f20)); + std::memcpy(this->f21, other.f21, sizeof(this->f21)); + std::memcpy(this->f22, other.f22, sizeof(this->f22)); + std::memcpy(this->f23, other.f23, sizeof(this->f23)); + std::memcpy(this->f24, other.f24, sizeof(this->f24)); + std::memcpy(this->f25, other.f25, sizeof(this->f25)); + std::memcpy(this->f26, other.f26, sizeof(this->f26)); + std::memcpy(this->f27, other.f27, sizeof(this->f27)); + std::memcpy(this->f28, other.f28, sizeof(this->f28)); + std::memcpy(this->f29, other.f29, sizeof(this->f29)); + std::memcpy(this->f30, other.f30, sizeof(this->f30)); + std::memcpy(this->f31, other.f31, sizeof(this->f31)); + } + + + void riscv32Cpu::clear(void) { + /* Clear memory */ + this->memory.clear(); + + /* Clear registers */ + std::memset(this->x0, 0x00, sizeof(this->x0)); + std::memset(this->x1, 0x00, sizeof(this->x1)); + std::memset(this->sp, 0x00, sizeof(this->sp)); + std::memset(this->x3, 0x00, sizeof(this->x3)); + std::memset(this->x4, 0x00, sizeof(this->x4)); + std::memset(this->x5, 0x00, sizeof(this->x5)); + std::memset(this->x6, 0x00, sizeof(this->x6)); + std::memset(this->x7, 0x00, sizeof(this->x7)); + std::memset(this->x8, 0x00, sizeof(this->x8)); + std::memset(this->x9, 0x00, sizeof(this->x9)); + std::memset(this->x10, 0x00, sizeof(this->x10)); + std::memset(this->x11, 0x00, sizeof(this->x11)); + std::memset(this->x12, 0x00, sizeof(this->x12)); + std::memset(this->x13, 0x00, sizeof(this->x13)); + std::memset(this->x14, 0x00, sizeof(this->x14)); + std::memset(this->x15, 0x00, sizeof(this->x15)); + std::memset(this->x16, 0x00, sizeof(this->x16)); + std::memset(this->x17, 0x00, sizeof(this->x17)); + std::memset(this->x18, 0x00, sizeof(this->x18)); + std::memset(this->x19, 0x00, sizeof(this->x19)); + std::memset(this->x20, 0x00, sizeof(this->x20)); + std::memset(this->x21, 0x00, sizeof(this->x21)); + std::memset(this->x22, 0x00, sizeof(this->x22)); + std::memset(this->x23, 0x00, sizeof(this->x23)); + std::memset(this->x24, 0x00, sizeof(this->x24)); + std::memset(this->x25, 0x00, sizeof(this->x25)); + std::memset(this->x26, 0x00, sizeof(this->x26)); + std::memset(this->x27, 0x00, sizeof(this->x27)); + std::memset(this->x28, 0x00, sizeof(this->x28)); + std::memset(this->x29, 0x00, sizeof(this->x29)); + std::memset(this->x30, 0x00, sizeof(this->x30)); + std::memset(this->x31, 0x00, sizeof(this->x31)); + std::memset(this->pc, 0x00, sizeof(this->pc)); + std::memset(this->f0, 0x00, sizeof(this->f0)); + std::memset(this->f1, 0x00, sizeof(this->f1)); + std::memset(this->f2, 0x00, sizeof(this->f2)); + std::memset(this->f3, 0x00, sizeof(this->f3)); + std::memset(this->f4, 0x00, sizeof(this->f4)); + std::memset(this->f5, 0x00, sizeof(this->f5)); + std::memset(this->f6, 0x00, sizeof(this->f6)); + std::memset(this->f7, 0x00, sizeof(this->f7)); + std::memset(this->f8, 0x00, sizeof(this->f8)); + std::memset(this->f9, 0x00, sizeof(this->f9)); + std::memset(this->f10, 0x00, sizeof(this->f10)); + std::memset(this->f11, 0x00, sizeof(this->f11)); + std::memset(this->f12, 0x00, sizeof(this->f12)); + std::memset(this->f13, 0x00, sizeof(this->f13)); + std::memset(this->f14, 0x00, sizeof(this->f14)); + std::memset(this->f15, 0x00, sizeof(this->f15)); + std::memset(this->f16, 0x00, sizeof(this->f16)); + std::memset(this->f17, 0x00, sizeof(this->f17)); + std::memset(this->f18, 0x00, sizeof(this->f18)); + std::memset(this->f19, 0x00, sizeof(this->f19)); + std::memset(this->f20, 0x00, sizeof(this->f20)); + std::memset(this->f21, 0x00, sizeof(this->f21)); + std::memset(this->f22, 0x00, sizeof(this->f22)); + std::memset(this->f23, 0x00, sizeof(this->f23)); + std::memset(this->f24, 0x00, sizeof(this->f24)); + std::memset(this->f25, 0x00, sizeof(this->f25)); + std::memset(this->f26, 0x00, sizeof(this->f26)); + std::memset(this->f27, 0x00, sizeof(this->f27)); + std::memset(this->f28, 0x00, sizeof(this->f28)); + std::memset(this->f29, 0x00, sizeof(this->f29)); + std::memset(this->f30, 0x00, sizeof(this->f30)); + std::memset(this->f31, 0x00, sizeof(this->f31)); + } + + + riscv32Cpu& riscv32Cpu::operator=(const riscv32Cpu& other) { + this->copy(other); + return *this; + } + + + triton::arch::endianness_e riscv32Cpu::getEndianness(void) const { + return triton::arch::LE_ENDIANNESS; + } + + + bool riscv32Cpu::isRegister(triton::arch::register_e regId) const { + return (this->isGPR(regId) || this->isFPU(regId) || regId == triton::arch::ID_REG_RV32_PC); + } + + + bool riscv32Cpu::isRegisterValid(triton::arch::register_e regId) const { + return (this->isFlag(regId) || this->isRegister(regId)); + } + + + bool riscv32Cpu::isGPR(triton::arch::register_e regId) const { + return ((regId >= triton::arch::ID_REG_RV32_X0 && regId <= triton::arch::ID_REG_RV32_X31) ? true : false); + } + + + bool riscv32Cpu::isFPU(triton::arch::register_e regId) const { + return ((regId >= triton::arch::ID_REG_RV32_F0 && regId <= triton::arch::ID_REG_RV32_F31) ? true : false); + } + + + bool riscv32Cpu::isFlag(triton::arch::register_e regId) const { + return false; + } + + + triton::uint32 riscv32Cpu::numberOfRegisters(void) const { + return triton::arch::ID_REG_LAST_ITEM; + } + + + triton::uint32 riscv32Cpu::gprSize(void) const { + return triton::size::dword; + } + + + triton::uint32 riscv32Cpu::gprBitSize(void) const { + return triton::bitsize::dword; + } + + + const std::unordered_map& riscv32Cpu::getAllRegisters(void) const { + return this->id2reg; + } + + const std::unordered_map>& riscv32Cpu::getConcreteMemory(void) const { + return this->memory; + } + + std::set riscv32Cpu::getParentRegisters(void) const { + std::set ret; + + for (const auto& kv: this->id2reg) { + auto regId = kv.first; + const auto& reg = kv.second; + + /* Add GPR */ + if (reg.getSize() == this->gprSize()) + ret.insert(®); + + /* Add FPU */ + else if (this->isFPU(regId)) + ret.insert(®); + } + + return ret; + } + + + const triton::arch::Register& riscv32Cpu::getRegister(triton::arch::register_e id) const { + try { + return this->id2reg.at(id); + } catch (const std::out_of_range&) { + throw triton::exceptions::Cpu("riscv32Cpu::getRegister(): Invalid register for this architecture."); + } + } + + + const triton::arch::Register& riscv32Cpu::getRegister(const std::string& name) const { + std::string lower = name; + std::transform(lower.begin(), lower.end(), lower.begin(), [](unsigned char c){ return std::tolower(c); }); + try { + return this->getRegister(this->name2id.at(lower)); + } catch (const std::out_of_range&) { + throw triton::exceptions::Cpu("riscv32Cpu::getRegister(): Invalid register for this architecture."); + } + } + + + const triton::arch::Register& riscv32Cpu::getParentRegister(const triton::arch::Register& reg) const { + return this->getRegister(reg.getParent()); + } + + + const triton::arch::Register& riscv32Cpu::getParentRegister(triton::arch::register_e id) const { + return this->getParentRegister(this->getRegister(id)); + } + + + const triton::arch::Register& riscv32Cpu::getProgramCounter(void) const { + return this->getRegister(this->pcId); + } + + + const triton::arch::Register& riscv32Cpu::getStackPointer(void) const { + return this->getRegister(this->spId); + } + + void riscv32Cpu::disassembly(triton::arch::Instruction& inst) { + + triton::extlibs::capstone::cs_insn* insn; + triton::usize count = 0; + triton::uint32 size = 0; + + /* Check if the opcode and opcode' size are defined */ + if (inst.getOpcode() == nullptr || inst.getSize() == 0) + throw triton::exceptions::Disassembly("riscv32Cpu::disassembly(): Opcode and opcodeSize must be definied."); + + /* Clear instructicon's operands if alredy defined */ + inst.operands.clear(); + + /* Update instruction address if undefined */ + if (!inst.getAddress()) { + inst.setAddress(static_cast(this->getConcreteRegisterValue(this->getProgramCounter()))); + } + + /* Let's disass and build our operands */ + count = triton::extlibs::capstone::cs_disasm(this->handle, inst.getOpcode(), inst.getSize(), inst.getAddress(), 0, &insn); + if (count > 0) { + /* Detail information */ + triton::extlibs::capstone::cs_detail* detail = insn->detail; + + /* Init the disassembly */ + std::stringstream str; + + str << insn[0].mnemonic; + if (detail->riscv.op_count) + str << " " << insn[0].op_str; + + inst.setDisassembly(str.str()); + + /* Refine the size */ + inst.setSize(insn[0].size); + + /* Init the instruction's type */ + inst.setType(this->capstoneInstructionToTritonInstruction(insn[0].id)); + + /* Set architecture */ + inst.setArchitecture(triton::arch::ARCH_RV32); + + /* Init operands */ + for (triton::uint32 n = 0; n < detail->riscv.op_count; n++) { + triton::extlibs::capstone::cs_riscv_op* op = &(detail->riscv.operands[n]); + + switch(op->type) { + + case triton::extlibs::capstone::RISCV_OP_IMM: { + triton::arch::Immediate imm(op->imm, size ? size : triton::size::dword); + if (static_cast(op->imm) > imm.getValue()) { + imm = Immediate(); + imm.setValue(op->imm, 0); /* By setting 0 as size, we automatically identify the size of the value */ + } + + inst.operands.push_back(triton::arch::OperandWrapper(imm)); + break; + } + + case triton::extlibs::capstone::RISCV_OP_MEM: { + triton::arch::MemoryAccess mem; + + /* Set the size of the memory access */ + size = this->getMemoryOperandSpecialSize(inst.getType()); + mem.setBits(size ? ((size * triton::bitsize::byte) - 1) : triton::bitsize::dword - 1, 0); + + /* Set address calculation units */ + triton::arch::Register base(*this, this->capstoneRegisterToTritonRegister32(op->mem.base)); + + triton::uint32 immsize = ( + this->isRegisterValid(base.getId()) ? base.getSize() : + this->gprSize() + ); + + triton::arch::Immediate disp(op->mem.disp, immsize); + + mem.setBaseRegister(base); + mem.setDisplacement(disp); + + inst.operands.push_back(triton::arch::OperandWrapper(mem)); + break; + } + + case triton::extlibs::capstone::RISCV_OP_REG: { + inst.operands.push_back(triton::arch::OperandWrapper(triton::arch::Register(*this, this->capstoneRegisterToTritonRegister32(op->reg)))); + break; + } + + default: + throw triton::exceptions::Disassembly("riscv32Cpu::disassembly(): Invalid operand."); + } // switch + } // for operand + + /* Set branch */ + if (detail->groups_count > 0) { + for (triton::uint32 n = 0; n < detail->groups_count; n++) { + if (detail->groups[n] == triton::extlibs::capstone::RISCV_GRP_JUMP) + inst.setBranch(true); + if (detail->groups[n] == triton::extlibs::capstone::RISCV_GRP_JUMP || + detail->groups[n] == triton::extlibs::capstone::RISCV_GRP_CALL || + detail->groups[n] == triton::extlibs::capstone::RISCV_GRP_RET) + inst.setControlFlow(true); + } + } + + /* Free capstone stuffs */ + triton::extlibs::capstone::cs_free(insn, count); + } + else + throw triton::exceptions::Disassembly("riscv32Cpu::disassembly(): Failed to disassemble the given code."); + } + + + triton::uint8 riscv32Cpu::getConcreteMemoryValue(triton::uint64 addr, bool execCallbacks) const { + if (execCallbacks && this->callbacks) + this->callbacks->processCallbacks(triton::callbacks::GET_CONCRETE_MEMORY_VALUE, MemoryAccess(addr, triton::size::byte)); + + auto it = this->memory.find(addr); + if (it == this->memory.end()) { + return 0x00; + } + + return it->second; + } + + + triton::uint512 riscv32Cpu::getConcreteMemoryValue(const triton::arch::MemoryAccess& mem, bool execCallbacks) const { + triton::uint512 ret = 0; + triton::uint64 addr = 0; + triton::uint32 size = 0; + + if (execCallbacks && this->callbacks) + this->callbacks->processCallbacks(triton::callbacks::GET_CONCRETE_MEMORY_VALUE, mem); + + addr = mem.getAddress(); + size = mem.getSize(); + + if (size == 0 || size > triton::size::dqqword) + throw triton::exceptions::Cpu("riscv32Cpu::getConcreteMemoryValue(): Invalid size memory."); + + for (triton::sint32 i = size-1; i >= 0; i--) + ret = ((ret << triton::bitsize::byte) | this->getConcreteMemoryValue(addr+i, false)); + + return ret; + } + + + std::vector riscv32Cpu::getConcreteMemoryAreaValue(triton::uint64 baseAddr, triton::usize size, bool execCallbacks) const { + std::vector area; + + for (triton::usize index = 0; index < size; index++) + area.push_back(this->getConcreteMemoryValue(baseAddr+index, execCallbacks)); + + return area; + } + + + triton::uint512 riscv32Cpu::getConcreteRegisterValue(const triton::arch::Register& reg, bool execCallbacks) const { + triton::uint512 value = 0; + + if (execCallbacks && this->callbacks) + this->callbacks->processCallbacks(triton::callbacks::GET_CONCRETE_REGISTER_VALUE, reg); + switch (reg.getId()) { + case triton::arch::ID_REG_RV32_X0: return 0; + case triton::arch::ID_REG_RV32_X1: return (*((triton::uint32*)(this->x1))); + case triton::arch::ID_REG_RV32_SP: return (*((triton::uint32*)(this->sp))); + case triton::arch::ID_REG_RV32_X3: return (*((triton::uint32*)(this->x3))); + case triton::arch::ID_REG_RV32_X4: return (*((triton::uint32*)(this->x4))); + case triton::arch::ID_REG_RV32_X5: return (*((triton::uint32*)(this->x5))); + case triton::arch::ID_REG_RV32_X6: return (*((triton::uint32*)(this->x6))); + case triton::arch::ID_REG_RV32_X7: return (*((triton::uint32*)(this->x7))); + case triton::arch::ID_REG_RV32_X8: return (*((triton::uint32*)(this->x8))); + case triton::arch::ID_REG_RV32_X9: return (*((triton::uint32*)(this->x9))); + case triton::arch::ID_REG_RV32_X10: return (*((triton::uint32*)(this->x10))); + case triton::arch::ID_REG_RV32_X11: return (*((triton::uint32*)(this->x11))); + case triton::arch::ID_REG_RV32_X12: return (*((triton::uint32*)(this->x12))); + case triton::arch::ID_REG_RV32_X13: return (*((triton::uint32*)(this->x13))); + case triton::arch::ID_REG_RV32_X14: return (*((triton::uint32*)(this->x14))); + case triton::arch::ID_REG_RV32_X15: return (*((triton::uint32*)(this->x15))); + case triton::arch::ID_REG_RV32_X16: return (*((triton::uint32*)(this->x16))); + case triton::arch::ID_REG_RV32_X17: return (*((triton::uint32*)(this->x17))); + case triton::arch::ID_REG_RV32_X18: return (*((triton::uint32*)(this->x18))); + case triton::arch::ID_REG_RV32_X19: return (*((triton::uint32*)(this->x19))); + case triton::arch::ID_REG_RV32_X20: return (*((triton::uint32*)(this->x20))); + case triton::arch::ID_REG_RV32_X21: return (*((triton::uint32*)(this->x21))); + case triton::arch::ID_REG_RV32_X22: return (*((triton::uint32*)(this->x22))); + case triton::arch::ID_REG_RV32_X23: return (*((triton::uint32*)(this->x23))); + case triton::arch::ID_REG_RV32_X24: return (*((triton::uint32*)(this->x24))); + case triton::arch::ID_REG_RV32_X25: return (*((triton::uint32*)(this->x25))); + case triton::arch::ID_REG_RV32_X26: return (*((triton::uint32*)(this->x26))); + case triton::arch::ID_REG_RV32_X27: return (*((triton::uint32*)(this->x27))); + case triton::arch::ID_REG_RV32_X28: return (*((triton::uint32*)(this->x28))); + case triton::arch::ID_REG_RV32_X29: return (*((triton::uint32*)(this->x29))); + case triton::arch::ID_REG_RV32_X30: return (*((triton::uint32*)(this->x30))); + case triton::arch::ID_REG_RV32_X31: return (*((triton::uint32*)(this->x31))); + case triton::arch::ID_REG_RV32_PC: return (*((triton::uint32*)(this->pc))); + case triton::arch::ID_REG_RV32_F0: return (*((triton::uint32*)(this->f0))); + case triton::arch::ID_REG_RV32_F1: return (*((triton::uint32*)(this->f1))); + case triton::arch::ID_REG_RV32_F2: return (*((triton::uint32*)(this->f2))); + case triton::arch::ID_REG_RV32_F3: return (*((triton::uint32*)(this->f3))); + case triton::arch::ID_REG_RV32_F4: return (*((triton::uint32*)(this->f4))); + case triton::arch::ID_REG_RV32_F5: return (*((triton::uint32*)(this->f5))); + case triton::arch::ID_REG_RV32_F6: return (*((triton::uint32*)(this->f6))); + case triton::arch::ID_REG_RV32_F7: return (*((triton::uint32*)(this->f7))); + case triton::arch::ID_REG_RV32_F8: return (*((triton::uint32*)(this->f8))); + case triton::arch::ID_REG_RV32_F9: return (*((triton::uint32*)(this->f9))); + case triton::arch::ID_REG_RV32_F10: return (*((triton::uint32*)(this->f10))); + case triton::arch::ID_REG_RV32_F11: return (*((triton::uint32*)(this->f11))); + case triton::arch::ID_REG_RV32_F12: return (*((triton::uint32*)(this->f12))); + case triton::arch::ID_REG_RV32_F13: return (*((triton::uint32*)(this->f13))); + case triton::arch::ID_REG_RV32_F14: return (*((triton::uint32*)(this->f14))); + case triton::arch::ID_REG_RV32_F15: return (*((triton::uint32*)(this->f15))); + case triton::arch::ID_REG_RV32_F16: return (*((triton::uint32*)(this->f16))); + case triton::arch::ID_REG_RV32_F17: return (*((triton::uint32*)(this->f17))); + case triton::arch::ID_REG_RV32_F18: return (*((triton::uint32*)(this->f18))); + case triton::arch::ID_REG_RV32_F19: return (*((triton::uint32*)(this->f19))); + case triton::arch::ID_REG_RV32_F20: return (*((triton::uint32*)(this->f20))); + case triton::arch::ID_REG_RV32_F21: return (*((triton::uint32*)(this->f21))); + case triton::arch::ID_REG_RV32_F22: return (*((triton::uint32*)(this->f22))); + case triton::arch::ID_REG_RV32_F23: return (*((triton::uint32*)(this->f23))); + case triton::arch::ID_REG_RV32_F24: return (*((triton::uint32*)(this->f24))); + case triton::arch::ID_REG_RV32_F25: return (*((triton::uint32*)(this->f25))); + case triton::arch::ID_REG_RV32_F26: return (*((triton::uint32*)(this->f26))); + case triton::arch::ID_REG_RV32_F27: return (*((triton::uint32*)(this->f27))); + case triton::arch::ID_REG_RV32_F28: return (*((triton::uint32*)(this->f28))); + case triton::arch::ID_REG_RV32_F29: return (*((triton::uint32*)(this->f29))); + case triton::arch::ID_REG_RV32_F30: return (*((triton::uint32*)(this->f30))); + case triton::arch::ID_REG_RV32_F31: return (*((triton::uint32*)(this->f31))); + + default: + throw triton::exceptions::Cpu("riscv32Cpu::getConcreteRegisterValue(): Invalid register."); + } + + return value; + } + + + void riscv32Cpu::setConcreteMemoryValue(triton::uint64 addr, triton::uint8 value, bool execCallbacks) { + if (execCallbacks && this->callbacks) + this->callbacks->processCallbacks(triton::callbacks::SET_CONCRETE_MEMORY_VALUE, MemoryAccess(addr, triton::size::byte), value); + this->memory[addr] = value; + } + + + void riscv32Cpu::setConcreteMemoryValue(const triton::arch::MemoryAccess& mem, const triton::uint512& value, bool execCallbacks) { + triton::uint64 addr = mem.getAddress(); + triton::uint32 size = mem.getSize(); + triton::uint512 cv = value; + + if (cv > mem.getMaxValue()) + throw triton::exceptions::Register("riscv32Cpu::setConcreteMemoryValue(): You cannot set this concrete value (too big) to this memory access."); + + if (size == 0 || size > triton::size::dqqword) + throw triton::exceptions::Cpu("riscv32Cpu::setConcreteMemoryValue(): Invalid size memory."); + + if (execCallbacks && this->callbacks) + this->callbacks->processCallbacks(triton::callbacks::SET_CONCRETE_MEMORY_VALUE, mem, value); + + for (triton::uint32 i = 0; i < size; i++) { + this->memory[addr+i] = static_cast((cv & 0xff)); + cv >>= 8; + } + } + + + void riscv32Cpu::setConcreteMemoryAreaValue(triton::uint64 baseAddr, const std::vector& values, bool execCallbacks) { + // Pre-reserving the memory. We modified the original robin_map to not force rehash on reserve. + this->memory.reserve(values.size() + this->memory.size()); + for (triton::usize index = 0; index < values.size(); index++) { + this->setConcreteMemoryValue(baseAddr+index, values[index], execCallbacks); + } + } + + + void riscv32Cpu::setConcreteMemoryAreaValue(triton::uint64 baseAddr, const void* area, triton::usize size, bool execCallbacks) { + // Pre-reserving the memory. We modified the original robin_map to not force rehash on every reserve if not needed. + this->memory.reserve(size + this->memory.size()); + for (triton::usize index = 0; index < size; index++) { + this->setConcreteMemoryValue(baseAddr+index, reinterpret_cast(area)[index], execCallbacks); + } + } + + + void riscv32Cpu::setConcreteRegisterValue(const triton::arch::Register& reg, const triton::uint512& value, bool execCallbacks) { + if (value > reg.getMaxValue()) + throw triton::exceptions::Register("riscv32Cpu::setConcreteRegisterValue(): You cannot set this concrete value (too big) to this register."); + + if (execCallbacks && this->callbacks) + this->callbacks->processCallbacks(triton::callbacks::SET_CONCRETE_REGISTER_VALUE, reg, value); + + switch (reg.getId()) { + case triton::arch::ID_REG_RV32_X0: break; // Always zero, just do nothing + case triton::arch::ID_REG_RV32_X1: (*((triton::uint32*)(this->x1))) = static_cast(value); break; + case triton::arch::ID_REG_RV32_SP: (*((triton::uint32*)(this->sp))) = static_cast(value); break; + case triton::arch::ID_REG_RV32_X3: (*((triton::uint32*)(this->x3))) = static_cast(value); break; + case triton::arch::ID_REG_RV32_X4: (*((triton::uint32*)(this->x4))) = static_cast(value); break; + case triton::arch::ID_REG_RV32_X5: (*((triton::uint32*)(this->x5))) = static_cast(value); break; + case triton::arch::ID_REG_RV32_X6: (*((triton::uint32*)(this->x6))) = static_cast(value); break; + case triton::arch::ID_REG_RV32_X7: (*((triton::uint32*)(this->x7))) = static_cast(value); break; + case triton::arch::ID_REG_RV32_X8: (*((triton::uint32*)(this->x8))) = static_cast(value); break; + case triton::arch::ID_REG_RV32_X9: (*((triton::uint32*)(this->x9))) = static_cast(value); break; + case triton::arch::ID_REG_RV32_X10: (*((triton::uint32*)(this->x10))) = static_cast(value); break; + case triton::arch::ID_REG_RV32_X11: (*((triton::uint32*)(this->x11))) = static_cast(value); break; + case triton::arch::ID_REG_RV32_X12: (*((triton::uint32*)(this->x12))) = static_cast(value); break; + case triton::arch::ID_REG_RV32_X13: (*((triton::uint32*)(this->x13))) = static_cast(value); break; + case triton::arch::ID_REG_RV32_X14: (*((triton::uint32*)(this->x14))) = static_cast(value); break; + case triton::arch::ID_REG_RV32_X15: (*((triton::uint32*)(this->x15))) = static_cast(value); break; + case triton::arch::ID_REG_RV32_X16: (*((triton::uint32*)(this->x16))) = static_cast(value); break; + case triton::arch::ID_REG_RV32_X17: (*((triton::uint32*)(this->x17))) = static_cast(value); break; + case triton::arch::ID_REG_RV32_X18: (*((triton::uint32*)(this->x18))) = static_cast(value); break; + case triton::arch::ID_REG_RV32_X19: (*((triton::uint32*)(this->x19))) = static_cast(value); break; + case triton::arch::ID_REG_RV32_X20: (*((triton::uint32*)(this->x20))) = static_cast(value); break; + case triton::arch::ID_REG_RV32_X21: (*((triton::uint32*)(this->x21))) = static_cast(value); break; + case triton::arch::ID_REG_RV32_X22: (*((triton::uint32*)(this->x22))) = static_cast(value); break; + case triton::arch::ID_REG_RV32_X23: (*((triton::uint32*)(this->x23))) = static_cast(value); break; + case triton::arch::ID_REG_RV32_X24: (*((triton::uint32*)(this->x24))) = static_cast(value); break; + case triton::arch::ID_REG_RV32_X25: (*((triton::uint32*)(this->x25))) = static_cast(value); break; + case triton::arch::ID_REG_RV32_X26: (*((triton::uint32*)(this->x26))) = static_cast(value); break; + case triton::arch::ID_REG_RV32_X27: (*((triton::uint32*)(this->x27))) = static_cast(value); break; + case triton::arch::ID_REG_RV32_X28: (*((triton::uint32*)(this->x28))) = static_cast(value); break; + case triton::arch::ID_REG_RV32_X29: (*((triton::uint32*)(this->x29))) = static_cast(value); break; + case triton::arch::ID_REG_RV32_X30: (*((triton::uint32*)(this->x30))) = static_cast(value); break; + case triton::arch::ID_REG_RV32_X31: (*((triton::uint32*)(this->x31))) = static_cast(value); break; + case triton::arch::ID_REG_RV32_PC: (*((triton::uint32*)(this->pc))) = static_cast(value); break; + + case triton::arch::ID_REG_RV32_F0: (*((triton::uint32*)(this->f0))) = static_cast(value); break; + case triton::arch::ID_REG_RV32_F1: (*((triton::uint32*)(this->f1))) = static_cast(value); break; + case triton::arch::ID_REG_RV32_F2: (*((triton::uint32*)(this->f2))) = static_cast(value); break; + case triton::arch::ID_REG_RV32_F3: (*((triton::uint32*)(this->f3))) = static_cast(value); break; + case triton::arch::ID_REG_RV32_F4: (*((triton::uint32*)(this->f4))) = static_cast(value); break; + case triton::arch::ID_REG_RV32_F5: (*((triton::uint32*)(this->f5))) = static_cast(value); break; + case triton::arch::ID_REG_RV32_F6: (*((triton::uint32*)(this->f6))) = static_cast(value); break; + case triton::arch::ID_REG_RV32_F7: (*((triton::uint32*)(this->f7))) = static_cast(value); break; + case triton::arch::ID_REG_RV32_F8: (*((triton::uint32*)(this->f8))) = static_cast(value); break; + case triton::arch::ID_REG_RV32_F9: (*((triton::uint32*)(this->f9))) = static_cast(value); break; + case triton::arch::ID_REG_RV32_F10: (*((triton::uint32*)(this->f10))) = static_cast(value); break; + case triton::arch::ID_REG_RV32_F11: (*((triton::uint32*)(this->f11))) = static_cast(value); break; + case triton::arch::ID_REG_RV32_F12: (*((triton::uint32*)(this->f12))) = static_cast(value); break; + case triton::arch::ID_REG_RV32_F13: (*((triton::uint32*)(this->f13))) = static_cast(value); break; + case triton::arch::ID_REG_RV32_F14: (*((triton::uint32*)(this->f14))) = static_cast(value); break; + case triton::arch::ID_REG_RV32_F15: (*((triton::uint32*)(this->f15))) = static_cast(value); break; + case triton::arch::ID_REG_RV32_F16: (*((triton::uint32*)(this->f16))) = static_cast(value); break; + case triton::arch::ID_REG_RV32_F17: (*((triton::uint32*)(this->f17))) = static_cast(value); break; + case triton::arch::ID_REG_RV32_F18: (*((triton::uint32*)(this->f18))) = static_cast(value); break; + case triton::arch::ID_REG_RV32_F19: (*((triton::uint32*)(this->f19))) = static_cast(value); break; + case triton::arch::ID_REG_RV32_F20: (*((triton::uint32*)(this->f20))) = static_cast(value); break; + case triton::arch::ID_REG_RV32_F21: (*((triton::uint32*)(this->f21))) = static_cast(value); break; + case triton::arch::ID_REG_RV32_F22: (*((triton::uint32*)(this->f22))) = static_cast(value); break; + case triton::arch::ID_REG_RV32_F23: (*((triton::uint32*)(this->f23))) = static_cast(value); break; + case triton::arch::ID_REG_RV32_F24: (*((triton::uint32*)(this->f24))) = static_cast(value); break; + case triton::arch::ID_REG_RV32_F25: (*((triton::uint32*)(this->f25))) = static_cast(value); break; + case triton::arch::ID_REG_RV32_F26: (*((triton::uint32*)(this->f26))) = static_cast(value); break; + case triton::arch::ID_REG_RV32_F27: (*((triton::uint32*)(this->f27))) = static_cast(value); break; + case triton::arch::ID_REG_RV32_F28: (*((triton::uint32*)(this->f28))) = static_cast(value); break; + case triton::arch::ID_REG_RV32_F29: (*((triton::uint32*)(this->f29))) = static_cast(value); break; + case triton::arch::ID_REG_RV32_F30: (*((triton::uint32*)(this->f30))) = static_cast(value); break; + case triton::arch::ID_REG_RV32_F31: (*((triton::uint32*)(this->f31))) = static_cast(value); break; + + default: + throw triton::exceptions::Cpu("riscv32Cpu:setConcreteRegisterValue(): Invalid register."); + + } + } + + + bool riscv32Cpu::isThumb(void) const { + /* There is no thumb mode in RV */ + return false; + } + + + void riscv32Cpu::setThumb(bool state) { + /* There is no thumb mode in RV */ + } + + + bool riscv32Cpu::isMemoryExclusive(const triton::arch::MemoryAccess& mem) const { + /* There is no exclusive memory access support in RV */ + return false; + } + + + void riscv32Cpu::setMemoryExclusiveTag(const triton::arch::MemoryAccess& mem, bool tag) { + /* There is no exclusive memory access support in RV */ + } + + + bool riscv32Cpu::isConcreteMemoryValueDefined(const triton::arch::MemoryAccess& mem) const { + return this->isConcreteMemoryValueDefined(mem.getAddress(), mem.getSize()); + } + + + bool riscv32Cpu::isConcreteMemoryValueDefined(triton::uint64 baseAddr, triton::usize size) const { + for (triton::usize index = 0; index < size; index++) { + if (this->memory.find(baseAddr + index) == this->memory.end()) { + return false; + } + } + return true; + } + + + void riscv32Cpu::clearConcreteMemoryValue(const triton::arch::MemoryAccess& mem) { + this->clearConcreteMemoryValue(mem.getAddress(), mem.getSize()); + } + + + void riscv32Cpu::clearConcreteMemoryValue(triton::uint64 baseAddr, triton::usize size) { + for (triton::usize index = 0; index < size; index++) { + if (this->memory.find(baseAddr + index) != this->memory.end()) { + this->memory.erase(baseAddr + index); + } + } + } + + }; /* riscv namespace */ + }; /* arch namespace */ +}; /* triton namespace */ diff --git a/src/libtriton/arch/riscv/riscv64Cpu.cpp b/src/libtriton/arch/riscv/riscv64Cpu.cpp new file mode 100644 index 000000000..4f7a90563 --- /dev/null +++ b/src/libtriton/arch/riscv/riscv64Cpu.cpp @@ -0,0 +1,741 @@ +//! \file +/* +** Copyright (C) - Triton +** +** This program is under the terms of the Apache License 2.0. +*/ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + + + +namespace triton { + namespace arch { + namespace riscv { + + riscv64Cpu::riscv64Cpu(triton::callbacks::Callbacks* callbacks) : riscvSpecifications(ARCH_RV64) { + this->callbacks = callbacks; + this->handle = 0; + + this->clear(); + this->disassInit(); + } + + + riscv64Cpu::riscv64Cpu(const riscv64Cpu& other) : riscvSpecifications(ARCH_RV64) { + this->copy(other); + } + + + riscv64Cpu::~riscv64Cpu() { + this->memory.clear(); + if (this->handle) { + triton::extlibs::capstone::cs_close(&this->handle); + } + } + + void riscv64Cpu::disassInit(void) { + if (this->handle) { + triton::extlibs::capstone::cs_close(&this->handle); + } + + // CS_MODE_RISCV64 | CS_MODE_RISCVC + auto rv_mode = static_cast((1 << 1) | (1 << 2)); + if (triton::extlibs::capstone::cs_open(triton::extlibs::capstone::CS_ARCH_RISCV, rv_mode, &this->handle) != triton::extlibs::capstone::CS_ERR_OK) + throw triton::exceptions::Disassembly("riscv64Cpu::disassInit(): Cannot open capstone."); + + triton::extlibs::capstone::cs_option(this->handle, triton::extlibs::capstone::CS_OPT_DETAIL, triton::extlibs::capstone::CS_OPT_ON); + } + + + void riscv64Cpu::copy(const riscv64Cpu& other) { + this->callbacks = other.callbacks; + this->memory = other.memory; + + std::memcpy(this->x0, other.x0, sizeof(this->x0)); + std::memcpy(this->x1, other.x1, sizeof(this->x1)); + std::memcpy(this->sp, other.sp, sizeof(this->sp)); + std::memcpy(this->x3, other.x3, sizeof(this->x3)); + std::memcpy(this->x4, other.x4, sizeof(this->x4)); + std::memcpy(this->x5, other.x5, sizeof(this->x5)); + std::memcpy(this->x6, other.x6, sizeof(this->x6)); + std::memcpy(this->x7, other.x7, sizeof(this->x7)); + std::memcpy(this->x8, other.x8, sizeof(this->x8)); + std::memcpy(this->x9, other.x9, sizeof(this->x9)); + std::memcpy(this->x10, other.x10, sizeof(this->x10)); + std::memcpy(this->x11, other.x11, sizeof(this->x11)); + std::memcpy(this->x12, other.x12, sizeof(this->x12)); + std::memcpy(this->x13, other.x13, sizeof(this->x13)); + std::memcpy(this->x14, other.x14, sizeof(this->x14)); + std::memcpy(this->x15, other.x15, sizeof(this->x15)); + std::memcpy(this->x16, other.x16, sizeof(this->x16)); + std::memcpy(this->x17, other.x17, sizeof(this->x17)); + std::memcpy(this->x18, other.x18, sizeof(this->x18)); + std::memcpy(this->x19, other.x19, sizeof(this->x19)); + std::memcpy(this->x20, other.x20, sizeof(this->x20)); + std::memcpy(this->x21, other.x21, sizeof(this->x21)); + std::memcpy(this->x22, other.x22, sizeof(this->x22)); + std::memcpy(this->x23, other.x23, sizeof(this->x23)); + std::memcpy(this->x24, other.x24, sizeof(this->x24)); + std::memcpy(this->x25, other.x25, sizeof(this->x25)); + std::memcpy(this->x26, other.x26, sizeof(this->x26)); + std::memcpy(this->x27, other.x27, sizeof(this->x27)); + std::memcpy(this->x28, other.x28, sizeof(this->x28)); + std::memcpy(this->x29, other.x29, sizeof(this->x29)); + std::memcpy(this->x30, other.x30, sizeof(this->x30)); + std::memcpy(this->x31, other.x31, sizeof(this->x31)); + std::memcpy(this->pc, other.pc, sizeof(this->pc)); + std::memcpy(this->f0, other.f0, sizeof(this->f0)); + std::memcpy(this->f1, other.f1, sizeof(this->f1)); + std::memcpy(this->f2, other.f2, sizeof(this->f2)); + std::memcpy(this->f3, other.f3, sizeof(this->f3)); + std::memcpy(this->f4, other.f4, sizeof(this->f4)); + std::memcpy(this->f5, other.f5, sizeof(this->f5)); + std::memcpy(this->f6, other.f6, sizeof(this->f6)); + std::memcpy(this->f7, other.f7, sizeof(this->f7)); + std::memcpy(this->f8, other.f8, sizeof(this->f8)); + std::memcpy(this->f9, other.f9, sizeof(this->f9)); + std::memcpy(this->f10, other.f10, sizeof(this->f10)); + std::memcpy(this->f11, other.f11, sizeof(this->f11)); + std::memcpy(this->f12, other.f12, sizeof(this->f12)); + std::memcpy(this->f13, other.f13, sizeof(this->f13)); + std::memcpy(this->f14, other.f14, sizeof(this->f14)); + std::memcpy(this->f15, other.f15, sizeof(this->f15)); + std::memcpy(this->f16, other.f16, sizeof(this->f16)); + std::memcpy(this->f17, other.f17, sizeof(this->f17)); + std::memcpy(this->f18, other.f18, sizeof(this->f18)); + std::memcpy(this->f19, other.f19, sizeof(this->f19)); + std::memcpy(this->f20, other.f20, sizeof(this->f20)); + std::memcpy(this->f21, other.f21, sizeof(this->f21)); + std::memcpy(this->f22, other.f22, sizeof(this->f22)); + std::memcpy(this->f23, other.f23, sizeof(this->f23)); + std::memcpy(this->f24, other.f24, sizeof(this->f24)); + std::memcpy(this->f25, other.f25, sizeof(this->f25)); + std::memcpy(this->f26, other.f26, sizeof(this->f26)); + std::memcpy(this->f27, other.f27, sizeof(this->f27)); + std::memcpy(this->f28, other.f28, sizeof(this->f28)); + std::memcpy(this->f29, other.f29, sizeof(this->f29)); + std::memcpy(this->f30, other.f30, sizeof(this->f30)); + std::memcpy(this->f31, other.f31, sizeof(this->f31)); + } + + + void riscv64Cpu::clear(void) { + /* Clear memory */ + this->memory.clear(); + + /* Clear registers */ + std::memset(this->x0, 0x00, sizeof(this->x0)); + std::memset(this->x1, 0x00, sizeof(this->x1)); + std::memset(this->sp, 0x00, sizeof(this->sp)); + std::memset(this->x3, 0x00, sizeof(this->x3)); + std::memset(this->x4, 0x00, sizeof(this->x4)); + std::memset(this->x5, 0x00, sizeof(this->x5)); + std::memset(this->x6, 0x00, sizeof(this->x6)); + std::memset(this->x7, 0x00, sizeof(this->x7)); + std::memset(this->x8, 0x00, sizeof(this->x8)); + std::memset(this->x9, 0x00, sizeof(this->x9)); + std::memset(this->x10, 0x00, sizeof(this->x10)); + std::memset(this->x11, 0x00, sizeof(this->x11)); + std::memset(this->x12, 0x00, sizeof(this->x12)); + std::memset(this->x13, 0x00, sizeof(this->x13)); + std::memset(this->x14, 0x00, sizeof(this->x14)); + std::memset(this->x15, 0x00, sizeof(this->x15)); + std::memset(this->x16, 0x00, sizeof(this->x16)); + std::memset(this->x17, 0x00, sizeof(this->x17)); + std::memset(this->x18, 0x00, sizeof(this->x18)); + std::memset(this->x19, 0x00, sizeof(this->x19)); + std::memset(this->x20, 0x00, sizeof(this->x20)); + std::memset(this->x21, 0x00, sizeof(this->x21)); + std::memset(this->x22, 0x00, sizeof(this->x22)); + std::memset(this->x23, 0x00, sizeof(this->x23)); + std::memset(this->x24, 0x00, sizeof(this->x24)); + std::memset(this->x25, 0x00, sizeof(this->x25)); + std::memset(this->x26, 0x00, sizeof(this->x26)); + std::memset(this->x27, 0x00, sizeof(this->x27)); + std::memset(this->x28, 0x00, sizeof(this->x28)); + std::memset(this->x29, 0x00, sizeof(this->x29)); + std::memset(this->x30, 0x00, sizeof(this->x30)); + std::memset(this->x31, 0x00, sizeof(this->x31)); + std::memset(this->pc, 0x00, sizeof(this->pc)); + std::memset(this->f0, 0x00, sizeof(this->f0)); + std::memset(this->f1, 0x00, sizeof(this->f1)); + std::memset(this->f2, 0x00, sizeof(this->f2)); + std::memset(this->f3, 0x00, sizeof(this->f3)); + std::memset(this->f4, 0x00, sizeof(this->f4)); + std::memset(this->f5, 0x00, sizeof(this->f5)); + std::memset(this->f6, 0x00, sizeof(this->f6)); + std::memset(this->f7, 0x00, sizeof(this->f7)); + std::memset(this->f8, 0x00, sizeof(this->f8)); + std::memset(this->f9, 0x00, sizeof(this->f9)); + std::memset(this->f10, 0x00, sizeof(this->f10)); + std::memset(this->f11, 0x00, sizeof(this->f11)); + std::memset(this->f12, 0x00, sizeof(this->f12)); + std::memset(this->f13, 0x00, sizeof(this->f13)); + std::memset(this->f14, 0x00, sizeof(this->f14)); + std::memset(this->f15, 0x00, sizeof(this->f15)); + std::memset(this->f16, 0x00, sizeof(this->f16)); + std::memset(this->f17, 0x00, sizeof(this->f17)); + std::memset(this->f18, 0x00, sizeof(this->f18)); + std::memset(this->f19, 0x00, sizeof(this->f19)); + std::memset(this->f20, 0x00, sizeof(this->f20)); + std::memset(this->f21, 0x00, sizeof(this->f21)); + std::memset(this->f22, 0x00, sizeof(this->f22)); + std::memset(this->f23, 0x00, sizeof(this->f23)); + std::memset(this->f24, 0x00, sizeof(this->f24)); + std::memset(this->f25, 0x00, sizeof(this->f25)); + std::memset(this->f26, 0x00, sizeof(this->f26)); + std::memset(this->f27, 0x00, sizeof(this->f27)); + std::memset(this->f28, 0x00, sizeof(this->f28)); + std::memset(this->f29, 0x00, sizeof(this->f29)); + std::memset(this->f30, 0x00, sizeof(this->f30)); + std::memset(this->f31, 0x00, sizeof(this->f31)); + } + + + riscv64Cpu& riscv64Cpu::operator=(const riscv64Cpu& other) { + this->copy(other); + return *this; + } + + + triton::arch::endianness_e riscv64Cpu::getEndianness(void) const { + return triton::arch::LE_ENDIANNESS; + } + + + bool riscv64Cpu::isRegister(triton::arch::register_e regId) const { + return (this->isGPR(regId) || this->isFPU(regId) || regId == triton::arch::ID_REG_RV64_PC); + } + + + bool riscv64Cpu::isRegisterValid(triton::arch::register_e regId) const { + return (this->isFlag(regId) || this->isRegister(regId)); + } + + + bool riscv64Cpu::isGPR(triton::arch::register_e regId) const { + return ((regId >= triton::arch::ID_REG_RV64_X0 && regId <= triton::arch::ID_REG_RV64_X31) ? true : false); + } + + + bool riscv64Cpu::isFPU(triton::arch::register_e regId) const { + return ((regId >= triton::arch::ID_REG_RV64_F0 && regId <= triton::arch::ID_REG_RV64_F31) ? true : false); + } + + + bool riscv64Cpu::isFlag(triton::arch::register_e regId) const { + return false; + } + + + triton::uint32 riscv64Cpu::numberOfRegisters(void) const { + return triton::arch::ID_REG_LAST_ITEM; + } + + + triton::uint32 riscv64Cpu::gprSize(void) const { + return triton::size::qword; + } + + + triton::uint32 riscv64Cpu::gprBitSize(void) const { + return triton::bitsize::qword; + } + + + const std::unordered_map& riscv64Cpu::getAllRegisters(void) const { + return this->id2reg; + } + + const std::unordered_map>& riscv64Cpu::getConcreteMemory(void) const { + return this->memory; + } + + std::set riscv64Cpu::getParentRegisters(void) const { + std::set ret; + + for (const auto& kv: this->id2reg) { + auto regId = kv.first; + const auto& reg = kv.second; + + /* Add GPR */ + if (reg.getSize() == this->gprSize()) + ret.insert(®); + + /* Add FPU */ + else if (this->isFPU(regId)) + ret.insert(®); + } + + return ret; + } + + + const triton::arch::Register& riscv64Cpu::getRegister(triton::arch::register_e id) const { + try { + return this->id2reg.at(id); + } catch (const std::out_of_range&) { + throw triton::exceptions::Cpu("riscv64Cpu::getRegister(): Invalid register for this architecture."); + } + } + + + const triton::arch::Register& riscv64Cpu::getRegister(const std::string& name) const { + std::string lower = name; + std::transform(lower.begin(), lower.end(), lower.begin(), [](unsigned char c){ return std::tolower(c); }); + try { + return this->getRegister(this->name2id.at(lower)); + } catch (const std::out_of_range&) { + throw triton::exceptions::Cpu("riscv64Cpu::getRegister(): Invalid register for this architecture."); + } + } + + + const triton::arch::Register& riscv64Cpu::getParentRegister(const triton::arch::Register& reg) const { + return this->getRegister(reg.getParent()); + } + + + const triton::arch::Register& riscv64Cpu::getParentRegister(triton::arch::register_e id) const { + return this->getParentRegister(this->getRegister(id)); + } + + + const triton::arch::Register& riscv64Cpu::getProgramCounter(void) const { + return this->getRegister(this->pcId); + } + + + const triton::arch::Register& riscv64Cpu::getStackPointer(void) const { + return this->getRegister(this->spId); + } + + void riscv64Cpu::disassembly(triton::arch::Instruction& inst) { + + triton::extlibs::capstone::cs_insn* insn; + triton::usize count = 0; + triton::uint32 size = 0; + + /* Check if the opcode and opcode' size are defined */ + if (inst.getOpcode() == nullptr || inst.getSize() == 0) + throw triton::exceptions::Disassembly("riscv64Cpu::disassembly(): Opcode and opcodeSize must be definied."); + + /* Clear instructicon's operands if alredy defined */ + inst.operands.clear(); + + /* Update instruction address if undefined */ + if (!inst.getAddress()) { + inst.setAddress(static_cast(this->getConcreteRegisterValue(this->getProgramCounter()))); + } + + /* Let's disass and build our operands */ + count = triton::extlibs::capstone::cs_disasm(this->handle, inst.getOpcode(), inst.getSize(), inst.getAddress(), 0, &insn); + if (count > 0) { + /* Detail information */ + triton::extlibs::capstone::cs_detail* detail = insn->detail; + + /* Init the disassembly */ + std::stringstream str; + + str << insn[0].mnemonic; + if (detail->riscv.op_count) + str << " " << insn[0].op_str; + + inst.setDisassembly(str.str()); + + /* Refine the size */ + inst.setSize(insn[0].size); + + /* Init the instruction's type */ + inst.setType(this->capstoneInstructionToTritonInstruction(insn[0].id)); + + /* Set architecture */ + inst.setArchitecture(triton::arch::ARCH_RV64); + + /* Init operands */ + for (triton::uint32 n = 0; n < detail->riscv.op_count; n++) { + triton::extlibs::capstone::cs_riscv_op* op = &(detail->riscv.operands[n]); + + switch(op->type) { + + case triton::extlibs::capstone::RISCV_OP_IMM: { + triton::arch::Immediate imm(op->imm, size ? size : triton::size::qword); + if (static_cast(op->imm) > imm.getValue()) { + imm = Immediate(); + imm.setValue(op->imm, 0); /* By setting 0 as size, we automatically identify the size of the value */ + } + + inst.operands.push_back(triton::arch::OperandWrapper(imm)); + break; + } + + case triton::extlibs::capstone::RISCV_OP_MEM: { + triton::arch::MemoryAccess mem; + + /* Set the size of the memory access */ + size = this->getMemoryOperandSpecialSize(inst.getType()); + mem.setBits(size ? ((size * triton::bitsize::byte) - 1) : triton::bitsize::qword - 1, 0); + + /* Set address calculation units */ + triton::arch::Register base(*this, this->capstoneRegisterToTritonRegister64(op->mem.base)); + + triton::uint32 immsize = ( + this->isRegisterValid(base.getId()) ? base.getSize() : + this->gprSize() + ); + + triton::arch::Immediate disp(op->mem.disp, immsize); + + mem.setBaseRegister(base); + mem.setDisplacement(disp); + + inst.operands.push_back(triton::arch::OperandWrapper(mem)); + break; + } + + case triton::extlibs::capstone::RISCV_OP_REG: { + inst.operands.push_back(triton::arch::OperandWrapper(triton::arch::Register(*this, this->capstoneRegisterToTritonRegister64(op->reg)))); + break; + } + + default: + throw triton::exceptions::Disassembly("riscv64Cpu::disassembly(): Invalid operand."); + } // switch + } // for operand + + /* Set branch */ + if (detail->groups_count > 0) { + for (triton::uint32 n = 0; n < detail->groups_count; n++) { + if (detail->groups[n] == triton::extlibs::capstone::RISCV_GRP_JUMP) + inst.setBranch(true); + if (detail->groups[n] == triton::extlibs::capstone::RISCV_GRP_JUMP || + detail->groups[n] == triton::extlibs::capstone::RISCV_GRP_CALL || + detail->groups[n] == triton::extlibs::capstone::RISCV_GRP_RET) + inst.setControlFlow(true); + } + } + + /* Free capstone stuffs */ + triton::extlibs::capstone::cs_free(insn, count); + } + else + throw triton::exceptions::Disassembly("riscv64Cpu::disassembly(): Failed to disassemble the given code."); + } + + + triton::uint8 riscv64Cpu::getConcreteMemoryValue(triton::uint64 addr, bool execCallbacks) const { + if (execCallbacks && this->callbacks) + this->callbacks->processCallbacks(triton::callbacks::GET_CONCRETE_MEMORY_VALUE, MemoryAccess(addr, triton::size::byte)); + + auto it = this->memory.find(addr); + if (it == this->memory.end()) { + return 0x00; + } + + return it->second; + } + + + triton::uint512 riscv64Cpu::getConcreteMemoryValue(const triton::arch::MemoryAccess& mem, bool execCallbacks) const { + triton::uint512 ret = 0; + triton::uint64 addr = 0; + triton::uint32 size = 0; + + if (execCallbacks && this->callbacks) + this->callbacks->processCallbacks(triton::callbacks::GET_CONCRETE_MEMORY_VALUE, mem); + + addr = mem.getAddress(); + size = mem.getSize(); + + if (size == 0 || size > triton::size::dqqword) + throw triton::exceptions::Cpu("riscv64Cpu::getConcreteMemoryValue(): Invalid size memory."); + + for (triton::sint32 i = size-1; i >= 0; i--) + ret = ((ret << triton::bitsize::byte) | this->getConcreteMemoryValue(addr+i, false)); + + return ret; + } + + + std::vector riscv64Cpu::getConcreteMemoryAreaValue(triton::uint64 baseAddr, triton::usize size, bool execCallbacks) const { + std::vector area; + + for (triton::usize index = 0; index < size; index++) + area.push_back(this->getConcreteMemoryValue(baseAddr+index, execCallbacks)); + + return area; + } + + + triton::uint512 riscv64Cpu::getConcreteRegisterValue(const triton::arch::Register& reg, bool execCallbacks) const { + triton::uint512 value = 0; + + if (execCallbacks && this->callbacks) + this->callbacks->processCallbacks(triton::callbacks::GET_CONCRETE_REGISTER_VALUE, reg); + switch (reg.getId()) { + case triton::arch::ID_REG_RV64_X0: return 0; + case triton::arch::ID_REG_RV64_X1: return (*((triton::uint64*)(this->x1))); + case triton::arch::ID_REG_RV64_SP: return (*((triton::uint64*)(this->sp))); + case triton::arch::ID_REG_RV64_X3: return (*((triton::uint64*)(this->x3))); + case triton::arch::ID_REG_RV64_X4: return (*((triton::uint64*)(this->x4))); + case triton::arch::ID_REG_RV64_X5: return (*((triton::uint64*)(this->x5))); + case triton::arch::ID_REG_RV64_X6: return (*((triton::uint64*)(this->x6))); + case triton::arch::ID_REG_RV64_X7: return (*((triton::uint64*)(this->x7))); + case triton::arch::ID_REG_RV64_X8: return (*((triton::uint64*)(this->x8))); + case triton::arch::ID_REG_RV64_X9: return (*((triton::uint64*)(this->x9))); + case triton::arch::ID_REG_RV64_X10: return (*((triton::uint64*)(this->x10))); + case triton::arch::ID_REG_RV64_X11: return (*((triton::uint64*)(this->x11))); + case triton::arch::ID_REG_RV64_X12: return (*((triton::uint64*)(this->x12))); + case triton::arch::ID_REG_RV64_X13: return (*((triton::uint64*)(this->x13))); + case triton::arch::ID_REG_RV64_X14: return (*((triton::uint64*)(this->x14))); + case triton::arch::ID_REG_RV64_X15: return (*((triton::uint64*)(this->x15))); + case triton::arch::ID_REG_RV64_X16: return (*((triton::uint64*)(this->x16))); + case triton::arch::ID_REG_RV64_X17: return (*((triton::uint64*)(this->x17))); + case triton::arch::ID_REG_RV64_X18: return (*((triton::uint64*)(this->x18))); + case triton::arch::ID_REG_RV64_X19: return (*((triton::uint64*)(this->x19))); + case triton::arch::ID_REG_RV64_X20: return (*((triton::uint64*)(this->x20))); + case triton::arch::ID_REG_RV64_X21: return (*((triton::uint64*)(this->x21))); + case triton::arch::ID_REG_RV64_X22: return (*((triton::uint64*)(this->x22))); + case triton::arch::ID_REG_RV64_X23: return (*((triton::uint64*)(this->x23))); + case triton::arch::ID_REG_RV64_X24: return (*((triton::uint64*)(this->x24))); + case triton::arch::ID_REG_RV64_X25: return (*((triton::uint64*)(this->x25))); + case triton::arch::ID_REG_RV64_X26: return (*((triton::uint64*)(this->x26))); + case triton::arch::ID_REG_RV64_X27: return (*((triton::uint64*)(this->x27))); + case triton::arch::ID_REG_RV64_X28: return (*((triton::uint64*)(this->x28))); + case triton::arch::ID_REG_RV64_X29: return (*((triton::uint64*)(this->x29))); + case triton::arch::ID_REG_RV64_X30: return (*((triton::uint64*)(this->x30))); + case triton::arch::ID_REG_RV64_X31: return (*((triton::uint64*)(this->x31))); + case triton::arch::ID_REG_RV64_PC: return (*((triton::uint64*)(this->pc))); + case triton::arch::ID_REG_RV64_F0: return (*((triton::uint64*)(this->f0))); + case triton::arch::ID_REG_RV64_F1: return (*((triton::uint64*)(this->f1))); + case triton::arch::ID_REG_RV64_F2: return (*((triton::uint64*)(this->f2))); + case triton::arch::ID_REG_RV64_F3: return (*((triton::uint64*)(this->f3))); + case triton::arch::ID_REG_RV64_F4: return (*((triton::uint64*)(this->f4))); + case triton::arch::ID_REG_RV64_F5: return (*((triton::uint64*)(this->f5))); + case triton::arch::ID_REG_RV64_F6: return (*((triton::uint64*)(this->f6))); + case triton::arch::ID_REG_RV64_F7: return (*((triton::uint64*)(this->f7))); + case triton::arch::ID_REG_RV64_F8: return (*((triton::uint64*)(this->f8))); + case triton::arch::ID_REG_RV64_F9: return (*((triton::uint64*)(this->f9))); + case triton::arch::ID_REG_RV64_F10: return (*((triton::uint64*)(this->f10))); + case triton::arch::ID_REG_RV64_F11: return (*((triton::uint64*)(this->f11))); + case triton::arch::ID_REG_RV64_F12: return (*((triton::uint64*)(this->f12))); + case triton::arch::ID_REG_RV64_F13: return (*((triton::uint64*)(this->f13))); + case triton::arch::ID_REG_RV64_F14: return (*((triton::uint64*)(this->f14))); + case triton::arch::ID_REG_RV64_F15: return (*((triton::uint64*)(this->f15))); + case triton::arch::ID_REG_RV64_F16: return (*((triton::uint64*)(this->f16))); + case triton::arch::ID_REG_RV64_F17: return (*((triton::uint64*)(this->f17))); + case triton::arch::ID_REG_RV64_F18: return (*((triton::uint64*)(this->f18))); + case triton::arch::ID_REG_RV64_F19: return (*((triton::uint64*)(this->f19))); + case triton::arch::ID_REG_RV64_F20: return (*((triton::uint64*)(this->f20))); + case triton::arch::ID_REG_RV64_F21: return (*((triton::uint64*)(this->f21))); + case triton::arch::ID_REG_RV64_F22: return (*((triton::uint64*)(this->f22))); + case triton::arch::ID_REG_RV64_F23: return (*((triton::uint64*)(this->f23))); + case triton::arch::ID_REG_RV64_F24: return (*((triton::uint64*)(this->f24))); + case triton::arch::ID_REG_RV64_F25: return (*((triton::uint64*)(this->f25))); + case triton::arch::ID_REG_RV64_F26: return (*((triton::uint64*)(this->f26))); + case triton::arch::ID_REG_RV64_F27: return (*((triton::uint64*)(this->f27))); + case triton::arch::ID_REG_RV64_F28: return (*((triton::uint64*)(this->f28))); + case triton::arch::ID_REG_RV64_F29: return (*((triton::uint64*)(this->f29))); + case triton::arch::ID_REG_RV64_F30: return (*((triton::uint64*)(this->f30))); + case triton::arch::ID_REG_RV64_F31: return (*((triton::uint64*)(this->f31))); + + default: + throw triton::exceptions::Cpu("riscv64Cpu::getConcreteRegisterValue(): Invalid register."); + } + + return value; + } + + + void riscv64Cpu::setConcreteMemoryValue(triton::uint64 addr, triton::uint8 value, bool execCallbacks) { + if (execCallbacks && this->callbacks) + this->callbacks->processCallbacks(triton::callbacks::SET_CONCRETE_MEMORY_VALUE, MemoryAccess(addr, triton::size::byte), value); + this->memory[addr] = value; + } + + + void riscv64Cpu::setConcreteMemoryValue(const triton::arch::MemoryAccess& mem, const triton::uint512& value, bool execCallbacks) { + triton::uint64 addr = mem.getAddress(); + triton::uint32 size = mem.getSize(); + triton::uint512 cv = value; + + if (cv > mem.getMaxValue()) + throw triton::exceptions::Register("riscv64Cpu::setConcreteMemoryValue(): You cannot set this concrete value (too big) to this memory access."); + + if (size == 0 || size > triton::size::dqqword) + throw triton::exceptions::Cpu("riscv64Cpu::setConcreteMemoryValue(): Invalid size memory."); + + if (execCallbacks && this->callbacks) + this->callbacks->processCallbacks(triton::callbacks::SET_CONCRETE_MEMORY_VALUE, mem, value); + + for (triton::uint32 i = 0; i < size; i++) { + this->memory[addr+i] = static_cast((cv & 0xff)); + cv >>= 8; + } + } + + + void riscv64Cpu::setConcreteMemoryAreaValue(triton::uint64 baseAddr, const std::vector& values, bool execCallbacks) { + // Pre-reserving the memory. We modified the original robin_map to not force rehash on reserve. + this->memory.reserve(values.size() + this->memory.size()); + for (triton::usize index = 0; index < values.size(); index++) { + this->setConcreteMemoryValue(baseAddr+index, values[index], execCallbacks); + } + } + + + void riscv64Cpu::setConcreteMemoryAreaValue(triton::uint64 baseAddr, const void* area, triton::usize size, bool execCallbacks) { + // Pre-reserving the memory. We modified the original robin_map to not force rehash on every reserve if not needed. + this->memory.reserve(size + this->memory.size()); + for (triton::usize index = 0; index < size; index++) { + this->setConcreteMemoryValue(baseAddr+index, reinterpret_cast(area)[index], execCallbacks); + } + } + + + void riscv64Cpu::setConcreteRegisterValue(const triton::arch::Register& reg, const triton::uint512& value, bool execCallbacks) { + if (value > reg.getMaxValue()) + throw triton::exceptions::Register("riscv64Cpu::setConcreteRegisterValue(): You cannot set this concrete value (too big) to this register."); + + if (execCallbacks && this->callbacks) + this->callbacks->processCallbacks(triton::callbacks::SET_CONCRETE_REGISTER_VALUE, reg, value); + + switch (reg.getId()) { + case triton::arch::ID_REG_RV64_X0: break; // Always zero, just do nothing + case triton::arch::ID_REG_RV64_X1: (*((triton::uint64*)(this->x1))) = static_cast(value); break; + case triton::arch::ID_REG_RV64_SP: (*((triton::uint64*)(this->sp))) = static_cast(value); break; + case triton::arch::ID_REG_RV64_X3: (*((triton::uint64*)(this->x3))) = static_cast(value); break; + case triton::arch::ID_REG_RV64_X4: (*((triton::uint64*)(this->x4))) = static_cast(value); break; + case triton::arch::ID_REG_RV64_X5: (*((triton::uint64*)(this->x5))) = static_cast(value); break; + case triton::arch::ID_REG_RV64_X6: (*((triton::uint64*)(this->x6))) = static_cast(value); break; + case triton::arch::ID_REG_RV64_X7: (*((triton::uint64*)(this->x7))) = static_cast(value); break; + case triton::arch::ID_REG_RV64_X8: (*((triton::uint64*)(this->x8))) = static_cast(value); break; + case triton::arch::ID_REG_RV64_X9: (*((triton::uint64*)(this->x9))) = static_cast(value); break; + case triton::arch::ID_REG_RV64_X10: (*((triton::uint64*)(this->x10))) = static_cast(value); break; + case triton::arch::ID_REG_RV64_X11: (*((triton::uint64*)(this->x11))) = static_cast(value); break; + case triton::arch::ID_REG_RV64_X12: (*((triton::uint64*)(this->x12))) = static_cast(value); break; + case triton::arch::ID_REG_RV64_X13: (*((triton::uint64*)(this->x13))) = static_cast(value); break; + case triton::arch::ID_REG_RV64_X14: (*((triton::uint64*)(this->x14))) = static_cast(value); break; + case triton::arch::ID_REG_RV64_X15: (*((triton::uint64*)(this->x15))) = static_cast(value); break; + case triton::arch::ID_REG_RV64_X16: (*((triton::uint64*)(this->x16))) = static_cast(value); break; + case triton::arch::ID_REG_RV64_X17: (*((triton::uint64*)(this->x17))) = static_cast(value); break; + case triton::arch::ID_REG_RV64_X18: (*((triton::uint64*)(this->x18))) = static_cast(value); break; + case triton::arch::ID_REG_RV64_X19: (*((triton::uint64*)(this->x19))) = static_cast(value); break; + case triton::arch::ID_REG_RV64_X20: (*((triton::uint64*)(this->x20))) = static_cast(value); break; + case triton::arch::ID_REG_RV64_X21: (*((triton::uint64*)(this->x21))) = static_cast(value); break; + case triton::arch::ID_REG_RV64_X22: (*((triton::uint64*)(this->x22))) = static_cast(value); break; + case triton::arch::ID_REG_RV64_X23: (*((triton::uint64*)(this->x23))) = static_cast(value); break; + case triton::arch::ID_REG_RV64_X24: (*((triton::uint64*)(this->x24))) = static_cast(value); break; + case triton::arch::ID_REG_RV64_X25: (*((triton::uint64*)(this->x25))) = static_cast(value); break; + case triton::arch::ID_REG_RV64_X26: (*((triton::uint64*)(this->x26))) = static_cast(value); break; + case triton::arch::ID_REG_RV64_X27: (*((triton::uint64*)(this->x27))) = static_cast(value); break; + case triton::arch::ID_REG_RV64_X28: (*((triton::uint64*)(this->x28))) = static_cast(value); break; + case triton::arch::ID_REG_RV64_X29: (*((triton::uint64*)(this->x29))) = static_cast(value); break; + case triton::arch::ID_REG_RV64_X30: (*((triton::uint64*)(this->x30))) = static_cast(value); break; + case triton::arch::ID_REG_RV64_X31: (*((triton::uint64*)(this->x31))) = static_cast(value); break; + case triton::arch::ID_REG_RV64_PC: (*((triton::uint64*)(this->pc))) = static_cast(value); break; + + case triton::arch::ID_REG_RV64_F0: (*((triton::uint64*)(this->f0))) = static_cast(value); break; + case triton::arch::ID_REG_RV64_F1: (*((triton::uint64*)(this->f1))) = static_cast(value); break; + case triton::arch::ID_REG_RV64_F2: (*((triton::uint64*)(this->f2))) = static_cast(value); break; + case triton::arch::ID_REG_RV64_F3: (*((triton::uint64*)(this->f3))) = static_cast(value); break; + case triton::arch::ID_REG_RV64_F4: (*((triton::uint64*)(this->f4))) = static_cast(value); break; + case triton::arch::ID_REG_RV64_F5: (*((triton::uint64*)(this->f5))) = static_cast(value); break; + case triton::arch::ID_REG_RV64_F6: (*((triton::uint64*)(this->f6))) = static_cast(value); break; + case triton::arch::ID_REG_RV64_F7: (*((triton::uint64*)(this->f7))) = static_cast(value); break; + case triton::arch::ID_REG_RV64_F8: (*((triton::uint64*)(this->f8))) = static_cast(value); break; + case triton::arch::ID_REG_RV64_F9: (*((triton::uint64*)(this->f9))) = static_cast(value); break; + case triton::arch::ID_REG_RV64_F10: (*((triton::uint64*)(this->f10))) = static_cast(value); break; + case triton::arch::ID_REG_RV64_F11: (*((triton::uint64*)(this->f11))) = static_cast(value); break; + case triton::arch::ID_REG_RV64_F12: (*((triton::uint64*)(this->f12))) = static_cast(value); break; + case triton::arch::ID_REG_RV64_F13: (*((triton::uint64*)(this->f13))) = static_cast(value); break; + case triton::arch::ID_REG_RV64_F14: (*((triton::uint64*)(this->f14))) = static_cast(value); break; + case triton::arch::ID_REG_RV64_F15: (*((triton::uint64*)(this->f15))) = static_cast(value); break; + case triton::arch::ID_REG_RV64_F16: (*((triton::uint64*)(this->f16))) = static_cast(value); break; + case triton::arch::ID_REG_RV64_F17: (*((triton::uint64*)(this->f17))) = static_cast(value); break; + case triton::arch::ID_REG_RV64_F18: (*((triton::uint64*)(this->f18))) = static_cast(value); break; + case triton::arch::ID_REG_RV64_F19: (*((triton::uint64*)(this->f19))) = static_cast(value); break; + case triton::arch::ID_REG_RV64_F20: (*((triton::uint64*)(this->f20))) = static_cast(value); break; + case triton::arch::ID_REG_RV64_F21: (*((triton::uint64*)(this->f21))) = static_cast(value); break; + case triton::arch::ID_REG_RV64_F22: (*((triton::uint64*)(this->f22))) = static_cast(value); break; + case triton::arch::ID_REG_RV64_F23: (*((triton::uint64*)(this->f23))) = static_cast(value); break; + case triton::arch::ID_REG_RV64_F24: (*((triton::uint64*)(this->f24))) = static_cast(value); break; + case triton::arch::ID_REG_RV64_F25: (*((triton::uint64*)(this->f25))) = static_cast(value); break; + case triton::arch::ID_REG_RV64_F26: (*((triton::uint64*)(this->f26))) = static_cast(value); break; + case triton::arch::ID_REG_RV64_F27: (*((triton::uint64*)(this->f27))) = static_cast(value); break; + case triton::arch::ID_REG_RV64_F28: (*((triton::uint64*)(this->f28))) = static_cast(value); break; + case triton::arch::ID_REG_RV64_F29: (*((triton::uint64*)(this->f29))) = static_cast(value); break; + case triton::arch::ID_REG_RV64_F30: (*((triton::uint64*)(this->f30))) = static_cast(value); break; + case triton::arch::ID_REG_RV64_F31: (*((triton::uint64*)(this->f31))) = static_cast(value); break; + + default: + throw triton::exceptions::Cpu("riscv64Cpu:setConcreteRegisterValue(): Invalid register."); + + } + } + + + bool riscv64Cpu::isThumb(void) const { + /* There is no thumb mode in RV */ + return false; + } + + + void riscv64Cpu::setThumb(bool state) { + /* There is no thumb mode in RV */ + } + + + bool riscv64Cpu::isMemoryExclusive(const triton::arch::MemoryAccess& mem) const { + /* There is no exclusive memory access support in RV */ + return false; + } + + + void riscv64Cpu::setMemoryExclusiveTag(const triton::arch::MemoryAccess& mem, bool tag) { + /* There is no exclusive memory access support in RV */ + } + + + bool riscv64Cpu::isConcreteMemoryValueDefined(const triton::arch::MemoryAccess& mem) const { + return this->isConcreteMemoryValueDefined(mem.getAddress(), mem.getSize()); + } + + + bool riscv64Cpu::isConcreteMemoryValueDefined(triton::uint64 baseAddr, triton::usize size) const { + for (triton::usize index = 0; index < size; index++) { + if (this->memory.find(baseAddr + index) == this->memory.end()) { + return false; + } + } + return true; + } + + + void riscv64Cpu::clearConcreteMemoryValue(const triton::arch::MemoryAccess& mem) { + this->clearConcreteMemoryValue(mem.getAddress(), mem.getSize()); + } + + + void riscv64Cpu::clearConcreteMemoryValue(triton::uint64 baseAddr, triton::usize size) { + for (triton::usize index = 0; index < size; index++) { + if (this->memory.find(baseAddr + index) != this->memory.end()) { + this->memory.erase(baseAddr + index); + } + } + } + + }; /* riscv namespace */ + }; /* arch namespace */ +}; /* triton namespace */ diff --git a/src/libtriton/arch/riscv/riscvSemantics.cpp b/src/libtriton/arch/riscv/riscvSemantics.cpp new file mode 100644 index 000000000..cfad0e58b --- /dev/null +++ b/src/libtriton/arch/riscv/riscvSemantics.cpp @@ -0,0 +1,2692 @@ +//! \file +/* +** Copyright (C) - Triton +** +** This program is under the terms of the Apache License 2.0. +*/ + +#include +#include +#include +#include +#include + + + +/*! \page SMT_Semantics_Supported_page SMT Semantics Supported + \brief [**internal**] All information about the supported semantics. + +- \ref SMT_aarch64_Semantics_Supported_page +- \ref SMT_arm32_Semantics_Supported_page +- \ref SMT_riscv_Semantics_Supported_page +- \ref SMT_x86_Semantics_Supported_page + +*/ + + +/*! \page SMT_riscv_Semantics_Supported_page RV32 and RV64 SMT semantics supported + \brief [**internal**] List of the supported semantics for the RV32 and RV64 architectures. + + +Mnemonic | Description +------------------------------|------------ +ADD | Add (register) +ADDI (pseudo: MV, NOP) | Add (immediate) +ADDIW (pseudo: SEXT.W) | Add word (immediate) / 64-bit only / +ADDW | Add word (register) / 64-bit only / +AND | And (register) +ANDI | And (immediate) +AUIPC | Add upper intermediate to pc +BEQ (pseudo: BEQZ) | Branch if equal +BGE (pseudo: BLEZ, BGEZ) | Branch if greater or equal +BGEU | Branch if greater or equal (unsigned) +BLT (pseudo: BLTZ, BGTZ) | Branch if less +BLTU | Branch if less (unsigned) +BNE (pseudo: BNEZ) | Branch if not equal +DIV | Signed integer division +DIVU | Unsigned integer division +DIVUW | Word unsigned integer division / 64-bit only / +DIVW | Word signed integer division / 64-bit only / +JAL (pseudo: J) | Jump and link +JALR (pseudo: JR, RET) | Jump and link register +LB | Load register signed byte +LBU | Load register unsigned byte +LD | Load register double word / 64-bit only / +LH | Load register signed halfword +LHU | Load register unsigned halfword +LUI | Load upper intermediate +LW | Load register signed word +LWU | Load register unsigned word / 64-bit only / +MUL | Signed multiply +MULH | Signed multiply high +MULHSU | Signed-unsigned multiply high +MULHU | Unsigned multiply high +MULW | Word multiply / 64-bit only / +OR | Or (register) +ORI | Or (immediate) +REM | Signed integer reminder +REMU | Unsigned integer reminder +REMUW | Word unsigned integer reminder / 64-bit only / +REMW | Word signed integer reminder / 64-bit only / +SB | Store register byte +SD | Store register double word / 64-bit only / +SH | Store register halfword +SLL | Logical left shift (register) +SLLI | Logical left shift (immediate) +SLLIW | Word logical left shift (immediate) / 64-bit only / +SLLW | Word logical left shift (register) +SLT (pseudo: SLTZ, SGTZ) | Set if less than register +SLTI | Set if less than immediate +SLTIU (pseudo: SEQZ) | Set if less than immediate (unsigned) +SLTU (pseudo: SNEZ) | Set if less than register (unsigned) +SRA | Arithmetic right shift (register) +SRAI | Arithmetic right shift (immediate) +SRAIW | Word arithmetic right shift (register) / 64-bit only / +SRAW | Word arithmetic right shift (immediate) / 64-bit only / +SRL | Logical right shift (register) +SRLI | Logical right shift (immediate) +SRLIW | Word logical right shift (register) / 64-bit only / +SRLW | Word logical right shift (immediate) / 64-bit only / +SUB (pseudo: NEG) | Subtract +SUBW (pseudo: NEGW) | Subtract word / 64-bit only / +SW | Store register word +XOR | Exclusive or (register) +XORI (pseudo: NOT) | Exclusive or (immediate) +------------------------------|------------ + Compressed instructions +------------------------------|------------ +C.ADD | Add (register) +C.ADDI | Add (immediate) +C.ADDI16SP | Add to SP (immediate, multiplied by 16) +C.ADDI4SPN | Add to SP (immediate, multiplied by 4) +C.ADDIW | Add word (immediate) / 64-bit only / +C.ADDW | Add word (register) / 64-bit only / +C.AND | And (register) +C.ANDI | And (immediate) +C.BEQZ | Branch if equal to zero +C.BNEZ | Branch if not equal to zero +C.J | Jump +C.JAL | Jump and link / 32-bit only / +C.JALR | Jump and link register +C.JR | Jump register +C.LD | Load register double word / 64-bit only / +C.LDSP | Load register double word from SP / 64-bit only / +C.LI | Load immediate +C.LUI | Load upper intermediate +C.LW | Load register signed word +C.LWSP | Load register word from SP / 64-bit only / +C.MV | Move register +C.NOP | No operation +C.OR | Or (register) +C.SD | Store register double word / 64-bit only / +C.SDSP | Store register double word to SP / 64-bit only / +C.SLLI | Logical left shift (immediate) +C.SRAI | Arithmetic right shift (immediate) +C.SRLI | Logical right shift (immediate) +C.SUB | Subtract +C.SUBW | Subtract word / 64-bit only / +C.SW | Store register word +C.SWSP | Store register word to SP +C.XOR | Exclusive or (register) + +*/ + + +namespace triton { + namespace arch { + namespace riscv { + + riscvSemantics::riscvSemantics(triton::arch::Architecture* architecture, + triton::engines::symbolic::SymbolicEngine* symbolicEngine, + triton::engines::taint::TaintEngine* taintEngine, + const triton::modes::SharedModes& modes, + const triton::ast::SharedAstContext& astCtxt) : modes(modes), astCtxt(astCtxt) { + + this->architecture = architecture; + this->exception = triton::arch::NO_FAULT; + this->symbolicEngine = symbolicEngine; + this->taintEngine = taintEngine; + + if (architecture == nullptr) + throw triton::exceptions::Semantics("riscvSemantics::riscvSemantics(): The architecture API must be defined."); + + if (this->symbolicEngine == nullptr) + throw triton::exceptions::Semantics("riscvSemantics::riscvSemantics(): The symbolic engine API must be defined."); + + if (this->taintEngine == nullptr) + throw triton::exceptions::Semantics("riscvSemantics::riscvSemantics(): The taint engines API must be defined."); + } + + + triton::arch::exception_e riscvSemantics::buildSemantics(triton::arch::Instruction& inst) { + this->exception = triton::arch::NO_FAULT; + switch (inst.getType()) { + case ID_INS_ADD: this->add_s(inst); break; + case ID_INS_ADDI: this->addi_s(inst); break; + case ID_INS_ADDIW: this->addiw_s(inst); break; + case ID_INS_ADDW: this->addw_s(inst); break; + case ID_INS_AND: this->and_s(inst); break; + case ID_INS_ANDI: this->and_s(inst); break; + case ID_INS_AUIPC: this->auipc_s(inst); break; + case ID_INS_BEQ: this->beq_s(inst); break; + case ID_INS_BGE: this->bge_s(inst); break; + case ID_INS_BGEU: this->bgeu_s(inst); break; + case ID_INS_BLT: this->blt_s(inst); break; + case ID_INS_BLTU: this->bltu_s(inst); break; + case ID_INS_BNE: this->bne_s(inst); break; + /* Compressed instructions */ + case ID_INS_C_ADD: this->c_add_s(inst); break; + case ID_INS_C_ADDI: this->c_add_s(inst); break; + case ID_INS_C_ADDI16SP: this->c_addi16sp_s(inst); break; + case ID_INS_C_ADDI4SPN: this->c_addi4spn_s(inst); break; + case ID_INS_C_ADDIW: this->c_addw_s(inst); break; + case ID_INS_C_ADDW: this->c_addw_s(inst); break; + case ID_INS_C_AND: this->c_and_s(inst); break; + case ID_INS_C_ANDI: this->c_and_s(inst); break; + case ID_INS_C_BEQZ: this->c_beqz_s(inst); break; + case ID_INS_C_BNEZ: this->c_bnez_s(inst); break; + case ID_INS_C_J: this->jal_j_s(inst); break; + case ID_INS_C_JAL: this->c_jal_s(inst); break; + case ID_INS_C_JALR: this->c_jalr_s(inst); break; + case ID_INS_C_JR: this->jalr_no_link_s(inst); break; + case ID_INS_C_LD: this->c_ld_s(inst); break; + case ID_INS_C_LDSP: this->c_ldsp_s(inst); break; + case ID_INS_C_LI: this->c_li_s(inst); break; + case ID_INS_C_LW: this->c_lw_s(inst); break; + case ID_INS_C_LWSP: this->c_lwsp_s(inst); break; + case ID_INS_C_LUI: this->lui_s(inst); break; + case ID_INS_C_MV: this->c_mv_s(inst); break; + case ID_INS_C_NOP: this->c_nop_s(inst); break; + case ID_INS_C_OR: this->c_or_s(inst); break; + case ID_INS_C_SD: this->c_sd_s(inst); break; + case ID_INS_C_SDSP: this->c_sdsp_s(inst); break; + case ID_INS_C_SLLI: this->c_slli_s(inst); break; + case ID_INS_C_SRAI: this->c_srai_s(inst); break; + case ID_INS_C_SRLI: this->c_srli_s(inst); break; + case ID_INS_C_SUB: this->c_sub_s(inst); break; + case ID_INS_C_SUBW: this->c_subw_s(inst); break; + case ID_INS_C_SW: this->c_sw_s(inst); break; + case ID_INS_C_SWSP: this->c_swsp_s(inst); break; + case ID_INS_C_XOR: this->c_xor_s(inst); break; + /* End of compressed instructions */ + case ID_INS_DIV: this->div_s(inst); break; + case ID_INS_DIVU: this->divu_s(inst); break; + case ID_INS_DIVUW: this->divuw_s(inst); break; + case ID_INS_DIVW: this->divw_s(inst); break; + case ID_INS_JAL: this->jal_s(inst); break; + case ID_INS_JALR: this->jalr_s(inst); break; + case ID_INS_LB: this->lb_s(inst); break; + case ID_INS_LBU: this->lbu_s(inst); break; + case ID_INS_LD: this->ld_s(inst); break; + case ID_INS_LH: this->lh_s(inst); break; + case ID_INS_LHU: this->lhu_s(inst); break; + case ID_INS_LUI: this->lui_s(inst); break; + case ID_INS_LW: this->lw_s(inst); break; + case ID_INS_LWU: this->lwu_s(inst); break; + case ID_INS_MUL: this->mul_s(inst); break; + case ID_INS_MULH: this->mulh_s(inst); break; + case ID_INS_MULHSU: this->mulhsu_s(inst); break; + case ID_INS_MULHU: this->mulhu_s(inst); break; + case ID_INS_MULW: this->mulw_s(inst); break; + case ID_INS_OR: this->or_s(inst); break; + case ID_INS_ORI: this->or_s(inst); break; + case ID_INS_REM: this->rem_s(inst); break; + case ID_INS_REMU: this->remu_s(inst); break; + case ID_INS_REMUW: this->remuw_s(inst); break; + case ID_INS_REMW: this->remw_s(inst); break; + case ID_INS_SB: this->sb_s(inst); break; + case ID_INS_SD: this->sd_s(inst); break; + case ID_INS_SH: this->sh_s(inst); break; + case ID_INS_SLL: this->sll_s(inst); break; + case ID_INS_SLLI: this->sll_s(inst); break; + case ID_INS_SLLIW: this->sllw_s(inst); break; + case ID_INS_SLLW: this->sllw_s(inst); break; + case ID_INS_SLT: this->slt_s(inst); break; + case ID_INS_SLTI: this->slt_s(inst); break; + case ID_INS_SLTIU: this->sltu_s(inst); break; + case ID_INS_SLTU: this->sltu_s(inst); break; + case ID_INS_SRA: this->sra_s(inst); break; + case ID_INS_SRAI: this->sra_s(inst); break; + case ID_INS_SRAIW: this->sraw_s(inst); break; + case ID_INS_SRAW: this->sraw_s(inst); break; + case ID_INS_SRL: this->srl_s(inst); break; + case ID_INS_SRLI: this->srl_s(inst); break; + case ID_INS_SRLIW: this->srlw_s(inst); break; + case ID_INS_SRLW: this->srlw_s(inst); break; + case ID_INS_SUB: this->sub_s(inst); break; + case ID_INS_SUBW: this->subw_s(inst); break; + case ID_INS_SW: this->sw_s(inst); break; + case ID_INS_XOR: this->xor_s(inst); break; + case ID_INS_XORI: this->xori_s(inst); break; + + default: + this->exception = triton::arch::FAULT_UD; + break; + } + return this->exception; + } + + + void riscvSemantics::controlFlow_s(triton::arch::Instruction& inst) { + auto pc = this->architecture->getProgramCounter(); + auto pc_op = triton::arch::OperandWrapper(pc); + + /* Create the semantics */ + auto node = this->astCtxt->bv(inst.getNextAddress(), pc_op.getBitSize()); + + /* Create symbolic expression */ + auto expr = this->symbolicEngine->createSymbolicRegisterExpression(inst, node, pc, "Program Counter"); + + /* Spread taint */ + expr->isTainted = this->taintEngine->setTaintRegister(pc, triton::engines::taint::UNTAINTED); + } + + + void riscvSemantics::add_s(triton::arch::Instruction& inst) { + auto& dst = inst.operands[0]; + auto& src1 = inst.operands[1]; + auto& src2 = inst.operands[2]; + + /* Create symbolic operands */ + auto op1 = this->symbolicEngine->getOperandAst(inst, src1); + auto op2 = this->symbolicEngine->getOperandAst(inst, src2); + + /* Create the semantics */ + auto node = this->astCtxt->bvadd(op1, op2); + + /* Create symbolic expression */ + auto expr = this->symbolicEngine->createSymbolicExpression(inst, node, dst, "ADD(I) operation"); + + /* Spread taint */ + expr->isTainted = this->taintEngine->taintUnion(src1, src2); + + /* Update the symbolic control flow */ + this->controlFlow_s(inst); + } + + + void riscvSemantics::addi_s(triton::arch::Instruction& inst) { + /* Check for possible pseudo instructions + mv rd, rs -- [addi rd, rs, 0] -- Copy register + nop -- [addi x0, x0, 0] -- No operation + */ + switch (inst.operands.size()) { + case 0: this->controlFlow_s(inst); return; // nop + case 2: addi_mv_s(inst); return; // mv + default: add_s(inst); return; // addi + } + } + + + void riscvSemantics::addi_mv_s(triton::arch::Instruction& inst) { + auto& dst = inst.operands[0]; + auto& src = inst.operands[1]; + + /* Create the semantics */ + auto node = this->symbolicEngine->getOperandAst(inst, src); + + /* Create symbolic expression */ + auto expr = this->symbolicEngine->createSymbolicExpression(inst, node, dst, "MV operation"); + + /* Spread taint */ + expr->isTainted = this->taintEngine->taintAssignment(dst, src); + + /* Update the symbolic control flow */ + this->controlFlow_s(inst); + } + + + void riscvSemantics::addiw_s(triton::arch::Instruction& inst) { /* 64-bit only */ + auto& dst = inst.operands[0]; + auto& src1 = inst.operands[1]; + auto size = dst.getBitSize(); + + /* Create symbolic operands */ + auto op1 = this->symbolicEngine->getOperandAst(inst, src1); + auto node = this->astCtxt->sx(32, this->astCtxt->extract(31, 0, op1)); // sext.w pseudo instruction semantics + if (inst.operands.size() > 2) { + auto& src2 = inst.operands[2]; + auto op2 = this->symbolicEngine->getOperandAst(inst, src2); + node = this->astCtxt->sx(32, this->astCtxt->extract(31, 0, this->astCtxt->bvadd(op1, op2))); + } + + /* Create symbolic expression */ + auto expr = this->symbolicEngine->createSymbolicExpression(inst, node, dst, "ADDIW operation"); + + /* Spread taint */ + expr->isTainted = this->taintEngine->setTaint(dst, this->taintEngine->isTainted(src1)); + + /* Update the symbolic control flow */ + this->controlFlow_s(inst); + } + + + void riscvSemantics::addw_s(triton::arch::Instruction& inst) { /* 64-bit only */ + auto& dst = inst.operands[0]; + auto& src1 = inst.operands[1]; + auto& src2 = inst.operands[2]; + + /* Create symbolic operands */ + auto op1 = this->symbolicEngine->getOperandAst(inst, src1); + auto op2 = this->symbolicEngine->getOperandAst(inst, src2); + + /* Create the semantics */ + auto node = this->astCtxt->sx(32, this->astCtxt->bvadd( + this->astCtxt->extract(31, 0, op1), + this->astCtxt->extract(31, 0, op2) + )); + + /* Create symbolic expression */ + auto expr = this->symbolicEngine->createSymbolicExpression(inst, node, dst, "ADDW operation"); + + /* Spread taint */ + expr->isTainted = this->taintEngine->taintUnion(src1, src2); + + /* Update the symbolic control flow */ + this->controlFlow_s(inst); + } + + + void riscvSemantics::and_s(triton::arch::Instruction& inst) { + auto& dst = inst.operands[0]; + auto& src1 = inst.operands[1]; + auto& src2 = inst.operands[2]; + + /* Create symbolic operands */ + auto op1 = this->symbolicEngine->getOperandAst(inst, src1); + auto op2 = this->symbolicEngine->getOperandAst(inst, src2); + + /* Create the semantics */ + auto node = this->astCtxt->bvand(op1, op2); + + /* Create symbolic expression */ + auto expr = this->symbolicEngine->createSymbolicExpression(inst, node, dst, "AND(I) operation"); + + /* Spread taint */ + expr->isTainted = this->taintEngine->setTaint(dst, this->taintEngine->isTainted(src1) | this->taintEngine->isTainted(src2)); + + /* Update the symbolic control flow */ + this->controlFlow_s(inst); + } + + + void riscvSemantics::auipc_s(triton::arch::Instruction& inst) { + // dst := pc + sx_64(src_imm(_20) << 12) + auto& dst = inst.operands[0]; + auto& src = inst.operands[1]; + auto pc = triton::arch::OperandWrapper(this->architecture->getProgramCounter()); + + /* Create symbolic operands */ + auto imm = this->symbolicEngine->getOperandAst(inst, src); + auto pc_ast = this->symbolicEngine->getOperandAst(pc); + + /* Create the semantics */ + auto node = this->astCtxt->concat(this->astCtxt->extract(19, 0, imm), this->astCtxt->bv(0, 12)); + if (dst.getBitSize() == 64) { + node = this->astCtxt->sx(32, node); + } + node = this->astCtxt->bvadd(node, pc_ast); + + /* Create symbolic expression */ + auto expr = this->symbolicEngine->createSymbolicExpression(inst, node, dst, "AUIPC operation"); + + /* Spread taint */ + expr->isTainted = this->taintEngine->isTainted(pc); + + /* Update the symbolic control flow */ + this->controlFlow_s(inst); + } + + + void riscvSemantics::beq_s(triton::arch::Instruction& inst) { + /* Check for possible pseudo instructions + beqz rs, offset -- [beq rs, x0, offset] -- Branch if == zero + */ + auto pc = triton::arch::OperandWrapper(this->architecture->getProgramCounter()); + auto& src1 = inst.operands[0]; + auto& src2 = inst.operands[1]; + auto size = src1.getBitSize(); + + /* Create symbolic operands */ + auto pc_ast = this->symbolicEngine->getOperandAst(pc); + auto op1 = this->symbolicEngine->getOperandAst(inst, src1); + auto op2 = this->astCtxt->bv(0, size); + auto op3 = this->symbolicEngine->getOperandAst(inst, src2); + + if (inst.operands.size() == 3) { + auto& imm = inst.operands[2]; + op2 = op3; + op3 = this->symbolicEngine->getOperandAst(inst, imm); + } + + /* Create the semantics */ + auto node = this->astCtxt->ite(this->astCtxt->equal(op1, op2), + this->astCtxt->bvadd(pc_ast, op3), + this->astCtxt->bv(inst.getNextAddress(), pc.getBitSize()) + ); + + /* Create symbolic expression */ + auto expr = this->symbolicEngine->createSymbolicExpression(inst, node, pc, "Program Counter"); + + /* Set condition flag */ + if (op1->evaluate() == op2->evaluate()) + inst.setConditionTaken(true); + + /* Spread taint */ + expr->isTainted = this->taintEngine->taintUnion(pc, src1); + expr->isTainted = this->taintEngine->taintUnion(pc, src2); + + /* Create the path constraint */ + this->symbolicEngine->pushPathConstraint(inst, expr); + } + + + void riscvSemantics::bge_s(triton::arch::Instruction& inst) { + /* Check for possible pseudo instructions (no ble in capstone) + blez rs, offset -- [bge x0, rs, offset] -- Branch if <= zero + bgez rs, offset -- [bge rs, x0, offset] -- Branch if >= zero + */ + auto pc = triton::arch::OperandWrapper(this->architecture->getProgramCounter()); + auto& src1 = inst.operands[0]; + auto& src2 = inst.operands[1]; + auto size = src1.getBitSize(); + + /* Create symbolic operands */ + auto pc_ast = this->symbolicEngine->getOperandAst(pc); + auto op1 = this->symbolicEngine->getOperandAst(inst, src1); + auto op2 = this->astCtxt->bv(0, size); + auto op3 = this->symbolicEngine->getOperandAst(inst, src2); + + /* Create branch condition AST */ + bool taken = false; + auto node = this->astCtxt->bvsge(op1, op2); // bgez + if (inst.operands.size() < 3) { + auto mnem = inst.getDisassembly(); + if (mnem[1] == 'l') { // blez + node = this->astCtxt->bvsle(op1, op2); + taken = (long long)(op1->evaluate()) <= 0; + } + else { + taken = (long long)(op1->evaluate()) >= 0; + } + } + else { // bge + auto& imm = inst.operands[2]; + op2 = op3; + op3 = this->symbolicEngine->getOperandAst(inst, imm); + node = this->astCtxt->bvsge(op1, op2); + taken = (long long)(op1->evaluate() - op2->evaluate()) >= 0; + } + + /* Create the semantics */ + node = this->astCtxt->ite(node, + this->astCtxt->bvadd(pc_ast, op3), + this->astCtxt->bv(inst.getNextAddress(), pc.getBitSize()) + ); + + /* Create symbolic expression */ + auto expr = this->symbolicEngine->createSymbolicExpression(inst, node, pc, "Program Counter"); + + /* Set condition flag */ + inst.setConditionTaken(taken); + + /* Spread taint */ + expr->isTainted = this->taintEngine->taintUnion(pc, src1); + expr->isTainted = this->taintEngine->taintUnion(pc, src2); + + /* Create the path constraint */ + this->symbolicEngine->pushPathConstraint(inst, expr); + } + + + void riscvSemantics::bgeu_s(triton::arch::Instruction& inst) { + auto pc = triton::arch::OperandWrapper(this->architecture->getProgramCounter()); + auto& src1 = inst.operands[0]; + auto& src2 = inst.operands[1]; + auto& imm = inst.operands[2]; + + /* Create symbolic operands */ + auto op1 = this->symbolicEngine->getOperandAst(inst, src1); + auto op2 = this->symbolicEngine->getOperandAst(inst, src2); + auto op3 = this->symbolicEngine->getOperandAst(inst, imm); + auto pc_ast = this->symbolicEngine->getOperandAst(pc); + + /* Create the semantics */ + auto node = this->astCtxt->ite(this->astCtxt->bvuge(op1, op2), + this->astCtxt->bvadd(pc_ast, op3), + this->astCtxt->bv(inst.getNextAddress(), pc.getBitSize()) + ); + + /* Create symbolic expression */ + auto expr = this->symbolicEngine->createSymbolicExpression(inst, node, pc, "Program Counter"); + + /* Set condition flag */ + if (op1->evaluate() >= op2->evaluate()) + inst.setConditionTaken(true); + + /* Spread taint */ + expr->isTainted = this->taintEngine->taintUnion(pc, src1); + expr->isTainted = this->taintEngine->taintUnion(pc, src2); + + /* Create the path constraint */ + this->symbolicEngine->pushPathConstraint(inst, expr); + } + + + void riscvSemantics::blt_s(triton::arch::Instruction& inst) { + /* Check for possible pseudo instructions (no bgt in capstone) + bltz rs, offset -- [blt rs, x0, offset] -- Branch if < zero + bgtz rs, offset -- [blt x0, rs, offset] -- Branch if > zero + */ + auto pc = triton::arch::OperandWrapper(this->architecture->getProgramCounter()); + auto& src1 = inst.operands[0]; + auto& src2 = inst.operands[1]; + auto size = src1.getBitSize(); + + /* Create symbolic operands */ + auto pc_ast = this->symbolicEngine->getOperandAst(pc); + auto op1 = this->symbolicEngine->getOperandAst(inst, src1); + auto op2 = this->astCtxt->bv(0, size); + auto op3 = this->symbolicEngine->getOperandAst(inst, src2); + + /* Create branch condition AST */ + bool taken = false; + auto node = this->astCtxt->bvslt(op1, op2); // bltz + if (inst.operands.size() < 3) { + auto mnem = inst.getDisassembly(); + if (mnem[1] == 'g') { // bgtz + node = this->astCtxt->bvsgt(op1, op2); + taken = (long long)(op1->evaluate()) > 0; + } + else { + taken = (long long)(op1->evaluate()) < 0; + } + } + else { // blt + auto& imm = inst.operands[2]; + op2 = op3; + op3 = this->symbolicEngine->getOperandAst(inst, imm); + node = this->astCtxt->bvslt(op1, op2); + taken = (long long)(op1->evaluate() - op2->evaluate()) < 0; + } + + /* Create the semantics */ + node = this->astCtxt->ite(node, + this->astCtxt->bvadd(pc_ast, op3), + this->astCtxt->bv(inst.getNextAddress(), pc.getBitSize()) + ); + + /* Create symbolic expression */ + auto expr = this->symbolicEngine->createSymbolicExpression(inst, node, pc, "Program Counter"); + + /* Set condition flag */ + inst.setConditionTaken(taken); + + /* Spread taint */ + + expr->isTainted = this->taintEngine->taintUnion(pc, src1); + expr->isTainted = this->taintEngine->taintUnion(pc, src2); + + /* Create the path constraint */ + this->symbolicEngine->pushPathConstraint(inst, expr); + } + + + void riscvSemantics::bltu_s(triton::arch::Instruction& inst) { + auto pc = triton::arch::OperandWrapper(this->architecture->getProgramCounter()); + auto& src1 = inst.operands[0]; + auto& src2 = inst.operands[1]; + auto& imm = inst.operands[2]; + + /* Create symbolic operands */ + auto op1 = this->symbolicEngine->getOperandAst(inst, src1); + auto op2 = this->symbolicEngine->getOperandAst(inst, src2); + auto op3 = this->symbolicEngine->getOperandAst(inst, imm); + auto pc_ast = this->symbolicEngine->getOperandAst(pc); + + /* Create the semantics */ + auto node = this->astCtxt->ite(this->astCtxt->bvult(op1, op2), + this->astCtxt->bvadd(pc_ast, op3), + this->astCtxt->bv(inst.getNextAddress(), pc.getBitSize()) + ); + + /* Create symbolic expression */ + auto expr = this->symbolicEngine->createSymbolicExpression(inst, node, pc, "Program Counter"); + + /* Set condition flag */ + if (op2->evaluate() > op1->evaluate()) + inst.setConditionTaken(true); + + /* Spread taint */ + expr->isTainted = this->taintEngine->taintUnion(pc, src1); + expr->isTainted = this->taintEngine->taintUnion(pc, src2); + + /* Create the path constraint */ + this->symbolicEngine->pushPathConstraint(inst, expr); + } + + + void riscvSemantics::bne_s(triton::arch::Instruction& inst) { + /* Check for possible pseudo instructions + bnez rs, offset -- [blt rs, x0, offset] -- Branch if != zero + */ + auto pc = triton::arch::OperandWrapper(this->architecture->getProgramCounter()); + auto& src1 = inst.operands[0]; + auto& src2 = inst.operands[1]; + auto size = src1.getBitSize(); + + /* Create symbolic operands */ + auto pc_ast = this->symbolicEngine->getOperandAst(pc); + auto op1 = this->symbolicEngine->getOperandAst(inst, src1); + auto op2 = this->astCtxt->bv(0, size); + auto op3 = this->symbolicEngine->getOperandAst(inst, src2); + + if (inst.operands.size() == 3) { + auto& imm = inst.operands[2]; + op2 = op3; + op3 = this->symbolicEngine->getOperandAst(inst, imm); + } + + /* Create the semantics */ + auto node = this->astCtxt->ite(this->astCtxt->equal(op1, op2), + this->astCtxt->bv(inst.getNextAddress(), pc.getBitSize()), + this->astCtxt->bvadd(pc_ast, op3) + ); + + /* Create symbolic expression */ + auto expr = this->symbolicEngine->createSymbolicExpression(inst, node, pc, "Program Counter"); + + /* Set condition flag */ + if (op1->evaluate() - op2->evaluate()) + inst.setConditionTaken(true); + + /* Spread taint */ + expr->isTainted = this->taintEngine->taintUnion(pc, src1); + expr->isTainted = this->taintEngine->taintUnion(pc, src2); + + /* Create the path constraint */ + this->symbolicEngine->pushPathConstraint(inst, expr); + } + + + // Compressed instructions: + void riscvSemantics::c_add_s(triton::arch::Instruction& inst) { + auto& dst = inst.operands[0]; + auto& src = inst.operands[1]; + + /* Create symbolic operands */ + auto op1 = this->symbolicEngine->getOperandAst(inst, dst); + auto op2 = this->symbolicEngine->getOperandAst(inst, src); + + /* Create the semantics */ + auto node = this->astCtxt->bvadd(op1, op2); + + /* Create symbolic expression */ + auto expr = this->symbolicEngine->createSymbolicExpression(inst, node, dst, "C.ADD(I) operation"); + + /* Spread taint */ + expr->isTainted = this->taintEngine->taintUnion(dst, src); + + /* Update the symbolic control flow */ + this->controlFlow_s(inst); + } + + + void riscvSemantics::c_addi16sp_s(triton::arch::Instruction& inst) { + auto& sp = inst.operands[0]; + auto& imm = inst.operands[1]; + + /* Create symbolic operands */ + auto op1 = this->symbolicEngine->getOperandAst(inst, sp); + auto op2 = this->symbolicEngine->getOperandAst(inst, imm); + + /* Create the semantics */ + auto node = this->astCtxt->bvadd(op1, op2); + + /* Create symbolic expression */ + auto expr = this->symbolicEngine->createSymbolicExpression(inst, node, sp, "C.ADDI16SP operation"); + + /* Spread taint */ + expr->isTainted = this->taintEngine->isTainted(sp); + + /* Update the symbolic control flow */ + this->controlFlow_s(inst); + } + + + void riscvSemantics::c_addi4spn_s(triton::arch::Instruction& inst) { + auto& dst = inst.operands[0]; + auto& src = inst.operands[1]; + auto& imm = inst.operands[2]; + + /* Create symbolic operands */ + auto op1 = this->symbolicEngine->getOperandAst(inst, src); + auto op2 = this->symbolicEngine->getOperandAst(inst, imm); + + /* Create the semantics */ + auto node = this->astCtxt->bvadd(op1, op2); + + /* Create symbolic expression */ + auto expr = this->symbolicEngine->createSymbolicExpression(inst, node, dst, "C.ADDI4SPN operation"); + + /* Spread taint */ + expr->isTainted = this->taintEngine->setTaint(dst, this->taintEngine->isTainted(src)); + + /* Update the symbolic control flow */ + this->controlFlow_s(inst); + } + + + void riscvSemantics::c_addw_s(triton::arch::Instruction& inst) { /* 64-bit only */ + auto& dst = inst.operands[0]; + auto& src = inst.operands[1]; + + /* Create symbolic operands */ + auto op1 = this->symbolicEngine->getOperandAst(inst, dst); + auto op2 = this->symbolicEngine->getOperandAst(inst, src); + + /* Create the semantics */ + auto node = this->astCtxt->sx(32, this->astCtxt->bvadd( + this->astCtxt->extract(31, 0, op1), + this->astCtxt->extract(31, 0, op2) + )); + + /* Create symbolic expression */ + auto expr = this->symbolicEngine->createSymbolicExpression(inst, node, dst, "C.ADD(I)W operation"); + + /* Spread taint */ + expr->isTainted = this->taintEngine->taintUnion(dst, src); + + /* Update the symbolic control flow */ + this->controlFlow_s(inst); + } + + + void riscvSemantics::c_and_s(triton::arch::Instruction& inst) { + auto& dst = inst.operands[0]; + auto& src = inst.operands[1]; + + /* Create symbolic operands */ + auto op1 = this->symbolicEngine->getOperandAst(inst, dst); + auto op2 = this->symbolicEngine->getOperandAst(inst, src); + + /* Create the semantics */ + auto node = this->astCtxt->bvand(op1, op2); + + /* Create symbolic expression */ + auto expr = this->symbolicEngine->createSymbolicExpression(inst, node, dst, "C.AND(I) operation"); + + /* Spread taint */ + expr->isTainted = this->taintEngine->taintUnion(dst, src); + + /* Update the symbolic control flow */ + this->controlFlow_s(inst); + } + + + void riscvSemantics::c_beqz_s(triton::arch::Instruction& inst) { + auto pc = triton::arch::OperandWrapper(this->architecture->getProgramCounter()); + auto& src1 = inst.operands[0]; + auto& src2 = inst.operands[1]; + auto size = src1.getBitSize(); + + /* Create symbolic operands */ + auto pc_ast = this->symbolicEngine->getOperandAst(pc); + auto op1 = this->symbolicEngine->getOperandAst(inst, src1); + auto op2 = this->astCtxt->bv(0, size); + auto op3 = this->symbolicEngine->getOperandAst(inst, src2); + + /* Create the semantics */ + auto node = this->astCtxt->ite(this->astCtxt->equal(op1, op2), + this->astCtxt->bvadd(pc_ast, op3), + this->astCtxt->bv(inst.getNextAddress(), pc.getBitSize()) + ); + + /* Create symbolic expression */ + auto expr = this->symbolicEngine->createSymbolicExpression(inst, node, pc, "Program Counter"); + + /* Set condition flag */ + if (op1->evaluate() == 0) + inst.setConditionTaken(true); + + /* Spread taint */ + expr->isTainted = this->taintEngine->taintUnion(pc, src1); + + /* Create the path constraint */ + this->symbolicEngine->pushPathConstraint(inst, expr); + } + + + void riscvSemantics::c_bnez_s(triton::arch::Instruction& inst) { + auto pc = triton::arch::OperandWrapper(this->architecture->getProgramCounter()); + auto& src1 = inst.operands[0]; + auto& src2 = inst.operands[1]; + auto size = src1.getBitSize(); + + /* Create symbolic operands */ + auto pc_ast = this->symbolicEngine->getOperandAst(pc); + auto op1 = this->symbolicEngine->getOperandAst(inst, src1); + auto op2 = this->astCtxt->bv(0, size); + auto op3 = this->symbolicEngine->getOperandAst(inst, src2); + + /* Create the semantics */ + auto node = this->astCtxt->ite(this->astCtxt->equal(op1, op2), + this->astCtxt->bv(inst.getNextAddress(), pc.getBitSize()), + this->astCtxt->bvadd(pc_ast, op3) + ); + + /* Create symbolic expression */ + auto expr = this->symbolicEngine->createSymbolicExpression(inst, node, pc, "Program Counter"); + + /* Set condition flag */ + if (op1->evaluate() != 0) + inst.setConditionTaken(true); + + /* Spread taint */ + expr->isTainted = this->taintEngine->taintUnion(pc, src1); + + /* Create the path constraint */ + this->symbolicEngine->pushPathConstraint(inst, expr); + } + + + void riscvSemantics::c_jal_s(triton::arch::Instruction& inst) { /* 32-bit only */ + /* x1 := pc + 2; pc := pc + offset + Compressed instruction expands to: + jal offset -- [jal x1, offset] -- Jump and link + */ + auto pc = triton::arch::OperandWrapper(this->architecture->getProgramCounter()); + auto size = pc.getBitSize(); + auto& src = inst.operands[0]; + auto ra = this->architecture->getRegister(triton::arch::ID_REG_RV32_X1); + auto reg = triton::arch::OperandWrapper(ra); + + /* Create symbolic operands */ + auto pc_ast = this->symbolicEngine->getOperandAst(pc); + auto imm = this->symbolicEngine->getOperandAst(inst, src); + + /* Create the semantics */ + auto node = this->astCtxt->bv(inst.getNextAddress(), pc.getBitSize()); + auto node_pc = this->astCtxt->bvadd(pc_ast, imm); + + /* Create symbolic expression */ + auto expr = this->symbolicEngine->createSymbolicExpression(inst, node, reg, "C.JAL operation ra (x1)"); + auto expr_pc = this->symbolicEngine->createSymbolicExpression(inst, node_pc, pc, "Program Counter"); + + /* Spread taint */ + expr->isTainted = this->taintEngine->isTainted(pc); + expr_pc->isTainted = this->taintEngine->isTainted(pc); + + /* Create the path constraint */ + this->symbolicEngine->pushPathConstraint(inst, expr_pc); + } + + + void riscvSemantics::c_jalr_s(triton::arch::Instruction& inst) { + /* x1 := pc + 2; pc := (x[rs] + imm) & ~1 + Compressed instruction expands to: + jalr rs -- [jalr x1, rs, 0] -- Jump and link register + */ + auto pc = triton::arch::OperandWrapper(this->architecture->getProgramCounter()); + auto size = pc.getBitSize(); + auto& src = inst.operands[0]; + auto ra = this->architecture->getRegister( + size == 64 ? + triton::arch::ID_REG_RV64_X1 : + triton::arch::ID_REG_RV32_X1 + ); + auto dst = triton::arch::OperandWrapper(ra); + + /* Create symbolic operands */ + auto pc_ast = this->symbolicEngine->getOperandAst(pc); + auto op_src = this->symbolicEngine->getOperandAst(inst, src); + + /* Create the semantics */ + auto node_dst = this->astCtxt->bv(inst.getNextAddress(), pc.getBitSize()); + auto node_pc = this->astCtxt->bvand( /* ignore last bit */ + op_src, + this->astCtxt->bvshl(this->astCtxt->bv(-1, size), this->astCtxt->bv(1, size)) + ); + + /* Create symbolic expression */ + auto expr = this->symbolicEngine->createSymbolicExpression(inst, node_dst, dst, "C.JALR operation ra (x1)"); + auto expr_pc = this->symbolicEngine->createSymbolicExpression(inst, node_pc, pc, "Program Counter"); + + /* Spread taint */ + expr->isTainted = this->taintEngine->isTainted(pc); + expr_pc->isTainted = this->taintEngine->setTaint(pc, this->taintEngine->isTainted(src)); + + /* Create the path constraint */ + this->symbolicEngine->pushPathConstraint(inst, expr_pc); + } + + + void riscvSemantics::c_ld_s(triton::arch::Instruction& inst) { /* 64-bit only */ + // x[rd] := M[sp + offset][63:0] + auto& dst = inst.operands[0]; // rd + auto& src1 = inst.operands[1]; // offset - disp + auto& src2 = inst.operands[2]; // rs1 - base + + // FIXME when fixed https://github.com/capstone-engine/capstone/issues/2351 + /* Construct double word memory access manually with base and displacement */ + triton::arch::MemoryAccess mem; + mem.setBits(triton::bitsize::qword - 1, 0); + triton::arch::Immediate& disp = src1.getImmediate(); + triton::arch::Register& base = src2.getRegister(); + mem.setBaseRegister(base); + mem.setDisplacement(disp); + auto mem_op = triton::arch::OperandWrapper(mem); + this->symbolicEngine->initLeaAst(mem_op.getMemory()); + + /* Create the semantics */ + auto node = this->symbolicEngine->getOperandAst(inst, mem_op); + + /* Create symbolic expression */ + auto expr = this->symbolicEngine->createSymbolicExpression(inst, node, dst, "C.LD operation - LOAD access"); + + /* Spread taint */ + expr->isTainted = this->taintEngine->taintAssignment(dst, mem_op); + + /* Update the symbolic control flow */ + this->controlFlow_s(inst); + } + + + void riscvSemantics::c_ldsp_s(triton::arch::Instruction& inst) { /* 64-bit only */ + // x[rd] := M[sp + offset][63:0] + auto& dst = inst.operands[0]; // rd + auto& src1 = inst.operands[1]; // offset - disp; (sp - base) + + // FIXME when fixed https://github.com/capstone-engine/capstone/issues/2351 + /* Construct double word memory access manually with base and displacement */ + triton::arch::MemoryAccess mem; + mem.setBits(triton::bitsize::qword - 1, 0); + triton::arch::Immediate& disp = src1.getImmediate(); + auto sp = this->architecture->getStackPointer(); + mem.setBaseRegister(sp); + mem.setDisplacement(disp); + auto mem_op = triton::arch::OperandWrapper(mem); + this->symbolicEngine->initLeaAst(mem_op.getMemory()); + + /* Create the semantics */ + auto node = this->symbolicEngine->getOperandAst(inst, mem_op); + + /* Create symbolic expression */ + auto expr = this->symbolicEngine->createSymbolicExpression(inst, node, dst, "C.LDSP operation - LOAD access"); + + /* Spread taint */ + expr->isTainted = this->taintEngine->taintAssignment(dst, mem_op); + + /* Update the symbolic control flow */ + this->controlFlow_s(inst); + } + + + void riscvSemantics::c_li_s(triton::arch::Instruction& inst) { + auto& dst = inst.operands[0]; + auto& src = inst.operands[1]; + + /* Create the semantics */ + auto node = this->symbolicEngine->getOperandAst(inst, src); + + /* Create symbolic expression */ + auto expr = this->symbolicEngine->createSymbolicExpression(inst, node, dst, "C.LI operation"); + + /* Spread taint */ + expr->isTainted = this->taintEngine->setTaint(dst, false); + + /* Update the symbolic control flow */ + this->controlFlow_s(inst); + } + + + void riscvSemantics::c_lw_s(triton::arch::Instruction& inst) { + // x[rd] := M[x[rs] + offset][31:0] + auto& dst = inst.operands[0]; // rd + auto& src1 = inst.operands[1]; // offset - disp + auto& src2 = inst.operands[2]; // rs1 - base + + // FIXME when fixed https://github.com/capstone-engine/capstone/issues/2351 + /* Construct word memory access manually with base and displacement */ + triton::arch::MemoryAccess mem; + mem.setBits(triton::bitsize::dword - 1, 0); + triton::arch::Immediate& disp = src1.getImmediate(); + triton::arch::Register& base = src2.getRegister(); + mem.setBaseRegister(base); + mem.setDisplacement(disp); + auto mem_op = triton::arch::OperandWrapper(mem); + this->symbolicEngine->initLeaAst(mem_op.getMemory()); + + /* Create the semantics */ + auto node = this->symbolicEngine->getOperandAst(inst, mem_op); + if (dst.getBitSize() == 64) { /* extend to register size */ + node = this->astCtxt->sx(32, node); + } + + /* Create symbolic expression */ + auto expr = this->symbolicEngine->createSymbolicExpression(inst, node, dst, "C.LW operation - LOAD access"); + + /* Spread taint */ + expr->isTainted = this->taintEngine->taintAssignment(dst, mem_op); + + /* Update the symbolic control flow */ + this->controlFlow_s(inst); + } + + + void riscvSemantics::c_lwsp_s(triton::arch::Instruction& inst) { + // x[rd] := M[sp + offset][31:0] + auto& dst = inst.operands[0]; // rd + auto& src = inst.operands[1]; // offset - disp; (sp - base) + + // FIXME when fixed https://github.com/capstone-engine/capstone/issues/2351 + /* Construct word memory access manually with base and displacement */ + triton::arch::MemoryAccess mem; + mem.setBits(triton::bitsize::dword - 1, 0); + triton::arch::Immediate& disp = src.getImmediate(); + auto sp = this->architecture->getStackPointer(); + mem.setBaseRegister(sp); + mem.setDisplacement(disp); + auto mem_op = triton::arch::OperandWrapper(mem); + this->symbolicEngine->initLeaAst(mem_op.getMemory()); + + /* Create the semantics */ + auto node = this->symbolicEngine->getOperandAst(inst, mem_op); + if (dst.getBitSize() == 64) { /* extend to register size */ + node = this->astCtxt->sx(32, node); + } + + /* Create symbolic expression */ + auto expr = this->symbolicEngine->createSymbolicExpression(inst, node, dst, "C.LWSP operation - LOAD access"); + + /* Spread taint */ + expr->isTainted = this->taintEngine->taintAssignment(dst, mem_op); + + /* Update the symbolic control flow */ + this->controlFlow_s(inst); + } + + + void riscvSemantics::c_mv_s(triton::arch::Instruction& inst) { + auto& dst = inst.operands[0]; + auto& src = inst.operands[1]; + + /* Create the semantics */ + auto node = this->symbolicEngine->getOperandAst(inst, src); + + /* Create symbolic expression */ + auto expr = this->symbolicEngine->createSymbolicExpression(inst, node, dst, "C.MV operation"); + + /* Spread taint */ + expr->isTainted = this->taintEngine->taintAssignment(dst, src); + + /* Update the symbolic control flow */ + this->controlFlow_s(inst); + } + + + void riscvSemantics::c_nop_s(triton::arch::Instruction& inst) { + /* Update the symbolic control flow */ + this->controlFlow_s(inst); + } + + + void riscvSemantics::c_or_s(triton::arch::Instruction& inst) { + auto& dst = inst.operands[0]; + auto& src = inst.operands[1]; + + /* Create symbolic operands */ + auto op1 = this->symbolicEngine->getOperandAst(inst, dst); + auto op2 = this->symbolicEngine->getOperandAst(inst, src); + + /* Create the semantics */ + auto node = this->astCtxt->bvor(op1, op2); + + /* Create symbolic expression */ + auto expr = this->symbolicEngine->createSymbolicExpression(inst, node, dst, "C.OR operation"); + + /* Spread taint */ + expr->isTainted = this->taintEngine->setTaint(dst, this->taintEngine->isTainted(dst) | this->taintEngine->isTainted(src)); + + /* Update the symbolic control flow */ + this->controlFlow_s(inst); + } + + + void riscvSemantics::c_sd_s(triton::arch::Instruction& inst) { /* 64-bit only */ + // M[x[rs1] + offset] := x[rs2] + auto& src = inst.operands[0]; // rs2 + auto& imm = inst.operands[1]; // offset - disp + auto& dst = inst.operands[2]; // rs1 - base + + // FIXME when fixed https://github.com/capstone-engine/capstone/issues/2351 + /* Construct double word memory access manually with base and displacement */ + triton::arch::MemoryAccess mem; + mem.setBits(triton::bitsize::qword - 1, 0); + triton::arch::Immediate& disp = imm.getImmediate(); + triton::arch::Register& base = dst.getRegister(); + mem.setBaseRegister(base); + mem.setDisplacement(disp); + auto mem_op = triton::arch::OperandWrapper(mem); + this->symbolicEngine->initLeaAst(mem_op.getMemory()); + + /* Create the semantics */ + auto node = this->symbolicEngine->getOperandAst(inst, src); + + /* Create symbolic expression */ + auto expr = this->symbolicEngine->createSymbolicExpression(inst, node, mem_op, "C.SD operation - STORE access"); + + /* Spread taint */ + expr->isTainted = this->taintEngine->taintAssignment(mem_op, src); + + /* Update the symbolic control flow */ + this->controlFlow_s(inst); + } + + + void riscvSemantics::c_sdsp_s(triton::arch::Instruction& inst) { /* 64-bit only */ + // M[sp + offset] := x[rs] + auto& src = inst.operands[0]; // rs + auto& imm = inst.operands[1]; // offset - disp; (sp - base) + + // FIXME when fixed https://github.com/capstone-engine/capstone/issues/2351 + /* Construct double word memory access manually with base and displacement */ + triton::arch::MemoryAccess mem; + mem.setBits(triton::bitsize::qword - 1, 0); + triton::arch::Immediate& disp = imm.getImmediate(); + auto sp = this->architecture->getStackPointer(); + mem.setBaseRegister(sp); + mem.setDisplacement(disp); + auto mem_op = triton::arch::OperandWrapper(mem); + this->symbolicEngine->initLeaAst(mem_op.getMemory()); + + /* Create the semantics */ + auto node = this->symbolicEngine->getOperandAst(inst, src); + + /* Create symbolic expression */ + auto expr = this->symbolicEngine->createSymbolicExpression(inst, node, mem_op, "C.SDSP operation - STORE access"); + + /* Spread taint */ + expr->isTainted = this->taintEngine->taintAssignment(mem_op, src); + + /* Update the symbolic control flow */ + this->controlFlow_s(inst); + } + + + void riscvSemantics::c_slli_s(triton::arch::Instruction& inst) { + auto& dst = inst.operands[0]; + auto& src = inst.operands[1]; + auto size = src.getBitSize(); + + /* Create symbolic operands */ + auto op1 = this->symbolicEngine->getOperandAst(inst, dst); + auto op2 = this->astCtxt->bvand( + this->symbolicEngine->getOperandAst(inst, src), + dst.getBitSize() == 64 ? this->astCtxt->bv(0x3f, size) : this->astCtxt->bv(0x1f, size) + ); + + /* Create the semantics */ + auto node = this->astCtxt->bvshl(op1, op2); + + /* Create symbolic expression */ + auto expr = this->symbolicEngine->createSymbolicExpression(inst, node, dst, "C.SLLI operation"); + + /* Spread taint */ + expr->isTainted = this->taintEngine->taintUnion(dst, src); + + /* Update the symbolic control flow */ + this->controlFlow_s(inst); + } + + + void riscvSemantics::c_srai_s(triton::arch::Instruction& inst) { + auto& dst = inst.operands[0]; + auto& src = inst.operands[1]; + auto size = src.getBitSize(); + + /* Create symbolic operands */ + auto op1 = this->symbolicEngine->getOperandAst(inst, dst); + auto op2 = this->astCtxt->bvand( + this->symbolicEngine->getOperandAst(inst, src), + dst.getBitSize() == 64 ? this->astCtxt->bv(0x3f, size) : this->astCtxt->bv(0x1f, size) + ); + + /* Create the semantics */ + auto node = this->astCtxt->bvashr(op1, op2); + + /* Create symbolic expression */ + auto expr = this->symbolicEngine->createSymbolicExpression(inst, node, dst, "C.SRAI operation"); + + /* Spread taint */ + expr->isTainted = this->taintEngine->taintUnion(dst, src); + + /* Update the symbolic control flow */ + this->controlFlow_s(inst); + } + + + void riscvSemantics::c_srli_s(triton::arch::Instruction& inst) { + auto& dst = inst.operands[0]; + auto& src = inst.operands[1]; + auto size = src.getBitSize(); + + /* Create symbolic operands */ + auto op1 = this->symbolicEngine->getOperandAst(inst, dst); + auto op2 = this->astCtxt->bvand( + this->symbolicEngine->getOperandAst(inst, src), + dst.getBitSize() == 64 ? this->astCtxt->bv(0x3f, size) : this->astCtxt->bv(0x1f, size) + ); + + /* Create the semantics */ + auto node = this->astCtxt->bvlshr(op1, op2); + + /* Create symbolic expression */ + auto expr = this->symbolicEngine->createSymbolicExpression(inst, node, dst, "C.SRLI operation"); + + /* Spread taint */ + expr->isTainted = this->taintEngine->taintUnion(dst, src); + + /* Update the symbolic control flow */ + this->controlFlow_s(inst); + } + + + void riscvSemantics::c_sub_s(triton::arch::Instruction& inst) { + auto& dst = inst.operands[0]; + auto& src = inst.operands[1]; + + /* Create symbolic operands */ + auto op1 = this->symbolicEngine->getOperandAst(inst, dst); + auto op2 = this->symbolicEngine->getOperandAst(inst, src); + + /* Create the semantics */ + auto node = this->astCtxt->bvsub(op1, op2); + + /* Create symbolic expression */ + auto expr = this->symbolicEngine->createSymbolicExpression(inst, node, dst, "C.SUB operation"); + + /* Spread taint */ + expr->isTainted = this->taintEngine->taintUnion(dst, src); + + /* Update the symbolic control flow */ + this->controlFlow_s(inst); + } + + + void riscvSemantics::c_subw_s(triton::arch::Instruction& inst) { /* 64-bit only */ + auto& dst = inst.operands[0]; + auto& src = inst.operands[1]; + + /* Create symbolic operands */ + auto op1 = this->astCtxt->extract(31, 0, this->symbolicEngine->getOperandAst(inst, dst)); + auto op2 = this->astCtxt->extract(31, 0, this->symbolicEngine->getOperandAst(inst, src)); + + /* Create the semantics */ + auto node = this->astCtxt->sx(32, this->astCtxt->bvsub(op1, op2)); + + /* Create symbolic expression */ + auto expr = this->symbolicEngine->createSymbolicExpression(inst, node, dst, "C.SUBW operation"); + + /* Spread taint */ + expr->isTainted = this->taintEngine->taintUnion(dst, src); + + /* Update the symbolic control flow */ + this->controlFlow_s(inst); + } + + + void riscvSemantics::c_sw_s(triton::arch::Instruction& inst) { + // M[x[rs1] + offset] := (x[rs2] & 0xffffffff) + auto& src = inst.operands[0]; // rs2 + auto& imm = inst.operands[1]; // offset - disp + auto& dst = inst.operands[2]; // rs1 - base + + // FIXME when fixed https://github.com/capstone-engine/capstone/issues/2351 + /* Construct double word memory access manually with base and displacement */ + triton::arch::MemoryAccess mem; + mem.setBits(triton::bitsize::dword - 1, 0); + triton::arch::Immediate& disp = imm.getImmediate(); + triton::arch::Register& base = dst.getRegister(); + mem.setBaseRegister(base); + mem.setDisplacement(disp); + auto mem_op = triton::arch::OperandWrapper(mem); + this->symbolicEngine->initLeaAst(mem_op.getMemory()); + + /* Create the semantics */ + auto node = this->symbolicEngine->getOperandAst(inst, src); + if (src.getBitSize() == 64) { + node = this->astCtxt->extract(31, 0, node); + } + + /* Create symbolic expression */ + auto expr = this->symbolicEngine->createSymbolicExpression(inst, node, mem_op, "C.SW operation - STORE access"); + + /* Spread taint */ + expr->isTainted = this->taintEngine->taintAssignment(mem_op, src); + + /* Update the symbolic control flow */ + this->controlFlow_s(inst); + } + + + void riscvSemantics::c_swsp_s(triton::arch::Instruction& inst) { + // M[sp + offset] := (x[rs] & 0xffffffff) + auto& src = inst.operands[0]; // rs + auto& imm = inst.operands[1]; // offset - disp; (sp - base) + + // FIXME when fixed https://github.com/capstone-engine/capstone/issues/2351 + /* Construct double word memory access manually with base and displacement */ + triton::arch::MemoryAccess mem; + mem.setBits(triton::bitsize::dword - 1, 0); + triton::arch::Immediate& disp = imm.getImmediate(); + auto sp = this->architecture->getStackPointer(); + mem.setBaseRegister(sp); + mem.setDisplacement(disp); + auto mem_op = triton::arch::OperandWrapper(mem); + this->symbolicEngine->initLeaAst(mem_op.getMemory()); + + /* Create the semantics */ + auto node = this->symbolicEngine->getOperandAst(inst, src); + if (src.getBitSize() == 64) { + node = this->astCtxt->extract(31, 0, node); + } + + /* Create symbolic expression */ + auto expr = this->symbolicEngine->createSymbolicExpression(inst, node, mem_op, "C.SWSP operation - STORE access"); + + /* Spread taint */ + expr->isTainted = this->taintEngine->taintAssignment(mem_op, src); + + /* Update the symbolic control flow */ + this->controlFlow_s(inst); + } + + + void riscvSemantics::c_xor_s(triton::arch::Instruction& inst) { + auto& dst = inst.operands[0]; + auto& src = inst.operands[1]; + + /* Create symbolic operands */ + auto op1 = this->symbolicEngine->getOperandAst(inst, dst); + auto op2 = this->symbolicEngine->getOperandAst(inst, src); + + /* Create the semantics */ + auto node = this->astCtxt->bvxor(op1, op2); + + /* Create symbolic expression */ + auto expr = this->symbolicEngine->createSymbolicExpression(inst, node, dst, "C.XOR operation"); + + /* Spread taint */ + expr->isTainted = this->taintEngine->setTaint(dst, this->taintEngine->isTainted(dst) | this->taintEngine->isTainted(src)); + + /* Update the symbolic control flow */ + this->controlFlow_s(inst); + } + + + void riscvSemantics::div_s(triton::arch::Instruction& inst) { + auto& dst = inst.operands[0]; + auto& src1 = inst.operands[1]; + auto& src2 = inst.operands[2]; + + /* Create symbolic operands */ + auto op1 = this->symbolicEngine->getOperandAst(inst, src1); + auto op2 = this->symbolicEngine->getOperandAst(inst, src2); + + /* Create the semantics */ + auto node = this->astCtxt->ite( + this->astCtxt->equal(op2, this->astCtxt->bv(0, op2->getBitvectorSize())), + this->astCtxt->bv(-1, dst.getBitSize()), + this->astCtxt->bvsdiv(op1, op2) + ); + + /* Create symbolic expression */ + auto expr = this->symbolicEngine->createSymbolicExpression(inst, node, dst, "DIV operation"); + + /* Spread taint */ + expr->isTainted = this->taintEngine->setTaint(dst, this->taintEngine->isTainted(src1) | this->taintEngine->isTainted(src2)); + + /* Update the symbolic control flow */ + this->controlFlow_s(inst); + } + + + void riscvSemantics::divu_s(triton::arch::Instruction& inst) { + auto& dst = inst.operands[0]; + auto& src1 = inst.operands[1]; + auto& src2 = inst.operands[2]; + + /* Create symbolic operands */ + auto op1 = this->symbolicEngine->getOperandAst(inst, src1); + auto op2 = this->symbolicEngine->getOperandAst(inst, src2); + + /* Create the semantics */ + auto node = this->astCtxt->ite( + this->astCtxt->equal(op2, this->astCtxt->bv(0, op2->getBitvectorSize())), + this->astCtxt->bv(-1, dst.getBitSize()), + this->astCtxt->bvudiv(op1, op2) + ); + + /* Create symbolic expression */ + auto expr = this->symbolicEngine->createSymbolicExpression(inst, node, dst, "DIVU operation"); + + /* Spread taint */ + expr->isTainted = this->taintEngine->setTaint(dst, this->taintEngine->isTainted(src1) | this->taintEngine->isTainted(src2)); + + /* Update the symbolic control flow */ + this->controlFlow_s(inst); + } + + + void riscvSemantics::divuw_s(triton::arch::Instruction& inst) { /* 64-bit only */ + auto& dst = inst.operands[0]; + auto& src1 = inst.operands[1]; + auto& src2 = inst.operands[2]; + + /* Create symbolic operands */ + auto op1 = this->astCtxt->extract(31, 0, this->symbolicEngine->getOperandAst(inst, src1)); + auto op2 = this->astCtxt->extract(31, 0, this->symbolicEngine->getOperandAst(inst, src2)); + + /* Create the semantics */ + auto node = this->astCtxt->ite( + this->astCtxt->equal(op2, this->astCtxt->bv(0, op2->getBitvectorSize())), + this->astCtxt->bv(-1, dst.getBitSize()), + this->astCtxt->sx(32, this->astCtxt->bvudiv(op1, op2)) + ); + + /* Create symbolic expression */ + auto expr = this->symbolicEngine->createSymbolicExpression(inst, node, dst, "DIVUW operation"); + + /* Spread taint */ + expr->isTainted = this->taintEngine->setTaint(dst, this->taintEngine->isTainted(src1) | this->taintEngine->isTainted(src2)); + + /* Update the symbolic control flow */ + this->controlFlow_s(inst); + } + + + void riscvSemantics::divw_s(triton::arch::Instruction& inst) { /* 64-bit only */ + auto& dst = inst.operands[0]; + auto& src1 = inst.operands[1]; + auto& src2 = inst.operands[2]; + + /* Create symbolic operands */ + auto op1 = this->astCtxt->extract(31, 0, this->symbolicEngine->getOperandAst(inst, src1)); + auto op2 = this->astCtxt->extract(31, 0, this->symbolicEngine->getOperandAst(inst, src2)); + + /* Create the semantics */ + auto node = this->astCtxt->ite( + this->astCtxt->equal(op2, this->astCtxt->bv(0, op2->getBitvectorSize())), + this->astCtxt->bv(-1, dst.getBitSize()), + this->astCtxt->sx(32, this->astCtxt->bvsdiv(op1, op2)) + ); + + /* Create symbolic expression */ + auto expr = this->symbolicEngine->createSymbolicExpression(inst, node, dst, "DIVW operation"); + + /* Spread taint */ + expr->isTainted = this->taintEngine->setTaint(dst, this->taintEngine->isTainted(src1) | this->taintEngine->isTainted(src2)); + + /* Update the symbolic control flow */ + this->controlFlow_s(inst); + } + + void riscvSemantics::jal_s(triton::arch::Instruction& inst) { + /* Check for possible pseudo instructions + j offset -- [jal x0, offset] -- Jump + jal offset -- [jal x1, offset] -- Jump and link + */ + auto mnem = inst.getDisassembly(); + if (mnem[1] == ' ') { + jal_j_s(inst); + return; + } + + auto pc = triton::arch::OperandWrapper(this->architecture->getProgramCounter()); + auto size = pc.getBitSize(); + + auto ra = this->architecture->getRegister( + size == 64 ? + triton::arch::ID_REG_RV64_X1 : + triton::arch::ID_REG_RV32_X1 + ); + auto reg = triton::arch::OperandWrapper(ra); + auto& src1 = inst.operands[0]; + + /* Create symbolic operands */ + auto pc_ast = this->symbolicEngine->getOperandAst(pc); + auto imm = this->symbolicEngine->getOperandAst(inst, src1); + if (src1.getType() == triton::arch::OP_REG) { + auto& src2 = inst.operands[1]; + reg = src1; + imm = this->symbolicEngine->getOperandAst(inst, src2); + } + + /* Create the semantics */ + auto node = this->astCtxt->bv(inst.getNextAddress(), size); + auto node_pc = this->astCtxt->bvadd(pc_ast, imm); + + /* Create symbolic expression */ + auto expr = this->symbolicEngine->createSymbolicExpression(inst, node, reg, "JAL operation ret addr"); + auto expr_pc = this->symbolicEngine->createSymbolicExpression(inst, node_pc, pc, "Program Counter"); + + /* Spread taint */ + expr->isTainted = this->taintEngine->setTaint(reg, this->taintEngine->isTainted(pc)); + expr_pc->isTainted = this->taintEngine->setTaint(pc, this->taintEngine->isTainted(pc)); + + /* Create the path constraint */ + this->symbolicEngine->pushPathConstraint(inst, expr_pc); + } + + + void riscvSemantics::jal_j_s(triton::arch::Instruction& inst) { + auto pc = triton::arch::OperandWrapper(this->architecture->getProgramCounter()); + auto& src1 = inst.operands[0]; + auto size = pc.getBitSize(); + + /* Create symbolic operands */ + auto pc_ast = this->symbolicEngine->getOperandAst(pc); + auto imm = this->symbolicEngine->getOperandAst(inst, src1); + + /* Create the semantics */ + auto node_pc = this->astCtxt->bvadd(pc_ast, imm); + + /* Create symbolic expression */ + auto expr_pc = this->symbolicEngine->createSymbolicExpression(inst, node_pc, pc, "Program Counter"); + + /* Spread taint */ + expr_pc->isTainted = this->taintEngine->isTainted(pc); + + /* Create the path constraint */ + this->symbolicEngine->pushPathConstraint(inst, expr_pc); + } + + + void riscvSemantics::jalr_s(triton::arch::Instruction& inst) { + /* x[rd] := pc + 4; pc := (x[rs] + imm) & ~1 + /* Check for possible pseudo instructions + ret -- [jalr x0, x1, 0] -- Return from subroutine + jr rs -- [jalr x0, rs, 0] -- Jump register + jalr rs -- [jalr x1, rs, 0] -- Jump and link register + */ + auto mnem = inst.getDisassembly(); + if (mnem[2] != 'l') { jalr_no_link_s(inst); return; } // ret & jr semantics + + auto pc = triton::arch::OperandWrapper(this->architecture->getProgramCounter()); + auto size = pc.getBitSize(); + auto ra = this->architecture->getRegister( + size == 64 ? + triton::arch::ID_REG_RV64_X1 : + triton::arch::ID_REG_RV32_X1 + ); + auto dst = triton::arch::OperandWrapper(ra); + auto& src = inst.operands[0]; + + /* Create semantics (jalr with 1 operand) */ + auto pc_ast = this->symbolicEngine->getOperandAst(pc); + auto node_dst = this->astCtxt->bv(inst.getNextAddress(), size); + auto node_pc = this->symbolicEngine->getOperandAst(inst, src); + if (inst.operands.size() == 3) { // jalr with 3 operands semantics + dst = src; + src = inst.operands[1]; + auto& imm = inst.operands[2]; + + /* Create symbolic operands */ + auto op1 = this->symbolicEngine->getOperandAst(inst, src); + auto op2 = this->symbolicEngine->getOperandAst(inst, imm); + + node_pc = this->astCtxt->bvadd(op1, op2); + } + node_pc = this->astCtxt->bvand( /* ignore last bit */ + node_pc, + this->astCtxt->bvshl(this->astCtxt->bv(-1, size), this->astCtxt->bv(1, size)) + ); + + /* Create symbolic expression */ + auto expr = this->symbolicEngine->createSymbolicExpression(inst, node_dst, dst, "JALR operation ret addr"); + auto expr_pc = this->symbolicEngine->createSymbolicExpression(inst, node_pc, pc, "Program Counter"); + + /* Spread taint */ + expr->isTainted = this->taintEngine->isTainted(pc); + expr_pc->isTainted = this->taintEngine->setTaint(pc, this->taintEngine->isTainted(src)); + + /* Create the path constraint */ + this->symbolicEngine->pushPathConstraint(inst, expr_pc); + } + + + void riscvSemantics::jalr_no_link_s(triton::arch::Instruction& inst) { // rd == x0 + auto pc = triton::arch::OperandWrapper(this->architecture->getProgramCounter()); + auto size = pc.getBitSize(); + auto ra = this->architecture->getRegister( + size == 64 ? + triton::arch::ID_REG_RV64_X1 : + triton::arch::ID_REG_RV32_X1 + ); + auto src = triton::arch::OperandWrapper(ra); + if (inst.operands.size()) { + src = inst.operands[0]; + } + + /* Create the semantics */ + auto node = this->symbolicEngine->getOperandAst(inst, src); + node = this->astCtxt->bvand( /* ignore last bit */ + node, + this->astCtxt->bvshl(this->astCtxt->bv(-1, size), this->astCtxt->bv(1, size)) + ); + + /* Create symbolic expression */ + auto expr = this->symbolicEngine->createSymbolicExpression(inst, node, pc, "Program Counter"); + + /* Spread taint */ + expr->isTainted = this->taintEngine->setTaint(pc, this->taintEngine->isTainted(src)); + + /* Create the path constraint */ + this->symbolicEngine->pushPathConstraint(inst, expr); + } + + + void riscvSemantics::lb_s(triton::arch::Instruction& inst) { + // x[rd] := M[x[rs] + offset][7:0] + auto& dst = inst.operands[0]; // rd + auto& src = inst.operands[1]; // rs - base, offset - disp + auto size = dst.getBitSize(); + + /* Create the semantics */ + auto node = this->symbolicEngine->getOperandAst(inst, src); + node = this->astCtxt->sx(size - 8, node); + + /* Create symbolic expression */ + auto expr = this->symbolicEngine->createSymbolicExpression(inst, node, dst, "LB operation - LOAD access"); + + /* Spread taint */ + expr->isTainted = this->taintEngine->taintAssignment(dst, src); + + /* Update the symbolic control flow */ + this->controlFlow_s(inst); + } + + + void riscvSemantics::lbu_s(triton::arch::Instruction& inst) { + // x[rd] := M[x[rs] + offset][7:0] + auto& dst = inst.operands[0]; // rd + auto& src = inst.operands[1]; // rs - base, offset - disp + auto size = dst.getBitSize(); + + /* Create the semantics */ + auto node = this->symbolicEngine->getOperandAst(inst, src); + node = this->astCtxt->zx(size - 8, node); + + /* Create symbolic expression */ + auto expr = this->symbolicEngine->createSymbolicExpression(inst, node, dst, "LBU operation - LOAD access"); + + /* Spread taint */ + expr->isTainted = this->taintEngine->taintAssignment(dst, src); + + /* Update the symbolic control flow */ + this->controlFlow_s(inst); + } + + + void riscvSemantics::ld_s(triton::arch::Instruction& inst) { /* 64-bit only */ + // x[rd] := M[x[rs] + offset][63:0] + auto& dst = inst.operands[0]; // rd + auto& src = inst.operands[1]; // rs - base, offset - disp + + /* Create the semantics */ + auto node = this->symbolicEngine->getOperandAst(inst, src); + + /* Create symbolic expression */ + auto expr = this->symbolicEngine->createSymbolicExpression(inst, node, dst, "LD operation - LOAD access"); + + /* Spread taint */ + expr->isTainted = this->taintEngine->taintAssignment(dst, src); + + /* Update the symbolic control flow */ + this->controlFlow_s(inst); + } + + + void riscvSemantics::lh_s(triton::arch::Instruction& inst) { + // x[rd] := M[x[rs] + offset][15:0] + auto& dst = inst.operands[0]; // rd + auto& src = inst.operands[1]; // rs - base, offset - disp + auto size = dst.getBitSize(); + + /* Create the semantics */ + auto node = this->symbolicEngine->getOperandAst(inst, src); + node = this->astCtxt->sx(size - 16, node); + + /* Create symbolic expression */ + auto expr = this->symbolicEngine->createSymbolicExpression(inst, node, dst, "LH operation - LOAD access"); + + /* Spread taint */ + expr->isTainted = this->taintEngine->taintAssignment(dst, src); + + /* Update the symbolic control flow */ + this->controlFlow_s(inst); + } + + + void riscvSemantics::lhu_s(triton::arch::Instruction& inst) { + // x[rd] := M[x[rs] + offset][15:0] + auto& dst = inst.operands[0]; // rd + auto& src = inst.operands[1]; // rs - base, offset - disp + auto size = dst.getBitSize(); + + /* Create the semantics */ + auto node = this->symbolicEngine->getOperandAst(inst, src); + node = this->astCtxt->zx(size - 16, node); + + /* Create symbolic expression */ + auto expr = this->symbolicEngine->createSymbolicExpression(inst, node, dst, "LHU operation - LOAD access"); + + /* Spread taint */ + expr->isTainted = this->taintEngine->taintAssignment(dst, src); + + /* Update the symbolic control flow */ + this->controlFlow_s(inst); + } + + + void riscvSemantics::lui_s(triton::arch::Instruction& inst) { + // dst := (src_imm(_20) << 12) + auto& dst = inst.operands[0]; + auto& src = inst.operands[1]; + auto size = dst.getBitSize(); + + /* Create symbolic operands */ + auto imm = this->symbolicEngine->getOperandAst(inst, src); + + /* Create the semantics */ + auto node = this->astCtxt->bvshl( + this->astCtxt->sx(size - 20, this->astCtxt->extract(19, 0, imm)), + this->astCtxt->bv(12, size) + ); + + /* Create symbolic expression */ + auto expr = this->symbolicEngine->createSymbolicExpression(inst, node, dst, "LUI operation"); + + /* Spread taint */ + expr->isTainted = this->taintEngine->setTaint(dst, false); + + /* Update the symbolic control flow */ + this->controlFlow_s(inst); + } + + + void riscvSemantics::lw_s(triton::arch::Instruction& inst) { + // x[rd] := M[x[rs] + offset][31:0] + auto& dst = inst.operands[0]; // rd + auto& src = inst.operands[1]; // rs1 - base, offset - disp + + /* Create the semantics */ + auto node = this->symbolicEngine->getOperandAst(inst, src); + if (dst.getBitSize() == 64) { /* extend to register size */ + node = this->astCtxt->sx(32, node); + } + + /* Create symbolic expression */ + auto expr = this->symbolicEngine->createSymbolicExpression(inst, node, dst, "LW operation - LOAD access"); + + /* Spread taint */ + expr->isTainted = this->taintEngine->taintAssignment(dst, src); + + /* Update the symbolic control flow */ + this->controlFlow_s(inst); + } + + + void riscvSemantics::lwu_s(triton::arch::Instruction& inst) { /* 64-bit only */ + // x[rd] := M[x[rs] + offset][31:0] + auto& dst = inst.operands[0]; // rd + auto& src = inst.operands[1]; // rs1 - base, offset - disp + auto size = dst.getBitSize(); + + /* Create the semantics */ + auto node = this->symbolicEngine->getOperandAst(inst, src); + node = this->astCtxt->zx(32, node); + + /* Create symbolic expression */ + auto expr = this->symbolicEngine->createSymbolicExpression(inst, node, dst, "LWU operation - LOAD access"); + + /* Spread taint */ + expr->isTainted = this->taintEngine->taintAssignment(dst, src); + + /* Update the symbolic control flow */ + this->controlFlow_s(inst); + } + + + void riscvSemantics::mul_s(triton::arch::Instruction& inst) { + auto& dst = inst.operands[0]; + auto& src1 = inst.operands[1]; + auto& src2 = inst.operands[2]; + + /* Create symbolic operands */ + auto op1 = this->symbolicEngine->getOperandAst(inst, src1); + auto op2 = this->symbolicEngine->getOperandAst(inst, src2); + + /* Create the semantics */ + auto node = this->astCtxt->bvmul(op1, op2); + + /* Create symbolic expression */ + auto expr = this->symbolicEngine->createSymbolicExpression(inst, node, dst, "MUL operation"); + + /* Spread taint */ + expr->isTainted = this->taintEngine->setTaint(dst, this->taintEngine->isTainted(src1) | this->taintEngine->isTainted(src2)); + + /* Update the symbolic control flow */ + this->controlFlow_s(inst); + } + + + void riscvSemantics::mulh_s(triton::arch::Instruction& inst) { + auto& dst = inst.operands[0]; + auto& src1 = inst.operands[1]; + auto& src2 = inst.operands[2]; + auto size = src2.getBitSize(); + + /* Create symbolic operands */ + auto op1 = this->astCtxt->sx(size, this->symbolicEngine->getOperandAst(inst, src1)); + auto op2 = this->astCtxt->sx(size, this->symbolicEngine->getOperandAst(inst, src2)); + + /* Create the semantics */ + auto node = this->astCtxt->extract(size * 2 - 1, size, this->astCtxt->bvmul(op1, op2)); + + /* Create symbolic expression */ + auto expr = this->symbolicEngine->createSymbolicExpression(inst, node, dst, "MULH operation"); + + /* Spread taint */ + expr->isTainted = this->taintEngine->setTaint(dst, this->taintEngine->isTainted(src1) | this->taintEngine->isTainted(src2)); + + /* Update the symbolic control flow */ + this->controlFlow_s(inst); + } + + + void riscvSemantics::mulhsu_s(triton::arch::Instruction& inst) { + auto& dst = inst.operands[0]; + auto& src1 = inst.operands[1]; + auto& src2 = inst.operands[2]; + auto size = src2.getBitSize(); + + /* Create symbolic operands */ + auto op1 = this->astCtxt->sx(size, this->symbolicEngine->getOperandAst(inst, src1)); + auto op2 = this->astCtxt->zx(size, this->symbolicEngine->getOperandAst(inst, src2)); + + /* Create the semantics */ + auto node = this->astCtxt->extract(size * 2 - 1, size, this->astCtxt->bvmul(op1, op2)); + + /* Create symbolic expression */ + auto expr = this->symbolicEngine->createSymbolicExpression(inst, node, dst, "MULHSU operation"); + + /* Spread taint */ + expr->isTainted = this->taintEngine->setTaint(dst, this->taintEngine->isTainted(src1) | this->taintEngine->isTainted(src2)); + + /* Update the symbolic control flow */ + this->controlFlow_s(inst); + } + + + void riscvSemantics::mulhu_s(triton::arch::Instruction& inst) { + auto& dst = inst.operands[0]; + auto& src1 = inst.operands[1]; + auto& src2 = inst.operands[2]; + auto size = src2.getBitSize(); + + /* Create symbolic operands */ + auto op1 = this->astCtxt->zx(size, this->symbolicEngine->getOperandAst(inst, src1)); + auto op2 = this->astCtxt->zx(size, this->symbolicEngine->getOperandAst(inst, src2)); + + /* Create the semantics */ + auto node = this->astCtxt->extract(size * 2 - 1, size, this->astCtxt->bvmul(op1, op2)); + + /* Create symbolic expression */ + auto expr = this->symbolicEngine->createSymbolicExpression(inst, node, dst, "MULHU operation"); + + /* Spread taint */ + expr->isTainted = this->taintEngine->setTaint(dst, this->taintEngine->isTainted(src1) | this->taintEngine->isTainted(src2)); + + /* Update the symbolic control flow */ + this->controlFlow_s(inst); + } + + + void riscvSemantics::mulw_s(triton::arch::Instruction& inst) { /* 64-bit only */ + auto& dst = inst.operands[0]; + auto& src1 = inst.operands[1]; + auto& src2 = inst.operands[2]; + + /* Create symbolic operands */ + auto op1 = this->astCtxt->extract(31, 0, this->symbolicEngine->getOperandAst(inst, src1)); + auto op2 = this->astCtxt->extract(31, 0, this->symbolicEngine->getOperandAst(inst, src2)); + + /* Create the semantics */ + auto node = this->astCtxt->sx(32, this->astCtxt->bvmul(op1, op2)); + + /* Create symbolic expression */ + auto expr = this->symbolicEngine->createSymbolicExpression(inst, node, dst, "MULW operation"); + + /* Spread taint */ + expr->isTainted = this->taintEngine->setTaint(dst, this->taintEngine->isTainted(src1) | this->taintEngine->isTainted(src2)); + + /* Update the symbolic control flow */ + this->controlFlow_s(inst); + } + + + void riscvSemantics::or_s(triton::arch::Instruction& inst) { + auto& dst = inst.operands[0]; + auto& src1 = inst.operands[1]; + auto& src2 = inst.operands[2]; + + /* Create symbolic operands */ + auto op1 = this->symbolicEngine->getOperandAst(inst, src1); + auto op2 = this->symbolicEngine->getOperandAst(inst, src2); + + /* Create the semantics */ + auto node = this->astCtxt->bvor(op1, op2); + + /* Create symbolic expression */ + auto expr = this->symbolicEngine->createSymbolicExpression(inst, node, dst, "OR(I) operation"); + + /* Spread taint */ + expr->isTainted = this->taintEngine->setTaint(dst, this->taintEngine->isTainted(src1) | this->taintEngine->isTainted(src2)); + + /* Update the symbolic control flow */ + this->controlFlow_s(inst); + } + + + void riscvSemantics::rem_s(triton::arch::Instruction& inst) { + auto& dst = inst.operands[0]; + auto& src1 = inst.operands[1]; + auto& src2 = inst.operands[2]; + auto size = dst.getBitSize(); + + /* Create symbolic operands */ + auto op1 = this->symbolicEngine->getOperandAst(inst, src1); + auto op2 = this->symbolicEngine->getOperandAst(inst, src2); + + /* Create the semantics */ + auto node = this->astCtxt->ite( + this->astCtxt->equal(op2, this->astCtxt->bv(0, op2->getBitvectorSize())), + op1, + this->astCtxt->ite( // overflow check + this->astCtxt->land( + this->astCtxt->equal(op1, this->astCtxt->bv(-1, size)), + this->astCtxt->equal(op2, this->astCtxt->bv((1 << (size - 1)), size)) + ), + this->astCtxt->bv(0, size), + this->astCtxt->bvsrem(op1, op2) + ) + ); + + /* Create symbolic expression */ + auto expr = this->symbolicEngine->createSymbolicExpression(inst, node, dst, "REM operation"); + + /* Spread taint */ + expr->isTainted = this->taintEngine->setTaint(dst, this->taintEngine->isTainted(src1) | this->taintEngine->isTainted(src2)); + + /* Update the symbolic control flow */ + this->controlFlow_s(inst); + } + + + void riscvSemantics::remu_s(triton::arch::Instruction& inst) { + auto& dst = inst.operands[0]; + auto& src1 = inst.operands[1]; + auto& src2 = inst.operands[2]; + + /* Create symbolic operands */ + auto op1 = this->symbolicEngine->getOperandAst(inst, src1); + auto op2 = this->symbolicEngine->getOperandAst(inst, src2); + + /* Create the semantics */ + auto node = this->astCtxt->ite( + this->astCtxt->equal(op2, this->astCtxt->bv(0, op2->getBitvectorSize())), + op1, + this->astCtxt->bvurem(op1, op2) + ); + + /* Create symbolic expression */ + auto expr = this->symbolicEngine->createSymbolicExpression(inst, node, dst, "REMU operation"); + + /* Spread taint */ + expr->isTainted = this->taintEngine->setTaint(dst, this->taintEngine->isTainted(src1) | this->taintEngine->isTainted(src2)); + + /* Update the symbolic control flow */ + this->controlFlow_s(inst); + } + + + void riscvSemantics::remuw_s(triton::arch::Instruction& inst) { /* 64-bit only */ + auto& dst = inst.operands[0]; + auto& src1 = inst.operands[1]; + auto& src2 = inst.operands[2]; + + /* Create symbolic operands */ + auto op1 = this->astCtxt->extract(31, 0, this->symbolicEngine->getOperandAst(inst, src1)); + auto op2 = this->astCtxt->extract(31, 0, this->symbolicEngine->getOperandAst(inst, src2)); + + /* Create the semantics */ + auto node = this->astCtxt->ite( + this->astCtxt->equal(op2, this->astCtxt->bv(0, op2->getBitvectorSize())), + this->astCtxt->sx(32, op1), + this->astCtxt->sx(32, this->astCtxt->bvurem(op1, op2)) + ); + + /* Create symbolic expression */ + auto expr = this->symbolicEngine->createSymbolicExpression(inst, node, dst, "REMUW operation"); + + /* Spread taint */ + expr->isTainted = this->taintEngine->setTaint(dst, this->taintEngine->isTainted(src1) | this->taintEngine->isTainted(src2)); + + /* Update the symbolic control flow */ + this->controlFlow_s(inst); + } + + + void riscvSemantics::remw_s(triton::arch::Instruction& inst) { /* 64-bit only */ + auto& dst = inst.operands[0]; + auto& src1 = inst.operands[1]; + auto& src2 = inst.operands[2]; + + /* Create symbolic operands */ + auto op1 = this->astCtxt->extract(31, 0, this->symbolicEngine->getOperandAst(inst, src1)); + auto op2 = this->astCtxt->extract(31, 0, this->symbolicEngine->getOperandAst(inst, src2)); + + /* Create the semantics */ + uint32_t ov_value = 0x80000000; + auto node = this->astCtxt->ite( // div-by-zero check + this->astCtxt->equal(op2, this->astCtxt->bv(0, op2->getBitvectorSize())), + this->astCtxt->sx(32, op1), + this->astCtxt->ite( // signed overflow check + this->astCtxt->land( + this->astCtxt->equal(op1, this->astCtxt->bv(ov_value, 32)), + this->astCtxt->equal(op2, this->astCtxt->bv(-1, 32)) + ), + this->astCtxt->bv(0, dst.getBitSize()), + this->astCtxt->sx(32, this->astCtxt->bvsrem(op1, op2)) + ) + ); + + /* Create symbolic expression */ + auto expr = this->symbolicEngine->createSymbolicExpression(inst, node, dst, "REMW operation"); + + /* Spread taint */ + expr->isTainted = this->taintEngine->setTaint(dst, this->taintEngine->isTainted(src1) | this->taintEngine->isTainted(src2)); + + /* Update the symbolic control flow */ + this->controlFlow_s(inst); + } + + + void riscvSemantics::sb_s(triton::arch::Instruction& inst) { + // M[x[rs1] + offset] := (x[rs2] & 0xff) + auto& src = inst.operands[0]; // rs2 + auto& dst = inst.operands[1]; // rs1 - base, offset - disp + + /* Create symbolic operands */ + auto node = this->symbolicEngine->getOperandAst(inst, src); + node = this->astCtxt->extract(7, 0, node); + + /* Create symbolic expression */ + auto expr = this->symbolicEngine->createSymbolicExpression(inst, node, dst, "SB operation - STORE access"); + + /* Spread taint */ + expr->isTainted = this->taintEngine->taintAssignment(dst, src); + + /* Update the symbolic control flow */ + this->controlFlow_s(inst); + } + + + void riscvSemantics::sd_s(triton::arch::Instruction& inst) { /* 64-bit only */ + // M[x[rs1] + offset] := x[rs2] + auto& src = inst.operands[0]; // rs2 + auto& dst = inst.operands[1]; // rs1 - base, offset - disp + + /* Create symbolic operands */ + auto node = this->symbolicEngine->getOperandAst(inst, src); + + /* Create symbolic expression */ + auto expr = this->symbolicEngine->createSymbolicExpression(inst, node, dst, "SD operation - STORE access"); + + /* Spread taint */ + expr->isTainted = this->taintEngine->taintAssignment(dst, src); + + /* Update the symbolic control flow */ + this->controlFlow_s(inst); + } + + + void riscvSemantics::sh_s(triton::arch::Instruction& inst) { + // M[x[rs1] + offset] := (x[rs2] & 0xffff) + auto& src = inst.operands[0]; // rs2 + auto& dst = inst.operands[1]; // rs1 - base, offset - disp + + /* Create symbolic operands */ + auto node = this->symbolicEngine->getOperandAst(inst, src); + node = this->astCtxt->extract(15, 0, node); + + /* Create symbolic expression */ + auto expr = this->symbolicEngine->createSymbolicExpression(inst, node, dst, "SH operation - STORE access"); + + /* Spread taint */ + expr->isTainted = this->taintEngine->taintAssignment(dst, src); + + /* Update the symbolic control flow */ + this->controlFlow_s(inst); + } + + + void riscvSemantics::sll_s(triton::arch::Instruction& inst) { + auto& dst = inst.operands[0]; + auto& src1 = inst.operands[1]; + auto& src2 = inst.operands[2]; + auto size = src2.getBitSize(); + + /* Create symbolic operands */ + auto bits = size == 64 ? 0x3f : 0x1f; + auto op1 = this->symbolicEngine->getOperandAst(inst, src1); + auto op2 = this->astCtxt->bvand( + this->symbolicEngine->getOperandAst(inst, src2), + this->astCtxt->bv(bits, size) + ); + + /* Create the semantics */ + auto node = this->astCtxt->bvshl(op1, op2); + + /* Create symbolic expression */ + auto expr = this->symbolicEngine->createSymbolicExpression(inst, node, dst, "SLL(I) operation"); + + /* Spread taint */ + expr->isTainted = this->taintEngine->taintUnion(src1, src2); + + /* Update the symbolic control flow */ + this->controlFlow_s(inst); + } + + + void riscvSemantics::sllw_s(triton::arch::Instruction& inst) { /* 64-bit only */ + auto& dst = inst.operands[0]; + auto& src1 = inst.operands[1]; + auto& src2 = inst.operands[2]; + auto size = src2.getBitSize(); + + /* Create symbolic operands */ + auto op1 = this->symbolicEngine->getOperandAst(inst, src1); + auto op2 = this->astCtxt->bvand( + this->symbolicEngine->getOperandAst(inst, src2), + this->astCtxt->bv(0x1f, size) + ); + + /* Create the semantics */ + auto node = this->astCtxt->sx(32, + this->astCtxt->bvshl(this->astCtxt->extract(31, 0, op1), + this->astCtxt->extract(31, 0, op2))); + + /* Create symbolic expression */ + auto expr = this->symbolicEngine->createSymbolicExpression(inst, node, dst, "SLL(I)W operation"); + + /* Spread taint */ + expr->isTainted = this->taintEngine->taintUnion(src1, src2); + + /* Update the symbolic control flow */ + this->controlFlow_s(inst); + } + + + void riscvSemantics::slt_s(triton::arch::Instruction& inst) { + /* Check for possible pseudo instructions + sltz rd, rs -- [slt rd, rs, x0] -- Set if < zero + sgtz rd, rs -- [slt rd, x0, rs] -- Set if > zero + */ + auto mnem = inst.getDisassembly(); + if (mnem[3] == 'z') { + if (mnem[1] == 'l') { slt_sltz_s(inst); } else { slt_sgtz_s(inst); } + } else { + slti_s(inst); + } + } + + + void riscvSemantics::slt_sgtz_s(triton::arch::Instruction& inst) { + auto& dst = inst.operands[0]; + auto& src = inst.operands[1]; + auto size = dst.getBitSize(); + + /* Create symbolic operands */ + auto op1 = this->symbolicEngine->getOperandAst(inst, src); + auto zero = this->astCtxt->bv(0, size); + + /* Create the semantics */ + auto node = this->astCtxt->ite(this->astCtxt->bvsgt(op1, zero), + this->astCtxt->bv(1, size), + zero + ); + + /* Create symbolic expression */ + auto expr = this->symbolicEngine->createSymbolicExpression(inst, node, dst, "SGTZ operation"); + + /* Set condition flag */ + if ((long long)op1->evaluate() > 0) + inst.setConditionTaken(true); + + /* Spread taint */ + expr->isTainted = this->taintEngine->setTaint(dst, this->taintEngine->isTainted(src)); + + /* Update the symbolic control flow */ + this->controlFlow_s(inst); + } + + + void riscvSemantics::slt_sltz_s(triton::arch::Instruction& inst) { + auto& dst = inst.operands[0]; + auto& src = inst.operands[1]; + auto size = dst.getBitSize(); + + /* Create symbolic operands */ + auto op1 = this->symbolicEngine->getOperandAst(inst, src); + auto zero = this->astCtxt->bv(0, size); + + /* Create the semantics */ + auto node = this->astCtxt->ite(this->astCtxt->bvslt(op1, zero), + this->astCtxt->bv(1, size), + zero + ); + + /* Create symbolic expression */ + auto expr = this->symbolicEngine->createSymbolicExpression(inst, node, dst, "SLTZ operation"); + + /* Set condition flag */ + if ((long long)op1->evaluate() < 0) + inst.setConditionTaken(true); + + /* Spread taint */ + expr->isTainted = this->taintEngine->setTaint(dst, this->taintEngine->isTainted(src)); + + /* Update the symbolic control flow */ + this->controlFlow_s(inst); + } + + + void riscvSemantics::slti_s(triton::arch::Instruction& inst) { + auto& dst = inst.operands[0]; + auto& src1 = inst.operands[1]; + auto& src2 = inst.operands[2]; + auto size = dst.getBitSize(); + + /* Create symbolic operands */ + auto op1 = this->symbolicEngine->getOperandAst(inst, src1); + auto op2 = this->symbolicEngine->getOperandAst(inst, src2); + + /* Create the semantics */ + auto node = this->astCtxt->ite(this->astCtxt->bvslt(op1, op2), + this->astCtxt->bv(1, size), + this->astCtxt->bv(0, size) + ); + + /* Create symbolic expression */ + auto expr = this->symbolicEngine->createSymbolicExpression(inst, node, dst, "SLT(I) operation"); + + /* Set condition flag */ + if ((long long)(op2->evaluate() - op1->evaluate()) > 0) + inst.setConditionTaken(true); + + /* Spread taint */ + expr->isTainted = this->taintEngine->setTaint(dst, this->taintEngine->isTainted(src1) | this->taintEngine->isTainted(src2)); + + /* Update the symbolic control flow */ + this->controlFlow_s(inst); + } + + + void riscvSemantics::sltiu_seqz_s(triton::arch::Instruction& inst) { + auto& dst = inst.operands[0]; + auto& src = inst.operands[1]; + auto size = dst.getBitSize(); + + /* Create symbolic operands */ + auto op1 = this->symbolicEngine->getOperandAst(inst, src); + auto zero = this->astCtxt->bv(0, size); + + /* Create the semantics */ + auto node = this->astCtxt->ite(this->astCtxt->equal(op1, zero), + this->astCtxt->bv(1, size), + zero + ); + + /* Create symbolic expression */ + auto expr = this->symbolicEngine->createSymbolicExpression(inst, node, dst, "SEQZ operation"); + + /* Set condition flag */ + if (op1->evaluate() == 0) + inst.setConditionTaken(true); + + /* Spread taint */ + expr->isTainted = this->taintEngine->setTaint(dst, this->taintEngine->isTainted(src)); + + /* Update the symbolic control flow */ + this->controlFlow_s(inst); + } + + + void riscvSemantics::sltu_s(triton::arch::Instruction& inst) { + /* Check for possible pseudo instructions + seqz rd, rs -- [sltiu rd, rs, 1] -- Set if == zero + snez rd, rs -- [sltu rd, x0, rs] -- Set if != zero + */ + auto mnem = inst.getDisassembly(); + if (mnem[1] == 'e') { + sltiu_seqz_s(inst); + return; + } + if (mnem[1] == 'n') { + sltu_snez_s(inst); + return; + } + + auto& dst = inst.operands[0]; + auto& src1 = inst.operands[1]; + auto& src2 = inst.operands[2]; + auto size = dst.getBitSize(); + + /* Create symbolic operands */ + auto op1 = this->symbolicEngine->getOperandAst(inst, src1); + auto op2 = this->symbolicEngine->getOperandAst(inst, src2); + + /* Create the semantics */ + auto node = this->astCtxt->ite(this->astCtxt->bvult(op1, op2), + this->astCtxt->bv(1, size), + this->astCtxt->bv(0, size) + ); + + /* Create symbolic expression */ + auto expr = this->symbolicEngine->createSymbolicExpression(inst, node, dst, "SLT(I)U operation"); + + /* Set condition flag */ + if (op2->evaluate() > op1->evaluate()) + inst.setConditionTaken(true); + + /* Spread taint */ + expr->isTainted = this->taintEngine->setTaint(dst, this->taintEngine->isTainted(src1) | this->taintEngine->isTainted(src2)); + + /* Update the symbolic control flow */ + this->controlFlow_s(inst); + } + + + void riscvSemantics::sltu_snez_s(triton::arch::Instruction& inst) { + auto& dst = inst.operands[0]; + auto& src = inst.operands[1]; + auto size = dst.getBitSize(); + + /* Create symbolic operands */ + auto op1 = this->symbolicEngine->getOperandAst(inst, src); + auto zero = this->astCtxt->bv(0, size); + + /* Create the semantics */ + auto node = this->astCtxt->ite(this->astCtxt->equal(op1, zero), + zero, + this->astCtxt->bv(1, size) + ); + + /* Create symbolic expression */ + auto expr = this->symbolicEngine->createSymbolicExpression(inst, node, dst, "SNEZ operation"); + + /* Set condition flag */ + if (op1->evaluate() != 0) + inst.setConditionTaken(true); + + /* Spread taint */ + expr->isTainted = this->taintEngine->setTaint(dst, this->taintEngine->isTainted(src)); + + /* Update the symbolic control flow */ + this->controlFlow_s(inst); + } + + + void riscvSemantics::sra_s(triton::arch::Instruction& inst) { + auto& dst = inst.operands[0]; + auto& src1 = inst.operands[1]; + auto& src2 = inst.operands[2]; + auto size = src2.getBitSize(); + + /* Create symbolic operands */ + auto bits = size == 64 ? 0x3f : 0x1f; + auto op1 = this->symbolicEngine->getOperandAst(inst, src1); + auto op2 = this->astCtxt->bvand( + this->symbolicEngine->getOperandAst(inst, src2), + this->astCtxt->bv(bits, size) + ); + + /* Create the semantics */ + auto node = this->astCtxt->bvashr(op1, op2); + + /* Create symbolic expression */ + auto expr = this->symbolicEngine->createSymbolicExpression(inst, node, dst, "SRA operation"); + + /* Spread taint */ + expr->isTainted = this->taintEngine->taintUnion(src1, src2); + + /* Update the symbolic control flow */ + this->controlFlow_s(inst); + } + + + void riscvSemantics::sraw_s(triton::arch::Instruction& inst) { /* 64-bit only */ + auto& dst = inst.operands[0]; + auto& src1 = inst.operands[1]; + auto& src2 = inst.operands[2]; + auto size = src2.getBitSize(); + + /* Create symbolic operands */ + auto op1 = this->symbolicEngine->getOperandAst(inst, src1); + auto op2 = this->astCtxt->bvand( + this->symbolicEngine->getOperandAst(inst, src2), + this->astCtxt->bv(0x1f, size) + ); + + /* Create the semantics */ + auto node = this->astCtxt->sx(32, + this->astCtxt->bvashr(this->astCtxt->extract(31, 0, op1), + this->astCtxt->extract(31, 0, op2))); + + /* Create symbolic expression */ + auto expr = this->symbolicEngine->createSymbolicExpression(inst, node, dst, "SRA(I)W operation"); + + /* Spread taint */ + expr->isTainted = this->taintEngine->taintUnion(src1, src2); + + /* Update the symbolic control flow */ + this->controlFlow_s(inst); + } + + + void riscvSemantics::srl_s(triton::arch::Instruction& inst) { + auto& dst = inst.operands[0]; + auto& src1 = inst.operands[1]; + auto& src2 = inst.operands[2]; + auto size = src2.getBitSize(); + + /* Create symbolic operands */ + auto bits = size == 64 ? 0x3f : 0x1f; + auto op1 = this->symbolicEngine->getOperandAst(inst, src1); + auto op2 = this->astCtxt->bvand( + this->symbolicEngine->getOperandAst(inst, src2), + this->astCtxt->bv(bits, size) + ); + + /* Create the semantics */ + auto node = this->astCtxt->bvlshr(op1, op2); + + /* Create symbolic expression */ + auto expr = this->symbolicEngine->createSymbolicExpression(inst, node, dst, "SRL(I) operation"); + + /* Spread taint */ + expr->isTainted = this->taintEngine->taintUnion(src1, src2); + + /* Update the symbolic control flow */ + this->controlFlow_s(inst); + } + + + void riscvSemantics::srlw_s(triton::arch::Instruction& inst) { /* 64-bit only */ + auto& dst = inst.operands[0]; + auto& src1 = inst.operands[1]; + auto& src2 = inst.operands[2]; + auto size = src2.getBitSize(); + + /* Create symbolic operands */ + auto op1 = this->symbolicEngine->getOperandAst(inst, src1); + auto op2 = this->astCtxt->bvand( + this->symbolicEngine->getOperandAst(inst, src2), + this->astCtxt->bv(0x1f, size) + ); + + /* Create the semantics */ + auto node = this->astCtxt->sx(32, + this->astCtxt->bvlshr(this->astCtxt->extract(31, 0, op1), + this->astCtxt->extract(31, 0, op2))); + + /* Create symbolic expression */ + auto expr = this->symbolicEngine->createSymbolicExpression(inst, node, dst, "SRL(I)W operation"); + + /* Spread taint */ + expr->isTainted = this->taintEngine->taintUnion(src1, src2); + + /* Update the symbolic control flow */ + this->controlFlow_s(inst); + } + + + void riscvSemantics::sub_s(triton::arch::Instruction& inst) { + auto& dst = inst.operands[0]; + auto& src1 = inst.operands[1]; + auto size = dst.getBitSize(); + bool fix_taint = false; + + /* Create symbolic operands and semantics */ + auto op1 = this->symbolicEngine->getOperandAst(inst, src1); + auto node = this->astCtxt->bvneg(op1); // neg pseudo instruction semantics + if (inst.operands.size() > 2) { + auto& src2 = inst.operands[2]; + auto op2 = this->symbolicEngine->getOperandAst(inst, src2); + node = this->astCtxt->bvsub(op1, op2); // sub semantics + fix_taint = this->taintEngine->isTainted(src2); + } + + /* Create symbolic expression */ + auto expr = this->symbolicEngine->createSymbolicExpression(inst, node, dst, "SUB operation"); + + /* Spread taint */ + expr->isTainted = this->taintEngine->isTainted(src1) || fix_taint; + + /* Update the symbolic control flow */ + this->controlFlow_s(inst); + } + + + void riscvSemantics::subw_s(triton::arch::Instruction& inst) { /* 64-bit only */ + auto& dst = inst.operands[0]; + auto& src1 = inst.operands[1]; + auto size = dst.getBitSize(); + bool fix_taint = false; + + /* Create symbolic operands and semantics */ + auto op1 = this->astCtxt->extract(31, 0, this->symbolicEngine->getOperandAst(inst, src1)); + auto node = this->astCtxt->sx(32, this->astCtxt->bvneg(op1)); // negw pseudo instruction semantics + if (inst.operands.size() > 2) { + auto& src2 = inst.operands[2]; + auto op2 = this->astCtxt->extract(31, 0, this->symbolicEngine->getOperandAst(inst, src2)); + node = this->astCtxt->sx(32, this->astCtxt->bvsub(op1, op2)); // subw semantics + fix_taint = this->taintEngine->isTainted(src2); + } + + /* Create symbolic expression */ + auto expr = this->symbolicEngine->createSymbolicExpression(inst, node, dst, "SUBW operation"); + + /* Spread taint */ + expr->isTainted = this->taintEngine->isTainted(src1) || fix_taint; + + /* Update the symbolic control flow */ + this->controlFlow_s(inst); + } + + + void riscvSemantics::sw_s(triton::arch::Instruction& inst) { + // M[x[rs1] + offset] := (x[rs2] & 0xffffffff) + auto& src = inst.operands[0]; // rs2 + auto& dst = inst.operands[1]; // rs1 - base, offset - disp + + /* Create symbolic operands and semantics */ + auto node = this->symbolicEngine->getOperandAst(inst, src); + if (src.getBitSize() == 64) { + node = this->astCtxt->extract(31, 0, node); + } + + /* Create symbolic expression */ + auto expr = this->symbolicEngine->createSymbolicExpression(inst, node, dst, "SW operation - STORE access"); + + /* Spread taint */ + expr->isTainted = this->taintEngine->taintAssignment(dst, src); + + /* Update the symbolic control flow */ + this->controlFlow_s(inst); + } + + + void riscvSemantics::xor_s(triton::arch::Instruction& inst) { + auto& dst = inst.operands[0]; + auto& src1 = inst.operands[1]; + auto& src2 = inst.operands[2]; + + /* Create symbolic operands */ + auto op1 = this->symbolicEngine->getOperandAst(inst, src1); + auto op2 = this->symbolicEngine->getOperandAst(inst, src2); + + /* Create the semantics */ + auto node = this->astCtxt->bvxor(op1, op2); + + /* Create symbolic expression */ + auto expr = this->symbolicEngine->createSymbolicExpression(inst, node, dst, "XOR operation"); + + /* Spread taint */ + expr->isTainted = this->taintEngine->setTaint(dst, this->taintEngine->isTainted(src1) | this->taintEngine->isTainted(src2)); + + /* Update the symbolic control flow */ + this->controlFlow_s(inst); + } + + + void riscvSemantics::xori_s(triton::arch::Instruction& inst) { + auto& dst = inst.operands[0]; + auto& src1 = inst.operands[1]; + + /* Create symbolic operands */ + auto op1 = this->symbolicEngine->getOperandAst(inst, src1); + auto node = this->astCtxt->bvnot(op1); // not pseudo instruction semantics + + if (inst.operands.size() > 2) { + auto& src2 = inst.operands[2]; + auto op2 = this->symbolicEngine->getOperandAst(inst, src2); + node = this->astCtxt->bvxor(op1, op2); // xori semantics + } + + /* Create symbolic expression */ + auto expr = this->symbolicEngine->createSymbolicExpression(inst, node, dst, "XORI operation"); + + /* Spread taint */ + expr->isTainted = this->taintEngine->setTaint(dst, this->taintEngine->isTainted(src1)); + + /* Update the symbolic control flow */ + this->controlFlow_s(inst); + } + + }; /* riscv namespace */ + }; /* arch namespace */ +}; /* triton namespace */ diff --git a/src/libtriton/arch/riscv/riscvSpecifications.cpp b/src/libtriton/arch/riscv/riscvSpecifications.cpp new file mode 100644 index 000000000..8173405a8 --- /dev/null +++ b/src/libtriton/arch/riscv/riscvSpecifications.cpp @@ -0,0 +1,1233 @@ +//! \file +/* +** Copyright (C) - Triton +** +** This program is under the terms of the Apache License 2.0. +*/ + +#include + +#include +#include +#include +#include +#include + + + +namespace triton { + namespace arch { + namespace riscv { + + riscvSpecifications::riscvSpecifications(triton::arch::architecture_e arch) { + if (arch != triton::arch::ARCH_RV64 && arch != triton::arch::ARCH_RV32) + throw triton::exceptions::Architecture("riscvSpecifications::riscvSpecifications(): Invalid architecture."); + + if (arch == triton::arch::ARCH_RV64) { + // Fill id2reg and name2id with those available in riscv from spec + #define REG_SPEC(CS_UPPER_NAME, UPPER_NAME, LOWER_NAME, ABI_NAME, RISCV_UPPER, RISCV_LOWER, MUTABLE) \ + id2reg.emplace(ID_REG_RV64_##UPPER_NAME, \ + triton::arch::Register(triton::arch::ID_REG_RV64_##UPPER_NAME, \ + #LOWER_NAME, \ + triton::arch::ID_REG_RV64_##UPPER_NAME, \ + RISCV_UPPER, \ + RISCV_LOWER, \ + MUTABLE) \ + ); \ + name2id.emplace(#LOWER_NAME, ID_REG_RV64_##UPPER_NAME); \ + name2id.emplace(#ABI_NAME, ID_REG_RV64_##UPPER_NAME); + // Handle register not available in capstone as normal registers + #define REG_SPEC_NO_CAPSTONE REG_SPEC + #include "triton/riscv64.spec" + } + else { // RV32 + // Fill id2reg and name2id with those available in riscv32 from spec + #define REG_SPEC(CS_UPPER_NAME, UPPER_NAME, LOWER_NAME, ABI_NAME, RISCV_UPPER, RISCV_LOWER, MUTABLE) \ + id2reg.emplace(ID_REG_RV32_##UPPER_NAME, \ + triton::arch::Register(triton::arch::ID_REG_RV32_##UPPER_NAME, \ + #LOWER_NAME, \ + triton::arch::ID_REG_RV32_##UPPER_NAME, \ + RISCV_UPPER, \ + RISCV_LOWER, \ + MUTABLE) \ + ); \ + name2id.emplace(#LOWER_NAME, ID_REG_RV32_##UPPER_NAME); \ + name2id.emplace(#ABI_NAME, ID_REG_RV32_##UPPER_NAME); + // Handle register not available in capstone as normal registers + #define REG_SPEC_NO_CAPSTONE REG_SPEC + #include "triton/riscv32.spec" + } + } + + + triton::arch::register_e riscvSpecifications::capstoneRegisterToTritonRegister64(triton::uint32 id) const { + triton::arch::register_e tritonId = triton::arch::ID_REG_INVALID; + switch (id) { + // Convert registers from capstone value to triton value + #define REG_SPEC(CS_UPPER_NAME, UPPER_NAME, _1, _2, _3, _4, _5) \ + case triton::extlibs::capstone::RISCV_REG_##CS_UPPER_NAME: \ + tritonId = triton::arch::ID_REG_RV64_##UPPER_NAME; \ + break; + // Ignore registers not available in capstone + #define REG_SPEC_NO_CAPSTONE(_1, _2, _3, _4, _5, _6, _7) + #include "triton/riscv64.spec" + + default: + tritonId = triton::arch::ID_REG_INVALID; + break; + + } + return tritonId; + } + + + triton::arch::register_e riscvSpecifications::capstoneRegisterToTritonRegister32(triton::uint32 id) const { + triton::arch::register_e tritonId = triton::arch::ID_REG_INVALID; + switch (id) { + // Convert registers from capstone value to triton value + #define REG_SPEC(CS_UPPER_NAME, UPPER_NAME, _1, _2, _3, _4, _5) \ + case triton::extlibs::capstone::RISCV_REG_##CS_UPPER_NAME: \ + tritonId = triton::arch::ID_REG_RV32_##UPPER_NAME; \ + break; + // Ignore registers not available in capstone + #define REG_SPEC_NO_CAPSTONE(_1, _2, _3, _4, _5, _6, _7) + #include "triton/riscv32.spec" + + default: + tritonId = triton::arch::ID_REG_INVALID; + break; + + } + return tritonId; + } + + + triton::uint32 riscvSpecifications::capstoneInstructionToTritonInstruction(triton::uint32 id) const { + triton::uint32 tritonId = triton::arch::riscv::ID_INS_INVALID; + + switch (id) { + case triton::extlibs::capstone::RISCV_INS_INVALID: + tritonId = triton::arch::riscv::ID_INS_INVALID; + break; + + case triton::extlibs::capstone::RISCV_INS_ADD: + tritonId = triton::arch::riscv::ID_INS_ADD; + break; + + case triton::extlibs::capstone::RISCV_INS_ADDI: + tritonId = triton::arch::riscv::ID_INS_ADDI; + break; + + case triton::extlibs::capstone::RISCV_INS_ADDIW: + tritonId = triton::arch::riscv::ID_INS_ADDIW; + break; + + case triton::extlibs::capstone::RISCV_INS_ADDW: + tritonId = triton::arch::riscv::ID_INS_ADDW; + break; + + case triton::extlibs::capstone::RISCV_INS_AMOADD_D: + tritonId = triton::arch::riscv::ID_INS_AMOADD_D; + break; + + case triton::extlibs::capstone::RISCV_INS_AMOADD_D_AQ: + tritonId = triton::arch::riscv::ID_INS_AMOADD_D_AQ; + break; + + case triton::extlibs::capstone::RISCV_INS_AMOADD_D_AQ_RL: + tritonId = triton::arch::riscv::ID_INS_AMOADD_D_AQ_RL; + break; + + case triton::extlibs::capstone::RISCV_INS_AMOADD_D_RL: + tritonId = triton::arch::riscv::ID_INS_AMOADD_D_RL; + break; + + case triton::extlibs::capstone::RISCV_INS_AMOADD_W: + tritonId = triton::arch::riscv::ID_INS_AMOADD_W; + break; + + case triton::extlibs::capstone::RISCV_INS_AMOADD_W_AQ: + tritonId = triton::arch::riscv::ID_INS_AMOADD_W_AQ; + break; + + case triton::extlibs::capstone::RISCV_INS_AMOADD_W_AQ_RL: + tritonId = triton::arch::riscv::ID_INS_AMOADD_W_AQ_RL; + break; + + case triton::extlibs::capstone::RISCV_INS_AMOADD_W_RL: + tritonId = triton::arch::riscv::ID_INS_AMOADD_W_RL; + break; + + case triton::extlibs::capstone::RISCV_INS_AMOAND_D: + tritonId = triton::arch::riscv::ID_INS_AMOAND_D; + break; + + case triton::extlibs::capstone::RISCV_INS_AMOAND_D_AQ: + tritonId = triton::arch::riscv::ID_INS_AMOAND_D_AQ; + break; + + case triton::extlibs::capstone::RISCV_INS_AMOAND_D_AQ_RL: + tritonId = triton::arch::riscv::ID_INS_AMOAND_D_AQ_RL; + break; + + case triton::extlibs::capstone::RISCV_INS_AMOAND_D_RL: + tritonId = triton::arch::riscv::ID_INS_AMOAND_D_RL; + break; + + case triton::extlibs::capstone::RISCV_INS_AMOAND_W: + tritonId = triton::arch::riscv::ID_INS_AMOAND_W; + break; + + case triton::extlibs::capstone::RISCV_INS_AMOAND_W_AQ: + tritonId = triton::arch::riscv::ID_INS_AMOAND_W_AQ; + break; + + case triton::extlibs::capstone::RISCV_INS_AMOAND_W_AQ_RL: + tritonId = triton::arch::riscv::ID_INS_AMOAND_W_AQ_RL; + break; + + case triton::extlibs::capstone::RISCV_INS_AMOAND_W_RL: + tritonId = triton::arch::riscv::ID_INS_AMOAND_W_RL; + break; + + case triton::extlibs::capstone::RISCV_INS_AMOMAXU_D: + tritonId = triton::arch::riscv::ID_INS_AMOMAXU_D; + break; + + case triton::extlibs::capstone::RISCV_INS_AMOMAXU_D_AQ: + tritonId = triton::arch::riscv::ID_INS_AMOMAXU_D_AQ; + break; + + case triton::extlibs::capstone::RISCV_INS_AMOMAXU_D_AQ_RL: + tritonId = triton::arch::riscv::ID_INS_AMOMAXU_D_AQ_RL; + break; + + case triton::extlibs::capstone::RISCV_INS_AMOMAXU_D_RL: + tritonId = triton::arch::riscv::ID_INS_AMOMAXU_D_RL; + break; + + case triton::extlibs::capstone::RISCV_INS_AMOMAXU_W: + tritonId = triton::arch::riscv::ID_INS_AMOMAXU_W; + break; + + case triton::extlibs::capstone::RISCV_INS_AMOMAXU_W_AQ: + tritonId = triton::arch::riscv::ID_INS_AMOMAXU_W_AQ; + break; + + case triton::extlibs::capstone::RISCV_INS_AMOMAXU_W_AQ_RL: + tritonId = triton::arch::riscv::ID_INS_AMOMAXU_W_AQ_RL; + break; + + case triton::extlibs::capstone::RISCV_INS_AMOMAXU_W_RL: + tritonId = triton::arch::riscv::ID_INS_AMOMAXU_W_RL; + break; + + case triton::extlibs::capstone::RISCV_INS_AMOMAX_D: + tritonId = triton::arch::riscv::ID_INS_AMOMAX_D; + break; + + case triton::extlibs::capstone::RISCV_INS_AMOMAX_D_AQ: + tritonId = triton::arch::riscv::ID_INS_AMOMAX_D_AQ; + break; + + case triton::extlibs::capstone::RISCV_INS_AMOMAX_D_AQ_RL: + tritonId = triton::arch::riscv::ID_INS_AMOMAX_D_AQ_RL; + break; + + case triton::extlibs::capstone::RISCV_INS_AMOMAX_D_RL: + tritonId = triton::arch::riscv::ID_INS_AMOMAX_D_RL; + break; + + case triton::extlibs::capstone::RISCV_INS_AMOMAX_W: + tritonId = triton::arch::riscv::ID_INS_AMOMAX_W; + break; + + case triton::extlibs::capstone::RISCV_INS_AMOMAX_W_AQ: + tritonId = triton::arch::riscv::ID_INS_AMOMAX_W_AQ; + break; + + case triton::extlibs::capstone::RISCV_INS_AMOMAX_W_AQ_RL: + tritonId = triton::arch::riscv::ID_INS_AMOMAX_W_AQ_RL; + break; + + case triton::extlibs::capstone::RISCV_INS_AMOMAX_W_RL: + tritonId = triton::arch::riscv::ID_INS_AMOMAX_W_RL; + break; + + case triton::extlibs::capstone::RISCV_INS_AMOMINU_D: + tritonId = triton::arch::riscv::ID_INS_AMOMINU_D; + break; + + case triton::extlibs::capstone::RISCV_INS_AMOMINU_D_AQ: + tritonId = triton::arch::riscv::ID_INS_AMOMINU_D_AQ; + break; + + case triton::extlibs::capstone::RISCV_INS_AMOMINU_D_AQ_RL: + tritonId = triton::arch::riscv::ID_INS_AMOMINU_D_AQ_RL; + break; + + case triton::extlibs::capstone::RISCV_INS_AMOMINU_D_RL: + tritonId = triton::arch::riscv::ID_INS_AMOMINU_D_RL; + break; + + case triton::extlibs::capstone::RISCV_INS_AMOMINU_W: + tritonId = triton::arch::riscv::ID_INS_AMOMINU_W; + break; + + case triton::extlibs::capstone::RISCV_INS_AMOMINU_W_AQ: + tritonId = triton::arch::riscv::ID_INS_AMOMINU_W_AQ; + break; + + case triton::extlibs::capstone::RISCV_INS_AMOMINU_W_AQ_RL: + tritonId = triton::arch::riscv::ID_INS_AMOMINU_W_AQ_RL; + break; + + case triton::extlibs::capstone::RISCV_INS_AMOMINU_W_RL: + tritonId = triton::arch::riscv::ID_INS_AMOMINU_W_RL; + break; + + case triton::extlibs::capstone::RISCV_INS_AMOMIN_D: + tritonId = triton::arch::riscv::ID_INS_AMOMIN_D; + break; + + case triton::extlibs::capstone::RISCV_INS_AMOMIN_D_AQ: + tritonId = triton::arch::riscv::ID_INS_AMOMIN_D_AQ; + break; + + case triton::extlibs::capstone::RISCV_INS_AMOMIN_D_AQ_RL: + tritonId = triton::arch::riscv::ID_INS_AMOMIN_D_AQ_RL; + break; + + case triton::extlibs::capstone::RISCV_INS_AMOMIN_D_RL: + tritonId = triton::arch::riscv::ID_INS_AMOMIN_D_RL; + break; + + case triton::extlibs::capstone::RISCV_INS_AMOMIN_W: + tritonId = triton::arch::riscv::ID_INS_AMOMIN_W; + break; + + case triton::extlibs::capstone::RISCV_INS_AMOMIN_W_AQ: + tritonId = triton::arch::riscv::ID_INS_AMOMIN_W_AQ; + break; + + case triton::extlibs::capstone::RISCV_INS_AMOMIN_W_AQ_RL: + tritonId = triton::arch::riscv::ID_INS_AMOMIN_W_AQ_RL; + break; + + case triton::extlibs::capstone::RISCV_INS_AMOMIN_W_RL: + tritonId = triton::arch::riscv::ID_INS_AMOMIN_W_RL; + break; + + case triton::extlibs::capstone::RISCV_INS_AMOOR_D: + tritonId = triton::arch::riscv::ID_INS_AMOOR_D; + break; + + case triton::extlibs::capstone::RISCV_INS_AMOOR_D_AQ: + tritonId = triton::arch::riscv::ID_INS_AMOOR_D_AQ; + break; + + case triton::extlibs::capstone::RISCV_INS_AMOOR_D_AQ_RL: + tritonId = triton::arch::riscv::ID_INS_AMOOR_D_AQ_RL; + break; + + case triton::extlibs::capstone::RISCV_INS_AMOOR_D_RL: + tritonId = triton::arch::riscv::ID_INS_AMOOR_D_RL; + break; + + case triton::extlibs::capstone::RISCV_INS_AMOOR_W: + tritonId = triton::arch::riscv::ID_INS_AMOOR_W; + break; + + case triton::extlibs::capstone::RISCV_INS_AMOOR_W_AQ: + tritonId = triton::arch::riscv::ID_INS_AMOOR_W_AQ; + break; + + case triton::extlibs::capstone::RISCV_INS_AMOOR_W_AQ_RL: + tritonId = triton::arch::riscv::ID_INS_AMOOR_W_AQ_RL; + break; + + case triton::extlibs::capstone::RISCV_INS_AMOOR_W_RL: + tritonId = triton::arch::riscv::ID_INS_AMOOR_W_RL; + break; + + case triton::extlibs::capstone::RISCV_INS_AMOSWAP_D: + tritonId = triton::arch::riscv::ID_INS_AMOSWAP_D; + break; + + case triton::extlibs::capstone::RISCV_INS_AMOSWAP_D_AQ: + tritonId = triton::arch::riscv::ID_INS_AMOSWAP_D_AQ; + break; + + case triton::extlibs::capstone::RISCV_INS_AMOSWAP_D_AQ_RL: + tritonId = triton::arch::riscv::ID_INS_AMOSWAP_D_AQ_RL; + break; + + case triton::extlibs::capstone::RISCV_INS_AMOSWAP_D_RL: + tritonId = triton::arch::riscv::ID_INS_AMOSWAP_D_RL; + break; + + case triton::extlibs::capstone::RISCV_INS_AMOSWAP_W: + tritonId = triton::arch::riscv::ID_INS_AMOSWAP_W; + break; + + case triton::extlibs::capstone::RISCV_INS_AMOSWAP_W_AQ: + tritonId = triton::arch::riscv::ID_INS_AMOSWAP_W_AQ; + break; + + case triton::extlibs::capstone::RISCV_INS_AMOSWAP_W_AQ_RL: + tritonId = triton::arch::riscv::ID_INS_AMOSWAP_W_AQ_RL; + break; + + case triton::extlibs::capstone::RISCV_INS_AMOSWAP_W_RL: + tritonId = triton::arch::riscv::ID_INS_AMOSWAP_W_RL; + break; + + case triton::extlibs::capstone::RISCV_INS_AMOXOR_D: + tritonId = triton::arch::riscv::ID_INS_AMOXOR_D; + break; + + case triton::extlibs::capstone::RISCV_INS_AMOXOR_D_AQ: + tritonId = triton::arch::riscv::ID_INS_AMOXOR_D_AQ; + break; + + case triton::extlibs::capstone::RISCV_INS_AMOXOR_D_AQ_RL: + tritonId = triton::arch::riscv::ID_INS_AMOXOR_D_AQ_RL; + break; + + case triton::extlibs::capstone::RISCV_INS_AMOXOR_D_RL: + tritonId = triton::arch::riscv::ID_INS_AMOXOR_D_RL; + break; + + case triton::extlibs::capstone::RISCV_INS_AMOXOR_W: + tritonId = triton::arch::riscv::ID_INS_AMOXOR_W; + break; + + case triton::extlibs::capstone::RISCV_INS_AMOXOR_W_AQ: + tritonId = triton::arch::riscv::ID_INS_AMOXOR_W_AQ; + break; + + case triton::extlibs::capstone::RISCV_INS_AMOXOR_W_AQ_RL: + tritonId = triton::arch::riscv::ID_INS_AMOXOR_W_AQ_RL; + break; + + case triton::extlibs::capstone::RISCV_INS_AMOXOR_W_RL: + tritonId = triton::arch::riscv::ID_INS_AMOXOR_W_RL; + break; + + case triton::extlibs::capstone::RISCV_INS_AND: + tritonId = triton::arch::riscv::ID_INS_AND; + break; + + case triton::extlibs::capstone::RISCV_INS_ANDI: + tritonId = triton::arch::riscv::ID_INS_ANDI; + break; + + case triton::extlibs::capstone::RISCV_INS_AUIPC: + tritonId = triton::arch::riscv::ID_INS_AUIPC; + break; + + case triton::extlibs::capstone::RISCV_INS_BEQ: + tritonId = triton::arch::riscv::ID_INS_BEQ; + break; + + case triton::extlibs::capstone::RISCV_INS_BGE: + tritonId = triton::arch::riscv::ID_INS_BGE; + break; + + case triton::extlibs::capstone::RISCV_INS_BGEU: + tritonId = triton::arch::riscv::ID_INS_BGEU; + break; + + case triton::extlibs::capstone::RISCV_INS_BLT: + tritonId = triton::arch::riscv::ID_INS_BLT; + break; + + case triton::extlibs::capstone::RISCV_INS_BLTU: + tritonId = triton::arch::riscv::ID_INS_BLTU; + break; + + case triton::extlibs::capstone::RISCV_INS_BNE: + tritonId = triton::arch::riscv::ID_INS_BNE; + break; + + case triton::extlibs::capstone::RISCV_INS_CSRRC: + tritonId = triton::arch::riscv::ID_INS_CSRRC; + break; + + case triton::extlibs::capstone::RISCV_INS_CSRRCI: + tritonId = triton::arch::riscv::ID_INS_CSRRCI; + break; + + case triton::extlibs::capstone::RISCV_INS_CSRRS: + tritonId = triton::arch::riscv::ID_INS_CSRRS; + break; + + case triton::extlibs::capstone::RISCV_INS_CSRRSI: + tritonId = triton::arch::riscv::ID_INS_CSRRSI; + break; + + case triton::extlibs::capstone::RISCV_INS_CSRRW: + tritonId = triton::arch::riscv::ID_INS_CSRRW; + break; + + case triton::extlibs::capstone::RISCV_INS_CSRRWI: + tritonId = triton::arch::riscv::ID_INS_CSRRWI; + break; + /* Compressed instructions */ + case triton::extlibs::capstone::RISCV_INS_C_ADD: + tritonId = triton::arch::riscv::ID_INS_C_ADD; + break; + + case triton::extlibs::capstone::RISCV_INS_C_ADDI: + tritonId = triton::arch::riscv::ID_INS_C_ADDI; + break; + + case triton::extlibs::capstone::RISCV_INS_C_ADDI16SP: + tritonId = triton::arch::riscv::ID_INS_C_ADDI16SP; + break; + + case triton::extlibs::capstone::RISCV_INS_C_ADDI4SPN: + tritonId = triton::arch::riscv::ID_INS_C_ADDI4SPN; + break; + + case triton::extlibs::capstone::RISCV_INS_C_ADDIW: + tritonId = triton::arch::riscv::ID_INS_C_ADDIW; + break; + + case triton::extlibs::capstone::RISCV_INS_C_ADDW: + tritonId = triton::arch::riscv::ID_INS_C_ADDW; + break; + + case triton::extlibs::capstone::RISCV_INS_C_AND: + tritonId = triton::arch::riscv::ID_INS_C_AND; + break; + + case triton::extlibs::capstone::RISCV_INS_C_ANDI: + tritonId = triton::arch::riscv::ID_INS_C_ANDI; + break; + + case triton::extlibs::capstone::RISCV_INS_C_BEQZ: + tritonId = triton::arch::riscv::ID_INS_C_BEQZ; + break; + + case triton::extlibs::capstone::RISCV_INS_C_BNEZ: + tritonId = triton::arch::riscv::ID_INS_C_BNEZ; + break; + + case triton::extlibs::capstone::RISCV_INS_C_EBREAK: + tritonId = triton::arch::riscv::ID_INS_C_EBREAK; + break; + + case triton::extlibs::capstone::RISCV_INS_C_FLD: + tritonId = triton::arch::riscv::ID_INS_C_FLD; + break; + + case triton::extlibs::capstone::RISCV_INS_C_FLDSP: + tritonId = triton::arch::riscv::ID_INS_C_FLDSP; + break; + + case triton::extlibs::capstone::RISCV_INS_C_FLW: + tritonId = triton::arch::riscv::ID_INS_C_FLW; + break; + + case triton::extlibs::capstone::RISCV_INS_C_FLWSP: + tritonId = triton::arch::riscv::ID_INS_C_FLWSP; + break; + + case triton::extlibs::capstone::RISCV_INS_C_FSD: + tritonId = triton::arch::riscv::ID_INS_C_FSD; + break; + + case triton::extlibs::capstone::RISCV_INS_C_FSDSP: + tritonId = triton::arch::riscv::ID_INS_C_FSDSP; + break; + + case triton::extlibs::capstone::RISCV_INS_C_FSW: + tritonId = triton::arch::riscv::ID_INS_C_FSW; + break; + + case triton::extlibs::capstone::RISCV_INS_C_FSWSP: + tritonId = triton::arch::riscv::ID_INS_C_FSWSP; + break; + + case triton::extlibs::capstone::RISCV_INS_C_J: + tritonId = triton::arch::riscv::ID_INS_C_J; + break; + + case triton::extlibs::capstone::RISCV_INS_C_JAL: + tritonId = triton::arch::riscv::ID_INS_C_JAL; + break; + + case triton::extlibs::capstone::RISCV_INS_C_JALR: + tritonId = triton::arch::riscv::ID_INS_C_JALR; + break; + + case triton::extlibs::capstone::RISCV_INS_C_JR: + tritonId = triton::arch::riscv::ID_INS_C_JR; + break; + + case triton::extlibs::capstone::RISCV_INS_C_LD: + tritonId = triton::arch::riscv::ID_INS_C_LD; + break; + + case triton::extlibs::capstone::RISCV_INS_C_LDSP: + tritonId = triton::arch::riscv::ID_INS_C_LDSP; + break; + + case triton::extlibs::capstone::RISCV_INS_C_LI: + tritonId = triton::arch::riscv::ID_INS_C_LI; + break; + + case triton::extlibs::capstone::RISCV_INS_C_LUI: + tritonId = triton::arch::riscv::ID_INS_C_LUI; + break; + + case triton::extlibs::capstone::RISCV_INS_C_LW: + tritonId = triton::arch::riscv::ID_INS_C_LW; + break; + + case triton::extlibs::capstone::RISCV_INS_C_LWSP: + tritonId = triton::arch::riscv::ID_INS_C_LWSP; + break; + + case triton::extlibs::capstone::RISCV_INS_C_MV: + tritonId = triton::arch::riscv::ID_INS_C_MV; + break; + + case triton::extlibs::capstone::RISCV_INS_C_NOP: + tritonId = triton::arch::riscv::ID_INS_C_NOP; + break; + + case triton::extlibs::capstone::RISCV_INS_C_OR: + tritonId = triton::arch::riscv::ID_INS_C_OR; + break; + + case triton::extlibs::capstone::RISCV_INS_C_SD: + tritonId = triton::arch::riscv::ID_INS_C_SD; + break; + + case triton::extlibs::capstone::RISCV_INS_C_SDSP: + tritonId = triton::arch::riscv::ID_INS_C_SDSP; + break; + + case triton::extlibs::capstone::RISCV_INS_C_SLLI: + tritonId = triton::arch::riscv::ID_INS_C_SLLI; + break; + + case triton::extlibs::capstone::RISCV_INS_C_SRAI: + tritonId = triton::arch::riscv::ID_INS_C_SRAI; + break; + + case triton::extlibs::capstone::RISCV_INS_C_SRLI: + tritonId = triton::arch::riscv::ID_INS_C_SRLI; + break; + + case triton::extlibs::capstone::RISCV_INS_C_SUB: + tritonId = triton::arch::riscv::ID_INS_C_SUB; + break; + + case triton::extlibs::capstone::RISCV_INS_C_SUBW: + tritonId = triton::arch::riscv::ID_INS_C_SUBW; + break; + + case triton::extlibs::capstone::RISCV_INS_C_SW: + tritonId = triton::arch::riscv::ID_INS_C_SW; + break; + + case triton::extlibs::capstone::RISCV_INS_C_SWSP: + tritonId = triton::arch::riscv::ID_INS_C_SWSP; + break; + + case triton::extlibs::capstone::RISCV_INS_C_UNIMP: + tritonId = triton::arch::riscv::ID_INS_C_UNIMP; + break; + + case triton::extlibs::capstone::RISCV_INS_C_XOR: + tritonId = triton::arch::riscv::ID_INS_C_XOR; + break; + /* End of compressed instructions */ + case triton::extlibs::capstone::RISCV_INS_DIV: + tritonId = triton::arch::riscv::ID_INS_DIV; + break; + + case triton::extlibs::capstone::RISCV_INS_DIVU: + tritonId = triton::arch::riscv::ID_INS_DIVU; + break; + + case triton::extlibs::capstone::RISCV_INS_DIVUW: + tritonId = triton::arch::riscv::ID_INS_DIVUW; + break; + + case triton::extlibs::capstone::RISCV_INS_DIVW: + tritonId = triton::arch::riscv::ID_INS_DIVW; + break; + + case triton::extlibs::capstone::RISCV_INS_EBREAK: + tritonId = triton::arch::riscv::ID_INS_EBREAK; + break; + + case triton::extlibs::capstone::RISCV_INS_ECALL: + tritonId = triton::arch::riscv::ID_INS_ECALL; + break; + + case triton::extlibs::capstone::RISCV_INS_FADD_D: + tritonId = triton::arch::riscv::ID_INS_FADD_D; + break; + + case triton::extlibs::capstone::RISCV_INS_FADD_S: + tritonId = triton::arch::riscv::ID_INS_FADD_S; + break; + + case triton::extlibs::capstone::RISCV_INS_FCLASS_D: + tritonId = triton::arch::riscv::ID_INS_FCLASS_D; + break; + + case triton::extlibs::capstone::RISCV_INS_FCLASS_S: + tritonId = triton::arch::riscv::ID_INS_FCLASS_S; + break; + + case triton::extlibs::capstone::RISCV_INS_FCVT_D_L: + tritonId = triton::arch::riscv::ID_INS_FCVT_D_L; + break; + + case triton::extlibs::capstone::RISCV_INS_FCVT_D_LU: + tritonId = triton::arch::riscv::ID_INS_FCVT_D_LU; + break; + + case triton::extlibs::capstone::RISCV_INS_FCVT_D_S: + tritonId = triton::arch::riscv::ID_INS_FCVT_D_S; + break; + + case triton::extlibs::capstone::RISCV_INS_FCVT_D_W: + tritonId = triton::arch::riscv::ID_INS_FCVT_D_W; + break; + + case triton::extlibs::capstone::RISCV_INS_FCVT_D_WU: + tritonId = triton::arch::riscv::ID_INS_FCVT_D_WU; + break; + + case triton::extlibs::capstone::RISCV_INS_FCVT_LU_D: + tritonId = triton::arch::riscv::ID_INS_FCVT_LU_D; + break; + + case triton::extlibs::capstone::RISCV_INS_FCVT_LU_S: + tritonId = triton::arch::riscv::ID_INS_FCVT_LU_S; + break; + + case triton::extlibs::capstone::RISCV_INS_FCVT_L_D: + tritonId = triton::arch::riscv::ID_INS_FCVT_L_D; + break; + + case triton::extlibs::capstone::RISCV_INS_FCVT_L_S: + tritonId = triton::arch::riscv::ID_INS_FCVT_L_S; + break; + + case triton::extlibs::capstone::RISCV_INS_FCVT_S_D: + tritonId = triton::arch::riscv::ID_INS_FCVT_S_D; + break; + + case triton::extlibs::capstone::RISCV_INS_FCVT_S_L: + tritonId = triton::arch::riscv::ID_INS_FCVT_S_L; + break; + + case triton::extlibs::capstone::RISCV_INS_FCVT_S_LU: + tritonId = triton::arch::riscv::ID_INS_FCVT_S_LU; + break; + + case triton::extlibs::capstone::RISCV_INS_FCVT_S_W: + tritonId = triton::arch::riscv::ID_INS_FCVT_S_W; + break; + + case triton::extlibs::capstone::RISCV_INS_FCVT_S_WU: + tritonId = triton::arch::riscv::ID_INS_FCVT_S_WU; + break; + + case triton::extlibs::capstone::RISCV_INS_FCVT_WU_D: + tritonId = triton::arch::riscv::ID_INS_FCVT_WU_D; + break; + + case triton::extlibs::capstone::RISCV_INS_FCVT_WU_S: + tritonId = triton::arch::riscv::ID_INS_FCVT_WU_S; + break; + + case triton::extlibs::capstone::RISCV_INS_FCVT_W_D: + tritonId = triton::arch::riscv::ID_INS_FCVT_W_D; + break; + + case triton::extlibs::capstone::RISCV_INS_FCVT_W_S: + tritonId = triton::arch::riscv::ID_INS_FCVT_W_S; + break; + + case triton::extlibs::capstone::RISCV_INS_FDIV_D: + tritonId = triton::arch::riscv::ID_INS_FDIV_D; + break; + + case triton::extlibs::capstone::RISCV_INS_FDIV_S: + tritonId = triton::arch::riscv::ID_INS_FDIV_S; + break; + + case triton::extlibs::capstone::RISCV_INS_FENCE: + tritonId = triton::arch::riscv::ID_INS_FENCE; + break; + + case triton::extlibs::capstone::RISCV_INS_FENCE_I: + tritonId = triton::arch::riscv::ID_INS_FENCE_I; + break; + + case triton::extlibs::capstone::RISCV_INS_FENCE_TSO: + tritonId = triton::arch::riscv::ID_INS_FENCE_TSO; + break; + + case triton::extlibs::capstone::RISCV_INS_FEQ_D: + tritonId = triton::arch::riscv::ID_INS_FEQ_D; + break; + + case triton::extlibs::capstone::RISCV_INS_FEQ_S: + tritonId = triton::arch::riscv::ID_INS_FEQ_S; + break; + + case triton::extlibs::capstone::RISCV_INS_FLD: + tritonId = triton::arch::riscv::ID_INS_FLD; + break; + + case triton::extlibs::capstone::RISCV_INS_FLE_D: + tritonId = triton::arch::riscv::ID_INS_FLE_D; + break; + + case triton::extlibs::capstone::RISCV_INS_FLE_S: + tritonId = triton::arch::riscv::ID_INS_FLE_S; + break; + + case triton::extlibs::capstone::RISCV_INS_FLT_D: + tritonId = triton::arch::riscv::ID_INS_FLT_D; + break; + + case triton::extlibs::capstone::RISCV_INS_FLT_S: + tritonId = triton::arch::riscv::ID_INS_FLT_S; + break; + + case triton::extlibs::capstone::RISCV_INS_FLW: + tritonId = triton::arch::riscv::ID_INS_FLW; + break; + + case triton::extlibs::capstone::RISCV_INS_FMADD_D: + tritonId = triton::arch::riscv::ID_INS_FMADD_D; + break; + + case triton::extlibs::capstone::RISCV_INS_FMADD_S: + tritonId = triton::arch::riscv::ID_INS_FMADD_S; + break; + + case triton::extlibs::capstone::RISCV_INS_FMAX_D: + tritonId = triton::arch::riscv::ID_INS_FMAX_D; + break; + + case triton::extlibs::capstone::RISCV_INS_FMAX_S: + tritonId = triton::arch::riscv::ID_INS_FMAX_S; + break; + + case triton::extlibs::capstone::RISCV_INS_FMIN_D: + tritonId = triton::arch::riscv::ID_INS_FMIN_D; + break; + + case triton::extlibs::capstone::RISCV_INS_FMIN_S: + tritonId = triton::arch::riscv::ID_INS_FMIN_S; + break; + + case triton::extlibs::capstone::RISCV_INS_FMSUB_D: + tritonId = triton::arch::riscv::ID_INS_FMSUB_D; + break; + + case triton::extlibs::capstone::RISCV_INS_FMSUB_S: + tritonId = triton::arch::riscv::ID_INS_FMSUB_S; + break; + + case triton::extlibs::capstone::RISCV_INS_FMUL_D: + tritonId = triton::arch::riscv::ID_INS_FMUL_D; + break; + + case triton::extlibs::capstone::RISCV_INS_FMUL_S: + tritonId = triton::arch::riscv::ID_INS_FMUL_S; + break; + + case triton::extlibs::capstone::RISCV_INS_FMV_D_X: + tritonId = triton::arch::riscv::ID_INS_FMV_D_X; + break; + + case triton::extlibs::capstone::RISCV_INS_FMV_W_X: + tritonId = triton::arch::riscv::ID_INS_FMV_W_X; + break; + + case triton::extlibs::capstone::RISCV_INS_FMV_X_D: + tritonId = triton::arch::riscv::ID_INS_FMV_X_D; + break; + + case triton::extlibs::capstone::RISCV_INS_FMV_X_W: + tritonId = triton::arch::riscv::ID_INS_FMV_X_W; + break; + + case triton::extlibs::capstone::RISCV_INS_FNMADD_D: + tritonId = triton::arch::riscv::ID_INS_FNMADD_D; + break; + + case triton::extlibs::capstone::RISCV_INS_FNMADD_S: + tritonId = triton::arch::riscv::ID_INS_FNMADD_S; + break; + + case triton::extlibs::capstone::RISCV_INS_FNMSUB_D: + tritonId = triton::arch::riscv::ID_INS_FNMSUB_D; + break; + + case triton::extlibs::capstone::RISCV_INS_FNMSUB_S: + tritonId = triton::arch::riscv::ID_INS_FNMSUB_S; + break; + + case triton::extlibs::capstone::RISCV_INS_FSD: + tritonId = triton::arch::riscv::ID_INS_FSD; + break; + + case triton::extlibs::capstone::RISCV_INS_FSGNJN_D: + tritonId = triton::arch::riscv::ID_INS_FSGNJN_D; + break; + + case triton::extlibs::capstone::RISCV_INS_FSGNJN_S: + tritonId = triton::arch::riscv::ID_INS_FSGNJN_S; + break; + + case triton::extlibs::capstone::RISCV_INS_FSGNJX_D: + tritonId = triton::arch::riscv::ID_INS_FSGNJX_D; + break; + + case triton::extlibs::capstone::RISCV_INS_FSGNJX_S: + tritonId = triton::arch::riscv::ID_INS_FSGNJX_S; + break; + + case triton::extlibs::capstone::RISCV_INS_FSGNJ_D: + tritonId = triton::arch::riscv::ID_INS_FSGNJ_D; + break; + + case triton::extlibs::capstone::RISCV_INS_FSGNJ_S: + tritonId = triton::arch::riscv::ID_INS_FSGNJ_S; + break; + + case triton::extlibs::capstone::RISCV_INS_FSQRT_D: + tritonId = triton::arch::riscv::ID_INS_FSQRT_D; + break; + + case triton::extlibs::capstone::RISCV_INS_FSQRT_S: + tritonId = triton::arch::riscv::ID_INS_FSQRT_S; + break; + + case triton::extlibs::capstone::RISCV_INS_FSUB_D: + tritonId = triton::arch::riscv::ID_INS_FSUB_D; + break; + + case triton::extlibs::capstone::RISCV_INS_FSUB_S: + tritonId = triton::arch::riscv::ID_INS_FSUB_S; + break; + + case triton::extlibs::capstone::RISCV_INS_FSW: + tritonId = triton::arch::riscv::ID_INS_FSW; + break; + + case triton::extlibs::capstone::RISCV_INS_JAL: + tritonId = triton::arch::riscv::ID_INS_JAL; + break; + + case triton::extlibs::capstone::RISCV_INS_JALR: + tritonId = triton::arch::riscv::ID_INS_JALR; + break; + + case triton::extlibs::capstone::RISCV_INS_LB: + tritonId = triton::arch::riscv::ID_INS_LB; + break; + + case triton::extlibs::capstone::RISCV_INS_LBU: + tritonId = triton::arch::riscv::ID_INS_LBU; + break; + + case triton::extlibs::capstone::RISCV_INS_LD: + tritonId = triton::arch::riscv::ID_INS_LD; + break; + + case triton::extlibs::capstone::RISCV_INS_LH: + tritonId = triton::arch::riscv::ID_INS_LH; + break; + + case triton::extlibs::capstone::RISCV_INS_LHU: + tritonId = triton::arch::riscv::ID_INS_LHU; + break; + + case triton::extlibs::capstone::RISCV_INS_LR_D: + tritonId = triton::arch::riscv::ID_INS_LR_D; + break; + + case triton::extlibs::capstone::RISCV_INS_LR_D_AQ: + tritonId = triton::arch::riscv::ID_INS_LR_D_AQ; + break; + + case triton::extlibs::capstone::RISCV_INS_LR_D_AQ_RL: + tritonId = triton::arch::riscv::ID_INS_LR_D_AQ_RL; + break; + + case triton::extlibs::capstone::RISCV_INS_LR_D_RL: + tritonId = triton::arch::riscv::ID_INS_LR_D_RL; + break; + + case triton::extlibs::capstone::RISCV_INS_LR_W: + tritonId = triton::arch::riscv::ID_INS_LR_W; + break; + + case triton::extlibs::capstone::RISCV_INS_LR_W_AQ: + tritonId = triton::arch::riscv::ID_INS_LR_W_AQ; + break; + + case triton::extlibs::capstone::RISCV_INS_LR_W_AQ_RL: + tritonId = triton::arch::riscv::ID_INS_LR_W_AQ_RL; + break; + + case triton::extlibs::capstone::RISCV_INS_LR_W_RL: + tritonId = triton::arch::riscv::ID_INS_LR_W_RL; + break; + + case triton::extlibs::capstone::RISCV_INS_LUI: + tritonId = triton::arch::riscv::ID_INS_LUI; + break; + + case triton::extlibs::capstone::RISCV_INS_LW: + tritonId = triton::arch::riscv::ID_INS_LW; + break; + + case triton::extlibs::capstone::RISCV_INS_LWU: + tritonId = triton::arch::riscv::ID_INS_LWU; + break; + + case triton::extlibs::capstone::RISCV_INS_MRET: + tritonId = triton::arch::riscv::ID_INS_MRET; + break; + + case triton::extlibs::capstone::RISCV_INS_MUL: + tritonId = triton::arch::riscv::ID_INS_MUL; + break; + + case triton::extlibs::capstone::RISCV_INS_MULH: + tritonId = triton::arch::riscv::ID_INS_MULH; + break; + + case triton::extlibs::capstone::RISCV_INS_MULHSU: + tritonId = triton::arch::riscv::ID_INS_MULHSU; + break; + + case triton::extlibs::capstone::RISCV_INS_MULHU: + tritonId = triton::arch::riscv::ID_INS_MULHU; + break; + + case triton::extlibs::capstone::RISCV_INS_MULW: + tritonId = triton::arch::riscv::ID_INS_MULW; + break; + + case triton::extlibs::capstone::RISCV_INS_OR: + tritonId = triton::arch::riscv::ID_INS_OR; + break; + + case triton::extlibs::capstone::RISCV_INS_ORI: + tritonId = triton::arch::riscv::ID_INS_ORI; + break; + + case triton::extlibs::capstone::RISCV_INS_REM: + tritonId = triton::arch::riscv::ID_INS_REM; + break; + + case triton::extlibs::capstone::RISCV_INS_REMU: + tritonId = triton::arch::riscv::ID_INS_REMU; + break; + + case triton::extlibs::capstone::RISCV_INS_REMUW: + tritonId = triton::arch::riscv::ID_INS_REMUW; + break; + + case triton::extlibs::capstone::RISCV_INS_REMW: + tritonId = triton::arch::riscv::ID_INS_REMW; + break; + + case triton::extlibs::capstone::RISCV_INS_SB: + tritonId = triton::arch::riscv::ID_INS_SB; + break; + + case triton::extlibs::capstone::RISCV_INS_SC_D: + tritonId = triton::arch::riscv::ID_INS_SC_D; + break; + + case triton::extlibs::capstone::RISCV_INS_SC_D_AQ: + tritonId = triton::arch::riscv::ID_INS_SC_D_AQ; + break; + + case triton::extlibs::capstone::RISCV_INS_SC_D_AQ_RL: + tritonId = triton::arch::riscv::ID_INS_SC_D_AQ_RL; + break; + + case triton::extlibs::capstone::RISCV_INS_SC_D_RL: + tritonId = triton::arch::riscv::ID_INS_SC_D_RL; + break; + + case triton::extlibs::capstone::RISCV_INS_SC_W: + tritonId = triton::arch::riscv::ID_INS_SC_W; + break; + + case triton::extlibs::capstone::RISCV_INS_SC_W_AQ: + tritonId = triton::arch::riscv::ID_INS_SC_W_AQ; + break; + + case triton::extlibs::capstone::RISCV_INS_SC_W_AQ_RL: + tritonId = triton::arch::riscv::ID_INS_SC_W_AQ_RL; + break; + + case triton::extlibs::capstone::RISCV_INS_SC_W_RL: + tritonId = triton::arch::riscv::ID_INS_SC_W_RL; + break; + + case triton::extlibs::capstone::RISCV_INS_SD: + tritonId = triton::arch::riscv::ID_INS_SD; + break; + + case triton::extlibs::capstone::RISCV_INS_SFENCE_VMA: + tritonId = triton::arch::riscv::ID_INS_SFENCE_VMA; + break; + + case triton::extlibs::capstone::RISCV_INS_SH: + tritonId = triton::arch::riscv::ID_INS_SH; + break; + + case triton::extlibs::capstone::RISCV_INS_SLL: + tritonId = triton::arch::riscv::ID_INS_SLL; + break; + + case triton::extlibs::capstone::RISCV_INS_SLLI: + tritonId = triton::arch::riscv::ID_INS_SLLI; + break; + + case triton::extlibs::capstone::RISCV_INS_SLLIW: + tritonId = triton::arch::riscv::ID_INS_SLLIW; + break; + + case triton::extlibs::capstone::RISCV_INS_SLLW: + tritonId = triton::arch::riscv::ID_INS_SLLW; + break; + + case triton::extlibs::capstone::RISCV_INS_SLT: + tritonId = triton::arch::riscv::ID_INS_SLT; + break; + + case triton::extlibs::capstone::RISCV_INS_SLTI: + tritonId = triton::arch::riscv::ID_INS_SLTI; + break; + + case triton::extlibs::capstone::RISCV_INS_SLTIU: + tritonId = triton::arch::riscv::ID_INS_SLTIU; + break; + + case triton::extlibs::capstone::RISCV_INS_SLTU: + tritonId = triton::arch::riscv::ID_INS_SLTU; + break; + + case triton::extlibs::capstone::RISCV_INS_SRA: + tritonId = triton::arch::riscv::ID_INS_SRA; + break; + + case triton::extlibs::capstone::RISCV_INS_SRAI: + tritonId = triton::arch::riscv::ID_INS_SRAI; + break; + + case triton::extlibs::capstone::RISCV_INS_SRAIW: + tritonId = triton::arch::riscv::ID_INS_SRAIW; + break; + + case triton::extlibs::capstone::RISCV_INS_SRAW: + tritonId = triton::arch::riscv::ID_INS_SRAW; + break; + + case triton::extlibs::capstone::RISCV_INS_SRET: + tritonId = triton::arch::riscv::ID_INS_SRET; + break; + + case triton::extlibs::capstone::RISCV_INS_SRL: + tritonId = triton::arch::riscv::ID_INS_SRL; + break; + + case triton::extlibs::capstone::RISCV_INS_SRLI: + tritonId = triton::arch::riscv::ID_INS_SRLI; + break; + + case triton::extlibs::capstone::RISCV_INS_SRLIW: + tritonId = triton::arch::riscv::ID_INS_SRLIW; + break; + + case triton::extlibs::capstone::RISCV_INS_SRLW: + tritonId = triton::arch::riscv::ID_INS_SRLW; + break; + + case triton::extlibs::capstone::RISCV_INS_SUB: + tritonId = triton::arch::riscv::ID_INS_SUB; + break; + + case triton::extlibs::capstone::RISCV_INS_SUBW: + tritonId = triton::arch::riscv::ID_INS_SUBW; + break; + + case triton::extlibs::capstone::RISCV_INS_SW: + tritonId = triton::arch::riscv::ID_INS_SW; + break; + + case triton::extlibs::capstone::RISCV_INS_UNIMP: + tritonId = ID_INS_UNIMP; + break; + + case triton::extlibs::capstone::RISCV_INS_URET: + tritonId = ID_INS_URET; + break; + + case triton::extlibs::capstone::RISCV_INS_WFI: + tritonId = ID_INS_WFI; + break; + + case triton::extlibs::capstone::RISCV_INS_XOR: + tritonId = ID_INS_XOR; + break; + + case triton::extlibs::capstone::RISCV_INS_XORI: + tritonId = ID_INS_XORI; + break; + default: + tritonId = triton::arch::riscv::ID_INS_INVALID; + break; + } + + return tritonId; + } + + + triton::uint32 riscvSpecifications::getMemoryOperandSpecialSize(triton::uint32 id) const { + switch (id) { + case ID_INS_LB: + case ID_INS_LBU: + case ID_INS_SB: + return 1; + case ID_INS_LH: + case ID_INS_LHU: + case ID_INS_SH: + return 2; + case ID_INS_LW: + case ID_INS_LWU: + case ID_INS_SW: + return 4; + case ID_INS_LD: + case ID_INS_SD: + return 8; + default: + return 0; + } + } + + }; /* riscv namespace */ + }; /* arch namespace */ +}; /* triton namespace */ diff --git a/src/libtriton/bindings/python/namespaces/initArchNamespace.cpp b/src/libtriton/bindings/python/namespaces/initArchNamespace.cpp index 2f7a9b644..63ce23e08 100644 --- a/src/libtriton/bindings/python/namespaces/initArchNamespace.cpp +++ b/src/libtriton/bindings/python/namespaces/initArchNamespace.cpp @@ -27,6 +27,8 @@ The ARCH namespace contains all kinds of architecture supported by Triton. - **ARCH.AARCH64** - **ARCH.ARM32** +- **ARCH.RV32** +- **ARCH.RV64** - **ARCH.X86** - **ARCH.X86_64** @@ -41,6 +43,10 @@ namespace triton { void initArchNamespace(PyObject* archDict) { xPyDict_SetItemString(archDict, "AARCH64", PyLong_FromUint32(triton::arch::ARCH_AARCH64)); xPyDict_SetItemString(archDict, "ARM32", PyLong_FromUint32(triton::arch::ARCH_ARM32)); + #ifdef COMPILE_RISCV + xPyDict_SetItemString(archDict, "RV32", PyLong_FromUint32(triton::arch::ARCH_RV32)); + xPyDict_SetItemString(archDict, "RV64", PyLong_FromUint32(triton::arch::ARCH_RV64)); + #endif xPyDict_SetItemString(archDict, "X86", PyLong_FromUint32(triton::arch::ARCH_X86)); xPyDict_SetItemString(archDict, "X86_64", PyLong_FromUint32(triton::arch::ARCH_X86_64)); } diff --git a/src/libtriton/bindings/python/namespaces/initOpcodesNamespace.cpp b/src/libtriton/bindings/python/namespaces/initOpcodesNamespace.cpp index 1ddd415ee..6ac617789 100644 --- a/src/libtriton/bindings/python/namespaces/initOpcodesNamespace.cpp +++ b/src/libtriton/bindings/python/namespaces/initOpcodesNamespace.cpp @@ -10,6 +10,9 @@ #include #include #include +#ifdef COMPILE_RISCV +#include +#endif #include @@ -2179,6 +2182,180 @@ According to the CPU architecture, the OPCODE namespace contains all kinds of op - **OPCODE.AARCH64.ZIP1**
    - **OPCODE.AARCH64.ZIP2**
    +\subsection OPCODE_riscv64_py_api RV64 + +- **OPCODE.RV64.ADD**
    +- **OPCODE.RV64.ADDI**
    +- **OPCODE.RV64.ADDIW**
    +- **OPCODE.RV64.ADDW**
    +- **OPCODE.RV64.AND**
    +- **OPCODE.RV64.ANDI**
    +- **OPCODE.RV64.AND**
    +- **OPCODE.RV64.AUIPC**
    +- **OPCODE.RV64.BEQ**
    +- **OPCODE.RV64.BGE**
    +- **OPCODE.RV64.BGEU**
    +- **OPCODE.RV64.BLT**
    +- **OPCODE.RV64.BLTU**
    +- **OPCODE.RV64.BNE**
    +- **OPCODE.RV64.C_ADD**
    +- **OPCODE.RV64.C_ADDI**
    +- **OPCODE.RV64.C_ADDI16SP**
    +- **OPCODE.RV64.C_ADDI4SPN**
    +- **OPCODE.RV64.C_ADDIW**
    +- **OPCODE.RV64.C_ADDW**
    +- **OPCODE.RV64.C_AND**
    +- **OPCODE.RV64.C_ANDI**
    +- **OPCODE.RV64.C_BEQZ**
    +- **OPCODE.RV64.C_BNEZ**
    +- **OPCODE.RV64.C_J**
    +- **OPCODE.RV64.C_JALR**
    +- **OPCODE.RV64.C_JR**
    +- **OPCODE.RV64.C_LD**
    +- **OPCODE.RV64.C_LDSP**
    +- **OPCODE.RV64.C_LI**
    +- **OPCODE.RV64.C_LUI**
    +- **OPCODE.RV64.C_LW**
    +- **OPCODE.RV64.C_LWSP**
    +- **OPCODE.RV64.C_MV**
    +- **OPCODE.RV64.C_NOP**
    +- **OPCODE.RV64.C_OR**
    +- **OPCODE.RV64.C_SD**
    +- **OPCODE.RV64.C_SDSP**
    +- **OPCODE.RV64.C_SLLI**
    +- **OPCODE.RV64.C_SRAI**
    +- **OPCODE.RV64.C_SRLI**
    +- **OPCODE.RV64.C_SUB**
    +- **OPCODE.RV64.C_SUBW**
    +- **OPCODE.RV64.C_SW**
    +- **OPCODE.RV64.C_SWSP**
    +- **OPCODE.RV64.C_XOR**
    +- **OPCODE.RV64.DIV**
    +- **OPCODE.RV64.DIVU**
    +- **OPCODE.RV64.DIVUW**
    +- **OPCODE.RV64.DIVW**
    +- **OPCODE.RV64.JAL**
    +- **OPCODE.RV64.JALR**
    +- **OPCODE.RV64.LB**
    +- **OPCODE.RV64.LBU**
    +- **OPCODE.RV64.LD**
    +- **OPCODE.RV64.LH**
    +- **OPCODE.RV64.LHU**
    +- **OPCODE.RV64.LUI**
    +- **OPCODE.RV64.LW**
    +- **OPCODE.RV64.LWU**
    +- **OPCODE.RV64.MUL**
    +- **OPCODE.RV64.MULH**
    +- **OPCODE.RV64.MULHSU**
    +- **OPCODE.RV64.MULHU**
    +- **OPCODE.RV64.MULW**
    +- **OPCODE.RV64.OR**
    +- **OPCODE.RV64.ORI**
    +- **OPCODE.RV64.REM**
    +- **OPCODE.RV64.REMU**
    +- **OPCODE.RV64.REMUW**
    +- **OPCODE.RV64.REMW**
    +- **OPCODE.RV64.SB**
    +- **OPCODE.RV64.SD**
    +- **OPCODE.RV64.SH**
    +- **OPCODE.RV64.SLL**
    +- **OPCODE.RV64.SLLI**
    +- **OPCODE.RV64.SLLIW**
    +- **OPCODE.RV64.SLLW**
    +- **OPCODE.RV64.SLT**
    +- **OPCODE.RV64.SLTI**
    +- **OPCODE.RV64.SLTIU**
    +- **OPCODE.RV64.SLTU**
    +- **OPCODE.RV64.SRA**
    +- **OPCODE.RV64.SRAI**
    +- **OPCODE.RV64.SRAIW**
    +- **OPCODE.RV64.SRAW**
    +- **OPCODE.RV64.SRL**
    +- **OPCODE.RV64.SRLI**
    +- **OPCODE.RV64.SRLIW**
    +- **OPCODE.RV64.SRLW**
    +- **OPCODE.RV64.SUB**
    +- **OPCODE.RV64.SUBW**
    +- **OPCODE.RV64.SW**
    +- **OPCODE.RV64.XOR**
    +- **OPCODE.RV64.XORI**
    + +\subsection OPCODE_riscv32_py_api RV32 + +- **OPCODE.RV32.ADD**
    +- **OPCODE.RV32.ADDI**
    +- **OPCODE.RV32.AND**
    +- **OPCODE.RV32.ANDI**
    +- **OPCODE.RV32.AND**
    +- **OPCODE.RV32.AUIPC**
    +- **OPCODE.RV32.BEQ**
    +- **OPCODE.RV32.BGE**
    +- **OPCODE.RV32.BGEU**
    +- **OPCODE.RV32.BLT**
    +- **OPCODE.RV32.BLTU**
    +- **OPCODE.RV32.BNE**
    +- **OPCODE.RV32.C_ADD**
    +- **OPCODE.RV32.C_ADDI**
    +- **OPCODE.RV32.C_ADDI16SP**
    +- **OPCODE.RV32.C_ADDI4SPN**
    +- **OPCODE.RV32.C_AND**
    +- **OPCODE.RV32.C_ANDI**
    +- **OPCODE.RV32.C_BEQZ**
    +- **OPCODE.RV32.C_BNEZ**
    +- **OPCODE.RV32.C_J**
    +- **OPCODE.RV32.C_JAL**
    +- **OPCODE.RV32.C_JALR**
    +- **OPCODE.RV32.C_JR**
    +- **OPCODE.RV32.C_LI**
    +- **OPCODE.RV32.C_LUI**
    +- **OPCODE.RV32.C_LW**
    +- **OPCODE.RV32.C_LWSP**
    +- **OPCODE.RV32.C_MV**
    +- **OPCODE.RV32.C_NOP**
    +- **OPCODE.RV32.C_OR**
    +- **OPCODE.RV32.C_SLLI**
    +- **OPCODE.RV32.C_SRAI**
    +- **OPCODE.RV32.C_SRLI**
    +- **OPCODE.RV32.C_SUB**
    +- **OPCODE.RV32.C_SW**
    +- **OPCODE.RV32.C_SWSP**
    +- **OPCODE.RV32.C_XOR**
    +- **OPCODE.RV32.DIV**
    +- **OPCODE.RV32.DIVU**
    +- **OPCODE.RV32.JAL**
    +- **OPCODE.RV32.JALR**
    +- **OPCODE.RV32.LB**
    +- **OPCODE.RV32.LBU**
    +- **OPCODE.RV32.LD**
    +- **OPCODE.RV32.LH**
    +- **OPCODE.RV32.LHU**
    +- **OPCODE.RV32.LUI**
    +- **OPCODE.RV32.LW**
    +- **OPCODE.RV32.MUL**
    +- **OPCODE.RV32.MULH**
    +- **OPCODE.RV32.MULHS**
    +- **OPCODE.RV32.MULHU**
    +- **OPCODE.RV32.OR**
    +- **OPCODE.RV32.ORI**
    +- **OPCODE.RV32.REM**
    +- **OPCODE.RV32.REMU**
    +- **OPCODE.RV32.SB**
    +- **OPCODE.RV32.SH**
    +- **OPCODE.RV32.SLL**
    +- **OPCODE.RV32.SLLI**
    +- **OPCODE.RV32.SLT**
    +- **OPCODE.RV32.SLTI**
    +- **OPCODE.RV32.SLTIU**
    +- **OPCODE.RV32.SLTU**
    +- **OPCODE.RV32.SRA**
    +- **OPCODE.RV32.SRAI**
    +- **OPCODE.RV32.SRL**
    +- **OPCODE.RV32.SRLI**
    +- **OPCODE.RV32.SUB**
    +- **OPCODE.RV32.SW**
    +- **OPCODE.RV32.XOR**
    +- **OPCODE.RV32.XORI**
    + */ @@ -4350,6 +4527,192 @@ namespace triton { PyObject* arm32OpcodesDictClass = xPyClass_New(nullptr, arm32OpcodesDict, xPyString_FromString("ARM32")); xPyDict_SetItemString(opcodesDict, "ARM32", arm32OpcodesDictClass); + + + #ifdef COMPILE_RISCV + PyObject* riscv64OpcodesDict = xPyDict_New(); + + xPyDict_SetItemString(riscv64OpcodesDict, "ADD", PyLong_FromUint32(triton::arch::riscv::ID_INS_ADD)); + xPyDict_SetItemString(riscv64OpcodesDict, "ADDI", PyLong_FromUint32(triton::arch::riscv::ID_INS_ADDI)); + xPyDict_SetItemString(riscv64OpcodesDict, "ADDIW", PyLong_FromUint32(triton::arch::riscv::ID_INS_ADDIW)); + xPyDict_SetItemString(riscv64OpcodesDict, "ADDW", PyLong_FromUint32(triton::arch::riscv::ID_INS_ADDW)); + xPyDict_SetItemString(riscv64OpcodesDict, "AND", PyLong_FromUint32(triton::arch::riscv::ID_INS_AND)); + xPyDict_SetItemString(riscv64OpcodesDict, "ANDI", PyLong_FromUint32(triton::arch::riscv::ID_INS_ANDI)); + xPyDict_SetItemString(riscv64OpcodesDict, "AND", PyLong_FromUint32(triton::arch::riscv::ID_INS_AND)); + xPyDict_SetItemString(riscv64OpcodesDict, "AUIPC", PyLong_FromUint32(triton::arch::riscv::ID_INS_AUIPC)); + xPyDict_SetItemString(riscv64OpcodesDict, "BEQ", PyLong_FromUint32(triton::arch::riscv::ID_INS_BEQ)); + xPyDict_SetItemString(riscv64OpcodesDict, "BGE", PyLong_FromUint32(triton::arch::riscv::ID_INS_BGE)); + xPyDict_SetItemString(riscv64OpcodesDict, "BGEU", PyLong_FromUint32(triton::arch::riscv::ID_INS_BGEU)); + xPyDict_SetItemString(riscv64OpcodesDict, "BLT", PyLong_FromUint32(triton::arch::riscv::ID_INS_BLT)); + xPyDict_SetItemString(riscv64OpcodesDict, "BLTU", PyLong_FromUint32(triton::arch::riscv::ID_INS_BLTU)); + xPyDict_SetItemString(riscv64OpcodesDict, "BNE", PyLong_FromUint32(triton::arch::riscv::ID_INS_BNE)); + xPyDict_SetItemString(riscv64OpcodesDict, "DIV", PyLong_FromUint32(triton::arch::riscv::ID_INS_DIV)); + xPyDict_SetItemString(riscv64OpcodesDict, "DIVU", PyLong_FromUint32(triton::arch::riscv::ID_INS_DIVU)); + xPyDict_SetItemString(riscv64OpcodesDict, "DIVUW", PyLong_FromUint32(triton::arch::riscv::ID_INS_DIVUW)); + xPyDict_SetItemString(riscv64OpcodesDict, "DIVW", PyLong_FromUint32(triton::arch::riscv::ID_INS_DIVW)); + xPyDict_SetItemString(riscv64OpcodesDict, "JAL", PyLong_FromUint32(triton::arch::riscv::ID_INS_JAL)); + xPyDict_SetItemString(riscv64OpcodesDict, "JALR", PyLong_FromUint32(triton::arch::riscv::ID_INS_JALR)); + xPyDict_SetItemString(riscv64OpcodesDict, "LB", PyLong_FromUint32(triton::arch::riscv::ID_INS_LB)); + xPyDict_SetItemString(riscv64OpcodesDict, "LBU", PyLong_FromUint32(triton::arch::riscv::ID_INS_LBU)); + xPyDict_SetItemString(riscv64OpcodesDict, "LD", PyLong_FromUint32(triton::arch::riscv::ID_INS_LD)); + xPyDict_SetItemString(riscv64OpcodesDict, "LH", PyLong_FromUint32(triton::arch::riscv::ID_INS_LH)); + xPyDict_SetItemString(riscv64OpcodesDict, "LHU", PyLong_FromUint32(triton::arch::riscv::ID_INS_LHU)); + xPyDict_SetItemString(riscv64OpcodesDict, "LUI", PyLong_FromUint32(triton::arch::riscv::ID_INS_LUI)); + xPyDict_SetItemString(riscv64OpcodesDict, "LW", PyLong_FromUint32(triton::arch::riscv::ID_INS_LW)); + xPyDict_SetItemString(riscv64OpcodesDict, "LWU", PyLong_FromUint32(triton::arch::riscv::ID_INS_LWU)); + xPyDict_SetItemString(riscv64OpcodesDict, "MUL", PyLong_FromUint32(triton::arch::riscv::ID_INS_MUL)); + xPyDict_SetItemString(riscv64OpcodesDict, "MULH ", PyLong_FromUint32(triton::arch::riscv::ID_INS_MULH)); + xPyDict_SetItemString(riscv64OpcodesDict, "MULHSU", PyLong_FromUint32(triton::arch::riscv::ID_INS_MULHSU)); + xPyDict_SetItemString(riscv64OpcodesDict, "MULHU", PyLong_FromUint32(triton::arch::riscv::ID_INS_MULHU)); + xPyDict_SetItemString(riscv64OpcodesDict, "MULW", PyLong_FromUint32(triton::arch::riscv::ID_INS_MULW)); + xPyDict_SetItemString(riscv64OpcodesDict, "OR", PyLong_FromUint32(triton::arch::riscv::ID_INS_OR)); + xPyDict_SetItemString(riscv64OpcodesDict, "ORI", PyLong_FromUint32(triton::arch::riscv::ID_INS_ORI)); + xPyDict_SetItemString(riscv64OpcodesDict, "REM", PyLong_FromUint32(triton::arch::riscv::ID_INS_REM)); + xPyDict_SetItemString(riscv64OpcodesDict, "REMU", PyLong_FromUint32(triton::arch::riscv::ID_INS_REMU)); + xPyDict_SetItemString(riscv64OpcodesDict, "REMUW", PyLong_FromUint32(triton::arch::riscv::ID_INS_REMUW)); + xPyDict_SetItemString(riscv64OpcodesDict, "REMW", PyLong_FromUint32(triton::arch::riscv::ID_INS_REMW)); + xPyDict_SetItemString(riscv64OpcodesDict, "SB", PyLong_FromUint32(triton::arch::riscv::ID_INS_SB)); + xPyDict_SetItemString(riscv64OpcodesDict, "SD", PyLong_FromUint32(triton::arch::riscv::ID_INS_SD)); + xPyDict_SetItemString(riscv64OpcodesDict, "SH", PyLong_FromUint32(triton::arch::riscv::ID_INS_SH)); + xPyDict_SetItemString(riscv64OpcodesDict, "SLL", PyLong_FromUint32(triton::arch::riscv::ID_INS_SLL)); + xPyDict_SetItemString(riscv64OpcodesDict, "SLLI", PyLong_FromUint32(triton::arch::riscv::ID_INS_SLLI)); + xPyDict_SetItemString(riscv64OpcodesDict, "SLLIW", PyLong_FromUint32(triton::arch::riscv::ID_INS_SLLIW)); + xPyDict_SetItemString(riscv64OpcodesDict, "SLLW", PyLong_FromUint32(triton::arch::riscv::ID_INS_SLLW)); + xPyDict_SetItemString(riscv64OpcodesDict, "SLT", PyLong_FromUint32(triton::arch::riscv::ID_INS_SLT)); + xPyDict_SetItemString(riscv64OpcodesDict, "SLTI", PyLong_FromUint32(triton::arch::riscv::ID_INS_SLTI)); + xPyDict_SetItemString(riscv64OpcodesDict, "SLTIU", PyLong_FromUint32(triton::arch::riscv::ID_INS_SLTIU)); + xPyDict_SetItemString(riscv64OpcodesDict, "SLTU", PyLong_FromUint32(triton::arch::riscv::ID_INS_SLTU)); + xPyDict_SetItemString(riscv64OpcodesDict, "SRA", PyLong_FromUint32(triton::arch::riscv::ID_INS_SRA)); + xPyDict_SetItemString(riscv64OpcodesDict, "SRAI", PyLong_FromUint32(triton::arch::riscv::ID_INS_SRAI)); + xPyDict_SetItemString(riscv64OpcodesDict, "SRAIW", PyLong_FromUint32(triton::arch::riscv::ID_INS_SRAIW)); + xPyDict_SetItemString(riscv64OpcodesDict, "SRAW", PyLong_FromUint32(triton::arch::riscv::ID_INS_SRAW)); + xPyDict_SetItemString(riscv64OpcodesDict, "SRL", PyLong_FromUint32(triton::arch::riscv::ID_INS_SRL)); + xPyDict_SetItemString(riscv64OpcodesDict, "SRLI", PyLong_FromUint32(triton::arch::riscv::ID_INS_SRLI)); + xPyDict_SetItemString(riscv64OpcodesDict, "SRLIW", PyLong_FromUint32(triton::arch::riscv::ID_INS_SRLIW)); + xPyDict_SetItemString(riscv64OpcodesDict, "SRLW", PyLong_FromUint32(triton::arch::riscv::ID_INS_SRLW)); + xPyDict_SetItemString(riscv64OpcodesDict, "SUB", PyLong_FromUint32(triton::arch::riscv::ID_INS_SUB)); + xPyDict_SetItemString(riscv64OpcodesDict, "SUBW", PyLong_FromUint32(triton::arch::riscv::ID_INS_SUBW)); + xPyDict_SetItemString(riscv64OpcodesDict, "SW", PyLong_FromUint32(triton::arch::riscv::ID_INS_SW)); + xPyDict_SetItemString(riscv64OpcodesDict, "XOR", PyLong_FromUint32(triton::arch::riscv::ID_INS_XOR)); + xPyDict_SetItemString(riscv64OpcodesDict, "XORI", PyLong_FromUint32(triton::arch::riscv::ID_INS_XORI)); + + xPyDict_SetItemString(riscv64OpcodesDict, "C_ADD", PyLong_FromUint32(triton::arch::riscv::ID_INS_C_ADD)); + xPyDict_SetItemString(riscv64OpcodesDict, "C_ADDI", PyLong_FromUint32(triton::arch::riscv::ID_INS_C_ADDI)); + xPyDict_SetItemString(riscv64OpcodesDict, "C_ADDI16SP", PyLong_FromUint32(triton::arch::riscv::ID_INS_C_ADDI16SP)); + xPyDict_SetItemString(riscv64OpcodesDict, "C_ADDI4SPN", PyLong_FromUint32(triton::arch::riscv::ID_INS_C_ADDI4SPN)); + xPyDict_SetItemString(riscv64OpcodesDict, "C_ADDIW", PyLong_FromUint32(triton::arch::riscv::ID_INS_C_ADDIW)); + xPyDict_SetItemString(riscv64OpcodesDict, "C_ADDW", PyLong_FromUint32(triton::arch::riscv::ID_INS_C_ADDW)); + xPyDict_SetItemString(riscv64OpcodesDict, "C_AND", PyLong_FromUint32(triton::arch::riscv::ID_INS_C_AND)); + xPyDict_SetItemString(riscv64OpcodesDict, "C_ANDI", PyLong_FromUint32(triton::arch::riscv::ID_INS_C_ANDI)); + xPyDict_SetItemString(riscv64OpcodesDict, "C_BEQZ", PyLong_FromUint32(triton::arch::riscv::ID_INS_C_BEQZ)); + xPyDict_SetItemString(riscv64OpcodesDict, "C_BNEZ", PyLong_FromUint32(triton::arch::riscv::ID_INS_C_BNEZ)); + xPyDict_SetItemString(riscv64OpcodesDict, "C_J", PyLong_FromUint32(triton::arch::riscv::ID_INS_C_J)); + xPyDict_SetItemString(riscv64OpcodesDict, "C_JALR", PyLong_FromUint32(triton::arch::riscv::ID_INS_C_JALR)); + xPyDict_SetItemString(riscv64OpcodesDict, "C_JR", PyLong_FromUint32(triton::arch::riscv::ID_INS_C_JR)); + xPyDict_SetItemString(riscv64OpcodesDict, "C_LD", PyLong_FromUint32(triton::arch::riscv::ID_INS_C_LD)); + xPyDict_SetItemString(riscv64OpcodesDict, "C_LDSP", PyLong_FromUint32(triton::arch::riscv::ID_INS_C_LDSP)); + xPyDict_SetItemString(riscv64OpcodesDict, "C_LI", PyLong_FromUint32(triton::arch::riscv::ID_INS_C_LI)); + xPyDict_SetItemString(riscv64OpcodesDict, "C_LUI", PyLong_FromUint32(triton::arch::riscv::ID_INS_C_LUI)); + xPyDict_SetItemString(riscv64OpcodesDict, "C_LW", PyLong_FromUint32(triton::arch::riscv::ID_INS_C_LW)); + xPyDict_SetItemString(riscv64OpcodesDict, "C_LWSP", PyLong_FromUint32(triton::arch::riscv::ID_INS_C_LWSP)); + xPyDict_SetItemString(riscv64OpcodesDict, "C_MV", PyLong_FromUint32(triton::arch::riscv::ID_INS_C_MV)); + xPyDict_SetItemString(riscv64OpcodesDict, "C_NOP ", PyLong_FromUint32(triton::arch::riscv::ID_INS_C_NOP)); + xPyDict_SetItemString(riscv64OpcodesDict, "C_OR", PyLong_FromUint32(triton::arch::riscv::ID_INS_C_OR)); + xPyDict_SetItemString(riscv64OpcodesDict, "C_SD", PyLong_FromUint32(triton::arch::riscv::ID_INS_C_SD)); + xPyDict_SetItemString(riscv64OpcodesDict, "C_SDSP", PyLong_FromUint32(triton::arch::riscv::ID_INS_C_SDSP)); + xPyDict_SetItemString(riscv64OpcodesDict, "C_SLLI", PyLong_FromUint32(triton::arch::riscv::ID_INS_C_SLLI)); + xPyDict_SetItemString(riscv64OpcodesDict, "C_SRAI", PyLong_FromUint32(triton::arch::riscv::ID_INS_C_SRAI)); + xPyDict_SetItemString(riscv64OpcodesDict, "C_SRLI", PyLong_FromUint32(triton::arch::riscv::ID_INS_C_SRLI)); + xPyDict_SetItemString(riscv64OpcodesDict, "C_SUB", PyLong_FromUint32(triton::arch::riscv::ID_INS_C_SUB)); + xPyDict_SetItemString(riscv64OpcodesDict, "C_SUBW", PyLong_FromUint32(triton::arch::riscv::ID_INS_C_SUBW)); + xPyDict_SetItemString(riscv64OpcodesDict, "C_SW", PyLong_FromUint32(triton::arch::riscv::ID_INS_C_SW)); + xPyDict_SetItemString(riscv64OpcodesDict, "C_SWSP", PyLong_FromUint32(triton::arch::riscv::ID_INS_C_SWSP)); + xPyDict_SetItemString(riscv64OpcodesDict, "C_XOR", PyLong_FromUint32(triton::arch::riscv::ID_INS_C_XOR)); + + PyObject* riscv64OpcodesDictClass = xPyClass_New(nullptr, riscv64OpcodesDict, xPyString_FromString("RV64")); + xPyDict_SetItemString(opcodesDict, "RV64", riscv64OpcodesDictClass); + + + PyObject* riscv32OpcodesDict = xPyDict_New(); + + xPyDict_SetItemString(riscv32OpcodesDict, "ADD", PyLong_FromUint32(triton::arch::riscv::ID_INS_ADD)); + xPyDict_SetItemString(riscv32OpcodesDict, "ADDI", PyLong_FromUint32(triton::arch::riscv::ID_INS_ADDI)); + xPyDict_SetItemString(riscv32OpcodesDict, "AND", PyLong_FromUint32(triton::arch::riscv::ID_INS_AND)); + xPyDict_SetItemString(riscv32OpcodesDict, "ANDI", PyLong_FromUint32(triton::arch::riscv::ID_INS_ANDI)); + xPyDict_SetItemString(riscv32OpcodesDict, "AND", PyLong_FromUint32(triton::arch::riscv::ID_INS_AND)); + xPyDict_SetItemString(riscv32OpcodesDict, "AUIPC", PyLong_FromUint32(triton::arch::riscv::ID_INS_AUIPC)); + xPyDict_SetItemString(riscv32OpcodesDict, "BEQ", PyLong_FromUint32(triton::arch::riscv::ID_INS_BEQ)); + xPyDict_SetItemString(riscv32OpcodesDict, "BGE", PyLong_FromUint32(triton::arch::riscv::ID_INS_BGE)); + xPyDict_SetItemString(riscv32OpcodesDict, "BGEU", PyLong_FromUint32(triton::arch::riscv::ID_INS_BGEU)); + xPyDict_SetItemString(riscv32OpcodesDict, "BLT", PyLong_FromUint32(triton::arch::riscv::ID_INS_BLT)); + xPyDict_SetItemString(riscv32OpcodesDict, "BLTU", PyLong_FromUint32(triton::arch::riscv::ID_INS_BLTU)); + xPyDict_SetItemString(riscv32OpcodesDict, "BNE", PyLong_FromUint32(triton::arch::riscv::ID_INS_BNE)); + xPyDict_SetItemString(riscv32OpcodesDict, "DIV", PyLong_FromUint32(triton::arch::riscv::ID_INS_DIV)); + xPyDict_SetItemString(riscv32OpcodesDict, "DIVU", PyLong_FromUint32(triton::arch::riscv::ID_INS_DIVU)); + xPyDict_SetItemString(riscv32OpcodesDict, "JAL", PyLong_FromUint32(triton::arch::riscv::ID_INS_JAL)); + xPyDict_SetItemString(riscv32OpcodesDict, "JALR", PyLong_FromUint32(triton::arch::riscv::ID_INS_JALR)); + xPyDict_SetItemString(riscv32OpcodesDict, "LB", PyLong_FromUint32(triton::arch::riscv::ID_INS_LB)); + xPyDict_SetItemString(riscv32OpcodesDict, "LBU", PyLong_FromUint32(triton::arch::riscv::ID_INS_LBU)); + xPyDict_SetItemString(riscv32OpcodesDict, "LD", PyLong_FromUint32(triton::arch::riscv::ID_INS_LD)); + xPyDict_SetItemString(riscv32OpcodesDict, "LH", PyLong_FromUint32(triton::arch::riscv::ID_INS_LH)); + xPyDict_SetItemString(riscv32OpcodesDict, "LHU", PyLong_FromUint32(triton::arch::riscv::ID_INS_LHU)); + xPyDict_SetItemString(riscv32OpcodesDict, "LUI", PyLong_FromUint32(triton::arch::riscv::ID_INS_LUI)); + xPyDict_SetItemString(riscv32OpcodesDict, "LW", PyLong_FromUint32(triton::arch::riscv::ID_INS_LW)); + xPyDict_SetItemString(riscv32OpcodesDict, "MUL", PyLong_FromUint32(triton::arch::riscv::ID_INS_MUL)); + xPyDict_SetItemString(riscv32OpcodesDict, "MULH ", PyLong_FromUint32(triton::arch::riscv::ID_INS_MULH)); + xPyDict_SetItemString(riscv32OpcodesDict, "MULHSU", PyLong_FromUint32(triton::arch::riscv::ID_INS_MULHSU)); + xPyDict_SetItemString(riscv32OpcodesDict, "MULHU", PyLong_FromUint32(triton::arch::riscv::ID_INS_MULHU)); + xPyDict_SetItemString(riscv32OpcodesDict, "OR", PyLong_FromUint32(triton::arch::riscv::ID_INS_OR)); + xPyDict_SetItemString(riscv32OpcodesDict, "ORI", PyLong_FromUint32(triton::arch::riscv::ID_INS_ORI)); + xPyDict_SetItemString(riscv32OpcodesDict, "REM", PyLong_FromUint32(triton::arch::riscv::ID_INS_REM)); + xPyDict_SetItemString(riscv32OpcodesDict, "REMU", PyLong_FromUint32(triton::arch::riscv::ID_INS_REMU)); + xPyDict_SetItemString(riscv32OpcodesDict, "SB", PyLong_FromUint32(triton::arch::riscv::ID_INS_SB)); + xPyDict_SetItemString(riscv32OpcodesDict, "SH", PyLong_FromUint32(triton::arch::riscv::ID_INS_SH)); + xPyDict_SetItemString(riscv32OpcodesDict, "SLL", PyLong_FromUint32(triton::arch::riscv::ID_INS_SLL)); + xPyDict_SetItemString(riscv32OpcodesDict, "SLLI", PyLong_FromUint32(triton::arch::riscv::ID_INS_SLLI)); + xPyDict_SetItemString(riscv32OpcodesDict, "SLT", PyLong_FromUint32(triton::arch::riscv::ID_INS_SLT)); + xPyDict_SetItemString(riscv32OpcodesDict, "SLTI", PyLong_FromUint32(triton::arch::riscv::ID_INS_SLTI)); + xPyDict_SetItemString(riscv32OpcodesDict, "SLTIU", PyLong_FromUint32(triton::arch::riscv::ID_INS_SLTIU)); + xPyDict_SetItemString(riscv32OpcodesDict, "SLTU", PyLong_FromUint32(triton::arch::riscv::ID_INS_SLTU)); + xPyDict_SetItemString(riscv32OpcodesDict, "SRA", PyLong_FromUint32(triton::arch::riscv::ID_INS_SRA)); + xPyDict_SetItemString(riscv32OpcodesDict, "SRAI", PyLong_FromUint32(triton::arch::riscv::ID_INS_SRAI)); + xPyDict_SetItemString(riscv32OpcodesDict, "SRL", PyLong_FromUint32(triton::arch::riscv::ID_INS_SRL)); + xPyDict_SetItemString(riscv32OpcodesDict, "SRLI", PyLong_FromUint32(triton::arch::riscv::ID_INS_SRLI)); + xPyDict_SetItemString(riscv32OpcodesDict, "SUB", PyLong_FromUint32(triton::arch::riscv::ID_INS_SUB)); + xPyDict_SetItemString(riscv32OpcodesDict, "SW", PyLong_FromUint32(triton::arch::riscv::ID_INS_SW)); + xPyDict_SetItemString(riscv32OpcodesDict, "XOR", PyLong_FromUint32(triton::arch::riscv::ID_INS_XOR)); + xPyDict_SetItemString(riscv32OpcodesDict, "XORI", PyLong_FromUint32(triton::arch::riscv::ID_INS_XORI)); + + xPyDict_SetItemString(riscv32OpcodesDict, "C_ADD", PyLong_FromUint32(triton::arch::riscv::ID_INS_C_ADD)); + xPyDict_SetItemString(riscv32OpcodesDict, "C_ADDI", PyLong_FromUint32(triton::arch::riscv::ID_INS_C_ADDI)); + xPyDict_SetItemString(riscv32OpcodesDict, "C_ADDI16SP", PyLong_FromUint32(triton::arch::riscv::ID_INS_C_ADDI16SP)); + xPyDict_SetItemString(riscv32OpcodesDict, "C_ADDI4SPN", PyLong_FromUint32(triton::arch::riscv::ID_INS_C_ADDI4SPN)); + xPyDict_SetItemString(riscv32OpcodesDict, "C_AND", PyLong_FromUint32(triton::arch::riscv::ID_INS_C_AND)); + xPyDict_SetItemString(riscv32OpcodesDict, "C_ANDI", PyLong_FromUint32(triton::arch::riscv::ID_INS_C_ANDI)); + xPyDict_SetItemString(riscv32OpcodesDict, "C_BEQZ", PyLong_FromUint32(triton::arch::riscv::ID_INS_C_BEQZ)); + xPyDict_SetItemString(riscv32OpcodesDict, "C_BNEZ", PyLong_FromUint32(triton::arch::riscv::ID_INS_C_BNEZ)); + xPyDict_SetItemString(riscv32OpcodesDict, "C_J", PyLong_FromUint32(triton::arch::riscv::ID_INS_C_J)); + xPyDict_SetItemString(riscv32OpcodesDict, "C_JAL", PyLong_FromUint32(triton::arch::riscv::ID_INS_C_JAL)); + xPyDict_SetItemString(riscv32OpcodesDict, "C_JALR", PyLong_FromUint32(triton::arch::riscv::ID_INS_C_JALR)); + xPyDict_SetItemString(riscv32OpcodesDict, "C_JR", PyLong_FromUint32(triton::arch::riscv::ID_INS_C_JR)); + xPyDict_SetItemString(riscv32OpcodesDict, "C_LI", PyLong_FromUint32(triton::arch::riscv::ID_INS_C_LI)); + xPyDict_SetItemString(riscv32OpcodesDict, "C_LUI", PyLong_FromUint32(triton::arch::riscv::ID_INS_C_LUI)); + xPyDict_SetItemString(riscv32OpcodesDict, "C_LW", PyLong_FromUint32(triton::arch::riscv::ID_INS_C_LW)); + xPyDict_SetItemString(riscv32OpcodesDict, "C_LWSP", PyLong_FromUint32(triton::arch::riscv::ID_INS_C_LWSP)); + xPyDict_SetItemString(riscv32OpcodesDict, "C_MV", PyLong_FromUint32(triton::arch::riscv::ID_INS_C_MV)); + xPyDict_SetItemString(riscv32OpcodesDict, "C_NOP ", PyLong_FromUint32(triton::arch::riscv::ID_INS_C_NOP)); + xPyDict_SetItemString(riscv32OpcodesDict, "C_OR", PyLong_FromUint32(triton::arch::riscv::ID_INS_C_OR)); + xPyDict_SetItemString(riscv32OpcodesDict, "C_SLLI", PyLong_FromUint32(triton::arch::riscv::ID_INS_C_SLLI)); + xPyDict_SetItemString(riscv32OpcodesDict, "C_SRAI", PyLong_FromUint32(triton::arch::riscv::ID_INS_C_SRAI)); + xPyDict_SetItemString(riscv32OpcodesDict, "C_SRLI", PyLong_FromUint32(triton::arch::riscv::ID_INS_C_SRLI)); + xPyDict_SetItemString(riscv32OpcodesDict, "C_SUB", PyLong_FromUint32(triton::arch::riscv::ID_INS_C_SUB)); + xPyDict_SetItemString(riscv32OpcodesDict, "C_SW", PyLong_FromUint32(triton::arch::riscv::ID_INS_C_SW)); + xPyDict_SetItemString(riscv32OpcodesDict, "C_SWSP", PyLong_FromUint32(triton::arch::riscv::ID_INS_C_SWSP)); + xPyDict_SetItemString(riscv32OpcodesDict, "C_XOR", PyLong_FromUint32(triton::arch::riscv::ID_INS_C_XOR)); + + PyObject* riscv32OpcodesDictClass = xPyClass_New(nullptr, riscv32OpcodesDict, xPyString_FromString("RV32")); + xPyDict_SetItemString(opcodesDict, "RV32", riscv32OpcodesDictClass); + #endif } }; /* python namespace */ diff --git a/src/libtriton/bindings/python/namespaces/initRegNamespace.cpp b/src/libtriton/bindings/python/namespaces/initRegNamespace.cpp index ea40886c1..579d7772a 100644 --- a/src/libtriton/bindings/python/namespaces/initRegNamespace.cpp +++ b/src/libtriton/bindings/python/namespaces/initRegNamespace.cpp @@ -67,6 +67,14 @@ zmm1:512 bv[511..0] \htmlinclude aarch64_reg +\subsection REG_RV32_py_api riscv32 registers + +\htmlinclude rv32_reg + +\subsection REG_RV64_py_api riscv64 registers + +\htmlinclude rv64_reg + */ @@ -131,6 +139,36 @@ namespace triton { PyObject* arm32RegistersDictClass = xPyClass_New(nullptr, arm32RegistersDict, xPyString_FromString("ARM32")); xPyDict_SetItemString(registersDict, "ARM32", arm32RegistersDictClass); + + #ifdef COMPILE_RISCV + // Create RISCV64 REG namespace + + PyObject* riscv64RegistersDict = xPyDict_New(); + + #define REG_SPEC(_0, UPPER_NAME, _1, _2, _3, _4, _5) \ + xPyDict_SetItemString(riscv64RegistersDict, #UPPER_NAME, PyLong_FromUint32(triton::arch::ID_REG_RV64_##UPPER_NAME)); + // Use REG not available in capstone as normal register + #define REG_SPEC_NO_CAPSTONE REG_SPEC + #define SYS_REG_SPEC REG_SPEC + #include "triton/riscv64.spec" + + PyObject* riscv64RegistersDictClass = xPyClass_New(nullptr, riscv64RegistersDict, xPyString_FromString("RV64")); + xPyDict_SetItemString(registersDict, "RV64", riscv64RegistersDictClass); + + // Create RISCV32 REG namespace + + PyObject* riscv32RegistersDict = xPyDict_New(); + + #define REG_SPEC(_0, UPPER_NAME, _1, _2, _3, _4, _5) \ + xPyDict_SetItemString(riscv32RegistersDict, #UPPER_NAME, PyLong_FromUint32(triton::arch::ID_REG_RV32_##UPPER_NAME)); + // Use REG not available in capstone as normal register + #define REG_SPEC_NO_CAPSTONE REG_SPEC + #define SYS_REG_SPEC REG_SPEC + #include "triton/riscv32.spec" + + PyObject* riscv32RegistersDictClass = xPyClass_New(nullptr, riscv32RegistersDict, xPyString_FromString("RV32")); + xPyDict_SetItemString(registersDict, "RV32", riscv32RegistersDictClass); + #endif } }; /* python namespace */ diff --git a/src/libtriton/context/context.cpp b/src/libtriton/context/context.cpp index d325b99d3..392692ded 100644 --- a/src/libtriton/context/context.cpp +++ b/src/libtriton/context/context.cpp @@ -10,6 +10,10 @@ #include #include #include +#ifdef COMPILE_RISCV +#include +#include +#endif #include #include @@ -462,6 +466,14 @@ namespace triton { case triton::arch::ARCH_AARCH64: *static_cast(this->getCpuInstance()) = *static_cast(other.getCpuInstance()); break; + #ifdef COMPILE_RISCV + case triton::arch::ARCH_RV64: + *static_cast(this->getCpuInstance()) = *static_cast(other.getCpuInstance()); + break; + case triton::arch::ARCH_RV32: + *static_cast(this->getCpuInstance()) = *static_cast(other.getCpuInstance()); + break; + #endif default: throw triton::exceptions::Engines("Context::setConcreteState(): Invalid architecture."); } diff --git a/src/libtriton/includes/triton/archEnums.hpp b/src/libtriton/includes/triton/archEnums.hpp index 2ec4f07ce..5bdf24c3e 100644 --- a/src/libtriton/includes/triton/archEnums.hpp +++ b/src/libtriton/includes/triton/archEnums.hpp @@ -33,6 +33,10 @@ namespace triton { ARCH_INVALID = 0, /*!< Invalid architecture. */ ARCH_AARCH64, /*!< AArch64 architecture. */ ARCH_ARM32, /*!< ARM32 architecture. */ + #ifdef COMPILE_RISCV + ARCH_RV32, /*!< RISCV32 architecture. */ + ARCH_RV64, /*!< RISCV64 architecture. */ + #endif ARCH_X86, /*!< X86 architecture. */ ARCH_X86_64, /*!< X86_64 architecture. */ }; @@ -80,6 +84,18 @@ namespace triton { #define REG_SPEC_NO_CAPSTONE REG_SPEC #include "triton/arm32.spec" + #ifdef COMPILE_RISCV + #define REG_SPEC(_1, UPPER_NAME, _2, _3, _4, _5, _6) \ + ID_REG_RV64_##UPPER_NAME, + #define REG_SPEC_NO_CAPSTONE REG_SPEC + #include "triton/riscv64.spec" + + #define REG_SPEC(_1, UPPER_NAME, _2, _3, _4, _5, _6) \ + ID_REG_RV32_##UPPER_NAME, + #define REG_SPEC_NO_CAPSTONE REG_SPEC + #include "triton/riscv32.spec" + #endif + /* Must be the last item */ ID_REG_LAST_ITEM //!< must be the last item }; @@ -193,6 +209,58 @@ namespace triton { /*! @} End of arm namespace */ }; + + #ifdef COMPILE_RISCV + //! The riscv namespace + namespace riscv { + /*! + * \ingroup arch + * \addtogroup riscv + * @{ + */ + + //! Groups of RISCV instructions. */ + enum insn_group_e { + ID_GRP_INVALID = 0, //!< invalid + /* Generic groups */ + ID_GRP_JUMP, //!< JUMP (all jump instructions: conditional+direct+indirect jumps) + ID_GRP_CALL, //!< CALL + ID_GRP_RET, //!< RET + ID_GRP_INT, //!< all interrupt instructions (int+syscall) + ID_GRP_IRET, //!< all interrupt return instructions + ID_GRP_PRIVILEGE, //!< all privileged instructions + ID_GRP_BRANCH_RELATIVE, //!< all relative branching instructions + /* Architecture-specific groups */ + ID_GRP_ISRV32, + ID_GRP_ISRV64, + ID_GRP_HASSTDEXTA, + ID_GRP_HASSTDEXTC, + ID_GRP_HASSTDEXTD, + ID_GRP_HASSTDEXTF, + ID_GRP_HASSTDEXTM, + /* + ID_GRP_ISRVA, + ID_GRP_ISRVC, + ID_GRP_ISRVD, + ID_GRP_ISRVCD, + ID_GRP_ISRVF, + ID_GRP_ISRV32C, + ID_GRP_ISRV32CF, + ID_GRP_ISRVM, + ID_GRP_ISRV64A, + ID_GRP_ISRV64C, + ID_GRP_ISRV64D, + ID_GRP_ISRV64F, + ID_GRP_ISRV64M, + */ + + /* Must be the last item */ + ID_GRP_ENDING //!< must be the last item + }; + + /*! @} End of riscv namespace */ + }; + #endif /*! @} End of arch namespace */ }; /*! @} End of triton namespace */ diff --git a/src/libtriton/includes/triton/externalLibs.hpp b/src/libtriton/includes/triton/externalLibs.hpp index a4bb87be7..e4d640d33 100644 --- a/src/libtriton/includes/triton/externalLibs.hpp +++ b/src/libtriton/includes/triton/externalLibs.hpp @@ -32,6 +32,9 @@ namespace triton { #include #include #include + #ifdef COMPILE_RISCV + #include + #endif #include /*! @} End of capstone namespace */ }; diff --git a/src/libtriton/includes/triton/irBuilder.hpp b/src/libtriton/includes/triton/irBuilder.hpp index 6032db50d..2838256b5 100644 --- a/src/libtriton/includes/triton/irBuilder.hpp +++ b/src/libtriton/includes/triton/irBuilder.hpp @@ -79,6 +79,11 @@ namespace triton { //! x86 ISA builder. triton::arch::SemanticsInterface* x86Isa; + #ifdef COMPILE_RISCV + //! RISCV ISA builder. + triton::arch::SemanticsInterface* riscvIsa; + #endif + public: //! Constructor. TRITON_EXPORT IrBuilder(triton::arch::Architecture* architecture, diff --git a/src/libtriton/includes/triton/riscv32.spec b/src/libtriton/includes/triton/riscv32.spec new file mode 100644 index 000000000..15b7d5aff --- /dev/null +++ b/src/libtriton/includes/triton/riscv32.spec @@ -0,0 +1,89 @@ +#pragma warning(disable:4067) + +#if not (defined REG_SPEC || defined REG_SPEC_NO_CAPSTONE) +#error REG_SPEC have to be specified before including specs +#endif + +#define TT_MUTABLE_REG true +#define TT_IMMUTABLE_REG false + +// REG_SPEC(CS_UPPER_NAME, UPPER_NAME, LOWER_NAME, ABI_NAME, RISCV32_UPPER, RISCV32_LOWER, MUTABLE) + +// Thirty-two 32-bit general-purpose registers +REG_SPEC(X0, X0, x0, zero, triton::bitsize::dword-1, 0, TT_IMMUTABLE_REG) // x0 / zero +REG_SPEC(X1, X1, x1, ra, triton::bitsize::dword-1, 0, TT_MUTABLE_REG) // x1 / ra +REG_SPEC(SP, SP, x2, sp, triton::bitsize::dword-1, 0, TT_MUTABLE_REG) // x2 / sp +REG_SPEC(X3, X3, x3, gp, triton::bitsize::dword-1, 0, TT_MUTABLE_REG) // x3 / gp +REG_SPEC(X4, X4, x4, tp, triton::bitsize::dword-1, 0, TT_MUTABLE_REG) // x4 / tp +REG_SPEC(X5, X5, x5, t0, triton::bitsize::dword-1, 0, TT_MUTABLE_REG) // x5 / t0 or lr +REG_SPEC(X6, X6, x6, t1, triton::bitsize::dword-1, 0, TT_MUTABLE_REG) // x6 / t1 +REG_SPEC(X7, X7, x7, t2, triton::bitsize::dword-1, 0, TT_MUTABLE_REG) // x7 / t2 +REG_SPEC(X8, X8, x8, s0, triton::bitsize::dword-1, 0, TT_MUTABLE_REG) // x8 / s0 or fp +REG_SPEC(X9, X9, x9, s1, triton::bitsize::dword-1, 0, TT_MUTABLE_REG) // x9 / s1 +REG_SPEC(X10, X10, x10, a0, triton::bitsize::dword-1, 0, TT_MUTABLE_REG) // x10 / a0 +REG_SPEC(X11, X11, x11, a1, triton::bitsize::dword-1, 0, TT_MUTABLE_REG) // x11 / a1 +REG_SPEC(X12, X12, x12, a2, triton::bitsize::dword-1, 0, TT_MUTABLE_REG) // x12 / a2 +REG_SPEC(X13, X13, x13, a3, triton::bitsize::dword-1, 0, TT_MUTABLE_REG) // x13 / a3 +REG_SPEC(X14, X14, x14, a4, triton::bitsize::dword-1, 0, TT_MUTABLE_REG) // x14 / a4 +REG_SPEC(X15, X15, x15, a5, triton::bitsize::dword-1, 0, TT_MUTABLE_REG) // x15 / a5 +REG_SPEC(X16, X16, x16, a6, triton::bitsize::dword-1, 0, TT_MUTABLE_REG) // x16 / a6 +REG_SPEC(X17, X17, x17, a7, triton::bitsize::dword-1, 0, TT_MUTABLE_REG) // x17 / a7 +REG_SPEC(X18, X18, x18, s2, triton::bitsize::dword-1, 0, TT_MUTABLE_REG) // x18 / s2 +REG_SPEC(X19, X19, x19, s3, triton::bitsize::dword-1, 0, TT_MUTABLE_REG) // x19 / s3 +REG_SPEC(X20, X20, x20, s4, triton::bitsize::dword-1, 0, TT_MUTABLE_REG) // x20 / s4 +REG_SPEC(X21, X21, x21, s5, triton::bitsize::dword-1, 0, TT_MUTABLE_REG) // x21 / s5 +REG_SPEC(X22, X22, x22, s6, triton::bitsize::dword-1, 0, TT_MUTABLE_REG) // x22 / s6 +REG_SPEC(X23, X23, x23, s7, triton::bitsize::dword-1, 0, TT_MUTABLE_REG) // x23 / s7 +REG_SPEC(X24, X24, x24, s8, triton::bitsize::dword-1, 0, TT_MUTABLE_REG) // x24 / s8 +REG_SPEC(X25, X25, x25, s9, triton::bitsize::dword-1, 0, TT_MUTABLE_REG) // x25 / s9 +REG_SPEC(X26, X26, x26, s10, triton::bitsize::dword-1, 0, TT_MUTABLE_REG) // x26 / s10 +REG_SPEC(X27, X27, x27, s11, triton::bitsize::dword-1, 0, TT_MUTABLE_REG) // x27 / s11 +REG_SPEC(X28, X28, x28, t3, triton::bitsize::dword-1, 0, TT_MUTABLE_REG) // x28 / t3 +REG_SPEC(X29, X29, x29, t4, triton::bitsize::dword-1, 0, TT_MUTABLE_REG) // x29 / t4 +REG_SPEC(X30, X30, x30, t5, triton::bitsize::dword-1, 0, TT_MUTABLE_REG) // x30 / t5 +REG_SPEC(X31, X31, x31, t6, triton::bitsize::dword-1, 0, TT_MUTABLE_REG) // x31 / t6 + +// 32-bit program counter register +REG_SPEC_NO_CAPSTONE(PC, PC, pc, pc, triton::bitsize::dword-1, 0, TT_MUTABLE_REG) // PC + +// Thirty-two 32-bit floating-point registers +REG_SPEC(F0_32, F0, f0, ft0, triton::bitsize::qword-1, 0, TT_MUTABLE_REG) // f0 +REG_SPEC(F1_32, F1, f1, ft1, triton::bitsize::qword-1, 0, TT_MUTABLE_REG) // f1 +REG_SPEC(F2_32, F2, f2, ft2, triton::bitsize::qword-1, 0, TT_MUTABLE_REG) // f2 +REG_SPEC(F3_32, F3, f3, ft3, triton::bitsize::qword-1, 0, TT_MUTABLE_REG) // f3 +REG_SPEC(F4_32, F4, f4, ft4, triton::bitsize::qword-1, 0, TT_MUTABLE_REG) // f4 +REG_SPEC(F5_32, F5, f5, ft5, triton::bitsize::qword-1, 0, TT_MUTABLE_REG) // f5 +REG_SPEC(F6_32, F6, f6, ft6, triton::bitsize::qword-1, 0, TT_MUTABLE_REG) // f6 +REG_SPEC(F7_32, F7, f7, ft7, triton::bitsize::qword-1, 0, TT_MUTABLE_REG) // f7 +REG_SPEC(F8_32, F8, f8, fs0, triton::bitsize::qword-1, 0, TT_MUTABLE_REG) // f8 +REG_SPEC(F9_32, F9, f9, fs1, triton::bitsize::qword-1, 0, TT_MUTABLE_REG) // f9 +REG_SPEC(F10_32, F10, f10, fa0, triton::bitsize::qword-1, 0, TT_MUTABLE_REG) // f10 +REG_SPEC(F11_32, F11, f11, fa1, triton::bitsize::qword-1, 0, TT_MUTABLE_REG) // f11 +REG_SPEC(F12_32, F12, f12, fa2, triton::bitsize::qword-1, 0, TT_MUTABLE_REG) // f12 +REG_SPEC(F13_32, F13, f13, fa3, triton::bitsize::qword-1, 0, TT_MUTABLE_REG) // f13 +REG_SPEC(F14_32, F14, f14, fa4, triton::bitsize::qword-1, 0, TT_MUTABLE_REG) // f14 +REG_SPEC(F15_32, F15, f15, fa5, triton::bitsize::qword-1, 0, TT_MUTABLE_REG) // f15 +REG_SPEC(F16_32, F16, f16, fa6, triton::bitsize::qword-1, 0, TT_MUTABLE_REG) // f16 +REG_SPEC(F17_32, F17, f17, fa7, triton::bitsize::qword-1, 0, TT_MUTABLE_REG) // f17 +REG_SPEC(F18_32, F18, f18, fs2, triton::bitsize::qword-1, 0, TT_MUTABLE_REG) // f18 +REG_SPEC(F19_32, F19, f19, fs3, triton::bitsize::qword-1, 0, TT_MUTABLE_REG) // f19 +REG_SPEC(F20_32, F20, f20, fs4, triton::bitsize::qword-1, 0, TT_MUTABLE_REG) // f20 +REG_SPEC(F21_32, F21, f21, fs5, triton::bitsize::qword-1, 0, TT_MUTABLE_REG) // f21 +REG_SPEC(F22_32, F22, f22, fs6, triton::bitsize::qword-1, 0, TT_MUTABLE_REG) // f22 +REG_SPEC(F23_32, F23, f23, fs7, triton::bitsize::qword-1, 0, TT_MUTABLE_REG) // f23 +REG_SPEC(F24_32, F24, f24, fs8, triton::bitsize::qword-1, 0, TT_MUTABLE_REG) // f24 +REG_SPEC(F25_32, F25, f25, fs9, triton::bitsize::qword-1, 0, TT_MUTABLE_REG) // f25 +REG_SPEC(F26_32, F26, f26, fs10, triton::bitsize::qword-1, 0, TT_MUTABLE_REG) // f26 +REG_SPEC(F27_32, F27, f27, fs11, triton::bitsize::qword-1, 0, TT_MUTABLE_REG) // f27 +REG_SPEC(F28_32, F28, f28, ft8, triton::bitsize::qword-1, 0, TT_MUTABLE_REG) // f28 +REG_SPEC(F29_32, F29, f29, ft9, triton::bitsize::qword-1, 0, TT_MUTABLE_REG) // f29 +REG_SPEC(F30_32, F30, f30, ft10, triton::bitsize::qword-1, 0, TT_MUTABLE_REG) // f30 +REG_SPEC(F31_32, F31, f31, ft11, triton::bitsize::qword-1, 0, TT_MUTABLE_REG) // f31 + +#undef REG_SPEC +#undef REG_SPEC_NO_CAPSTONE +#undef SYS_REG_SPEC +#undef TT_IMMUTABLE_REG +#undef TT_MUTABLE_REG + +#pragma warning(default:4067) diff --git a/src/libtriton/includes/triton/riscv32Cpu.hpp b/src/libtriton/includes/triton/riscv32Cpu.hpp new file mode 100644 index 000000000..82afe63ba --- /dev/null +++ b/src/libtriton/includes/triton/riscv32Cpu.hpp @@ -0,0 +1,284 @@ +//! \file +/* +** Copyright (C) - Triton +** +** This program is under the terms of the Apache License 2.0. +*/ + +#ifndef TRITON_RISCV32CPU_HPP +#define TRITON_RISCV32CPU_HPP + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + + +//! The Triton namespace +namespace triton { +/*! + * \addtogroup triton + * @{ + */ + + //! The Architecture namespace + namespace arch { + /*! + * \ingroup triton + * \addtogroup arch + * @{ + */ + + //! The riscv namespace + namespace riscv { + /*! + * \ingroup arch + * \addtogroup riscv + * @{ + */ + + //! \class riscv32Cpu + /*! \brief This class is used to describe the RV32 spec. */ + class riscv32Cpu : public CpuInterface, public riscvSpecifications { + + static const triton::arch::register_e pcId = triton::arch::ID_REG_RV32_PC; + static const triton::arch::register_e spId = triton::arch::ID_REG_RV32_SP; + + private: + //! Callbacks API + triton::callbacks::Callbacks* callbacks; + + //! Capstone context + std::size_t handle; + + //! Copies a riscv32Cpu class. + void copy(const riscv32Cpu& other); + + //! Initializes the disassembler + void disassInit(void); + + protected: + /*! \brief map of address -> concrete value + * + * \details + * + * **item1**: memory address
    + * **item2**: concrete value + */ + std::unordered_map> memory; + + //! Concrete value of x0 + triton::uint8 x0[triton::size::dword]; + //! Concrete value of x1 + triton::uint8 x1[triton::size::dword]; + //! Concrete value of sp + triton::uint8 sp[triton::size::dword]; + //! Concrete value of x3 + triton::uint8 x3[triton::size::dword]; + //! Concrete value of x4 + triton::uint8 x4[triton::size::dword]; + //! Concrete value of x5 + triton::uint8 x5[triton::size::dword]; + //! Concrete value of x6 + triton::uint8 x6[triton::size::dword]; + //! Concrete value of x7 + triton::uint8 x7[triton::size::dword]; + //! Concrete value of x8 + triton::uint8 x8[triton::size::dword]; + //! Concrete value of x9 + triton::uint8 x9[triton::size::dword]; + //! Concrete value of x10 + triton::uint8 x10[triton::size::dword]; + //! Concrete value of x11 + triton::uint8 x11[triton::size::dword]; + //! Concrete value of x12 + triton::uint8 x12[triton::size::dword]; + //! Concrete value of x13 + triton::uint8 x13[triton::size::dword]; + //! Concrete value of x14 + triton::uint8 x14[triton::size::dword]; + //! Concrete value of x15 + triton::uint8 x15[triton::size::dword]; + //! Concrete value of x16 + triton::uint8 x16[triton::size::dword]; + //! Concrete value of x17 + triton::uint8 x17[triton::size::dword]; + //! Concrete value of x18 + triton::uint8 x18[triton::size::dword]; + //! Concrete value of x19 + triton::uint8 x19[triton::size::dword]; + //! Concrete value of x20 + triton::uint8 x20[triton::size::dword]; + //! Concrete value of x21 + triton::uint8 x21[triton::size::dword]; + //! Concrete value of x22 + triton::uint8 x22[triton::size::dword]; + //! Concrete value of x23 + triton::uint8 x23[triton::size::dword]; + //! Concrete value of x24 + triton::uint8 x24[triton::size::dword]; + //! Concrete value of x25 + triton::uint8 x25[triton::size::dword]; + //! Concrete value of x26 + triton::uint8 x26[triton::size::dword]; + //! Concrete value of x27 + triton::uint8 x27[triton::size::dword]; + //! Concrete value of x28 + triton::uint8 x28[triton::size::dword]; + //! Concrete value of x29 + triton::uint8 x29[triton::size::dword]; + //! Concrete value of x30 + triton::uint8 x30[triton::size::dword]; + //! Concrete value of x31 + triton::uint8 x31[triton::size::dword]; + //! Concrete value of f0 + triton::uint8 f0[triton::size::qword]; + //! Concrete value of f1 + triton::uint8 f1[triton::size::qword]; + //! Concrete value of f2 + triton::uint8 f2[triton::size::qword]; + //! Concrete value of f3 + triton::uint8 f3[triton::size::qword]; + //! Concrete value of f4 + triton::uint8 f4[triton::size::qword]; + //! Concrete value of f5 + triton::uint8 f5[triton::size::qword]; + //! Concrete value of f6 + triton::uint8 f6[triton::size::qword]; + //! Concrete value of f7 + triton::uint8 f7[triton::size::qword]; + //! Concrete value of f8 + triton::uint8 f8[triton::size::qword]; + //! Concrete value of f9 + triton::uint8 f9[triton::size::qword]; + //! Concrete value of f10 + triton::uint8 f10[triton::size::qword]; + //! Concrete value of f11 + triton::uint8 f11[triton::size::qword]; + //! Concrete value of f12 + triton::uint8 f12[triton::size::qword]; + //! Concrete value of f13 + triton::uint8 f13[triton::size::qword]; + //! Concrete value of f14 + triton::uint8 f14[triton::size::qword]; + //! Concrete value of f15 + triton::uint8 f15[triton::size::qword]; + //! Concrete value of f16 + triton::uint8 f16[triton::size::qword]; + //! Concrete value of f17 + triton::uint8 f17[triton::size::qword]; + //! Concrete value of f18 + triton::uint8 f18[triton::size::qword]; + //! Concrete value of f19 + triton::uint8 f19[triton::size::qword]; + //! Concrete value of f20 + triton::uint8 f20[triton::size::qword]; + //! Concrete value of f21 + triton::uint8 f21[triton::size::qword]; + //! Concrete value of f22 + triton::uint8 f22[triton::size::qword]; + //! Concrete value of f23 + triton::uint8 f23[triton::size::qword]; + //! Concrete value of f24 + triton::uint8 f24[triton::size::qword]; + //! Concrete value of f25 + triton::uint8 f25[triton::size::qword]; + //! Concrete value of f26 + triton::uint8 f26[triton::size::qword]; + //! Concrete value of f27 + triton::uint8 f27[triton::size::qword]; + //! Concrete value of f28 + triton::uint8 f28[triton::size::qword]; + //! Concrete value of f29 + triton::uint8 f29[triton::size::qword]; + //! Concrete value of f30 + triton::uint8 f30[triton::size::qword]; + //! Concrete value of f31 + triton::uint8 f31[triton::size::qword]; + //! Concrete value of pc + triton::uint8 pc[triton::size::dword]; + + //! System registers + #define SYS_REG_SPEC(_, LOWER_NAME, _2, _3, _4, _5, _6) \ + triton::uint8 LOWER_NAME[triton::size::qword]; + #define REG_SPEC(_1, _2, _3, _4, _5, _6, _7) + #define REG_SPEC_NO_CAPSTONE(_1, _2, _3, _4, _5, _6, _7) + #include "triton/riscv32.spec" + + public: + //! Constructor. + TRITON_EXPORT riscv32Cpu(triton::callbacks::Callbacks* callbacks=nullptr); + + //! Constructor + TRITON_EXPORT riscv32Cpu(const riscv32Cpu& other); + + //! Destructor. + TRITON_EXPORT virtual ~riscv32Cpu(); + + //! Copies a riscv32Cpu class. + TRITON_EXPORT riscv32Cpu& operator=(const riscv32Cpu& other); + + //! Returns true if regId is a GRP. + TRITON_EXPORT bool isGPR(triton::arch::register_e regId) const; + + //! Returns true if regId is a FPU register. + TRITON_EXPORT bool isFPU(triton::arch::register_e regId) const; + + /* Virtual pure inheritance ================================================= */ + TRITON_EXPORT bool isFlag(triton::arch::register_e regId) const; + TRITON_EXPORT bool isRegister(triton::arch::register_e regId) const; + TRITON_EXPORT bool isRegisterValid(triton::arch::register_e regId) const; + TRITON_EXPORT bool isThumb(void) const; + TRITON_EXPORT bool isMemoryExclusive(const triton::arch::MemoryAccess& mem) const; + TRITON_EXPORT const std::unordered_map& getAllRegisters(void) const; + TRITON_EXPORT const std::unordered_map>& getConcreteMemory(void) const; + TRITON_EXPORT const triton::arch::Register& getParentRegister(const triton::arch::Register& reg) const; + TRITON_EXPORT const triton::arch::Register& getParentRegister(triton::arch::register_e id) const; + TRITON_EXPORT const triton::arch::Register& getProgramCounter(void) const; + TRITON_EXPORT const triton::arch::Register& getRegister(triton::arch::register_e id) const; + TRITON_EXPORT const triton::arch::Register& getRegister(const std::string& name) const; + TRITON_EXPORT const triton::arch::Register& getStackPointer(void) const; + TRITON_EXPORT std::set getParentRegisters(void) const; + TRITON_EXPORT std::vector getConcreteMemoryAreaValue(triton::uint64 baseAddr, triton::usize size, bool execCallbacks=true) const; + TRITON_EXPORT triton::arch::endianness_e getEndianness(void) const; + TRITON_EXPORT triton::uint32 numberOfRegisters(void) const; + TRITON_EXPORT triton::uint32 gprBitSize(void) const; + TRITON_EXPORT triton::uint32 gprSize(void) const; + TRITON_EXPORT triton::uint512 getConcreteMemoryValue(const triton::arch::MemoryAccess& mem, bool execCallbacks=true) const; + TRITON_EXPORT triton::uint512 getConcreteRegisterValue(const triton::arch::Register& reg, bool execCallbacks=true) const; + TRITON_EXPORT triton::uint8 getConcreteMemoryValue(triton::uint64 addr, bool execCallbacks=true) const; + TRITON_EXPORT void clear(void); + TRITON_EXPORT void disassembly(triton::arch::Instruction& inst); + TRITON_EXPORT void setConcreteMemoryAreaValue(triton::uint64 baseAddr, const std::vector& values, bool execCallbacks=true); + TRITON_EXPORT void setConcreteMemoryAreaValue(triton::uint64 baseAddr, const void* area, triton::usize size, bool execCallbacks=true); + TRITON_EXPORT void setConcreteMemoryValue(const triton::arch::MemoryAccess& mem, const triton::uint512& value, bool execCallbacks=true); + TRITON_EXPORT void setConcreteMemoryValue(triton::uint64 addr, triton::uint8 value, bool execCallbacks=true); + TRITON_EXPORT void setConcreteRegisterValue(const triton::arch::Register& reg, const triton::uint512& value, bool execCallbacks=true); + TRITON_EXPORT void setThumb(bool state); + TRITON_EXPORT void setMemoryExclusiveTag(const triton::arch::MemoryAccess& mem, bool tag); + TRITON_EXPORT bool isConcreteMemoryValueDefined(const triton::arch::MemoryAccess& mem) const; + TRITON_EXPORT bool isConcreteMemoryValueDefined(triton::uint64 baseAddr, triton::usize size=1) const; + TRITON_EXPORT void clearConcreteMemoryValue(const triton::arch::MemoryAccess& mem); + TRITON_EXPORT void clearConcreteMemoryValue(triton::uint64 baseAddr, triton::usize size=1); + /* End of virtual pure inheritance ========================================== */ + }; + + /*! @} End of riscv namespace */ + }; + /*! @} End of arch namespace */ + }; +/*! @} End of triton namespace */ +}; + +#endif /* TRITON_RISCV32CPU_HPP */ diff --git a/src/libtriton/includes/triton/riscv64.spec b/src/libtriton/includes/triton/riscv64.spec new file mode 100644 index 000000000..d742262b5 --- /dev/null +++ b/src/libtriton/includes/triton/riscv64.spec @@ -0,0 +1,89 @@ +#pragma warning(disable:4067) + +#if not (defined REG_SPEC || defined REG_SPEC_NO_CAPSTONE) +#error REG_SPEC have to be specified before including specs +#endif + +#define TT_MUTABLE_REG true +#define TT_IMMUTABLE_REG false + +// REG_SPEC(CS_UPPER_NAME, UPPER_NAME, LOWER_NAME, ABI_NAME, RISCV64_UPPER, RISCV64_LOWER, MUTABLE) + +// Thirty-two 64-bit general-purpose registers +REG_SPEC(X0, X0, x0, zero, triton::bitsize::qword-1, 0, TT_IMMUTABLE_REG) // x0 / zero +REG_SPEC(X1, X1, x1, ra, triton::bitsize::qword-1, 0, TT_MUTABLE_REG) // x1 / ra +REG_SPEC(SP, SP, x2, sp, triton::bitsize::qword-1, 0, TT_MUTABLE_REG) // x2 / sp +REG_SPEC(X3, X3, x3, gp, triton::bitsize::qword-1, 0, TT_MUTABLE_REG) // x3 / gp +REG_SPEC(X4, X4, x4, tp, triton::bitsize::qword-1, 0, TT_MUTABLE_REG) // x4 / tp +REG_SPEC(X5, X5, x5, t0, triton::bitsize::qword-1, 0, TT_MUTABLE_REG) // x5 / t0 or lr +REG_SPEC(X6, X6, x6, t1, triton::bitsize::qword-1, 0, TT_MUTABLE_REG) // x6 / t1 +REG_SPEC(X7, X7, x7, t2, triton::bitsize::qword-1, 0, TT_MUTABLE_REG) // x7 / t2 +REG_SPEC(X8, X8, x8, s0, triton::bitsize::qword-1, 0, TT_MUTABLE_REG) // x8 / s0 or fp +REG_SPEC(X9, X9, x9, s1, triton::bitsize::qword-1, 0, TT_MUTABLE_REG) // x9 / s1 +REG_SPEC(X10, X10, x10, a0, triton::bitsize::qword-1, 0, TT_MUTABLE_REG) // x10 / a0 +REG_SPEC(X11, X11, x11, a1, triton::bitsize::qword-1, 0, TT_MUTABLE_REG) // x11 / a1 +REG_SPEC(X12, X12, x12, a2, triton::bitsize::qword-1, 0, TT_MUTABLE_REG) // x12 / a2 +REG_SPEC(X13, X13, x13, a3, triton::bitsize::qword-1, 0, TT_MUTABLE_REG) // x13 / a3 +REG_SPEC(X14, X14, x14, a4, triton::bitsize::qword-1, 0, TT_MUTABLE_REG) // x14 / a4 +REG_SPEC(X15, X15, x15, a5, triton::bitsize::qword-1, 0, TT_MUTABLE_REG) // x15 / a5 +REG_SPEC(X16, X16, x16, a6, triton::bitsize::qword-1, 0, TT_MUTABLE_REG) // x16 / a6 +REG_SPEC(X17, X17, x17, a7, triton::bitsize::qword-1, 0, TT_MUTABLE_REG) // x17 / a7 +REG_SPEC(X18, X18, x18, s2, triton::bitsize::qword-1, 0, TT_MUTABLE_REG) // x18 / s2 +REG_SPEC(X19, X19, x19, s3, triton::bitsize::qword-1, 0, TT_MUTABLE_REG) // x19 / s3 +REG_SPEC(X20, X20, x20, s4, triton::bitsize::qword-1, 0, TT_MUTABLE_REG) // x20 / s4 +REG_SPEC(X21, X21, x21, s5, triton::bitsize::qword-1, 0, TT_MUTABLE_REG) // x21 / s5 +REG_SPEC(X22, X22, x22, s6, triton::bitsize::qword-1, 0, TT_MUTABLE_REG) // x22 / s6 +REG_SPEC(X23, X23, x23, s7, triton::bitsize::qword-1, 0, TT_MUTABLE_REG) // x23 / s7 +REG_SPEC(X24, X24, x24, s8, triton::bitsize::qword-1, 0, TT_MUTABLE_REG) // x24 / s8 +REG_SPEC(X25, X25, x25, s9, triton::bitsize::qword-1, 0, TT_MUTABLE_REG) // x25 / s9 +REG_SPEC(X26, X26, x26, s10, triton::bitsize::qword-1, 0, TT_MUTABLE_REG) // x26 / s10 +REG_SPEC(X27, X27, x27, s11, triton::bitsize::qword-1, 0, TT_MUTABLE_REG) // x27 / s11 +REG_SPEC(X28, X28, x28, t3, triton::bitsize::qword-1, 0, TT_MUTABLE_REG) // x28 / t3 +REG_SPEC(X29, X29, x29, t4, triton::bitsize::qword-1, 0, TT_MUTABLE_REG) // x29 / t4 +REG_SPEC(X30, X30, x30, t5, triton::bitsize::qword-1, 0, TT_MUTABLE_REG) // x30 / t5 +REG_SPEC(X31, X31, x31, t6, triton::bitsize::qword-1, 0, TT_MUTABLE_REG) // x31 / t6 + +// Program counter register +REG_SPEC_NO_CAPSTONE(PC, PC, pc, pc, triton::bitsize::qword-1, 0, TT_MUTABLE_REG) // PC + +// Thirty-two 64-bit floating-point registers +REG_SPEC(F0_64, F0, f0, ft0, triton::bitsize::dqword-1, 0, TT_MUTABLE_REG) // f0 +REG_SPEC(F1_64, F1, f1, ft1, triton::bitsize::dqword-1, 0, TT_MUTABLE_REG) // f1 +REG_SPEC(F2_64, F2, f2, ft2, triton::bitsize::dqword-1, 0, TT_MUTABLE_REG) // f2 +REG_SPEC(F3_64, F3, f3, ft3, triton::bitsize::dqword-1, 0, TT_MUTABLE_REG) // f3 +REG_SPEC(F4_64, F4, f4, ft4, triton::bitsize::dqword-1, 0, TT_MUTABLE_REG) // f4 +REG_SPEC(F5_64, F5, f5, ft5, triton::bitsize::dqword-1, 0, TT_MUTABLE_REG) // f5 +REG_SPEC(F6_64, F6, f6, ft6, triton::bitsize::dqword-1, 0, TT_MUTABLE_REG) // f6 +REG_SPEC(F7_64, F7, f7, ft7, triton::bitsize::dqword-1, 0, TT_MUTABLE_REG) // f7 +REG_SPEC(F8_64, F8, f8, fs0, triton::bitsize::dqword-1, 0, TT_MUTABLE_REG) // f8 +REG_SPEC(F9_64, F9, f9, fs1, triton::bitsize::dqword-1, 0, TT_MUTABLE_REG) // f9 +REG_SPEC(F10_64, F10, f10, fa0, triton::bitsize::dqword-1, 0, TT_MUTABLE_REG) // f10 +REG_SPEC(F11_64, F11, f11, fa1, triton::bitsize::dqword-1, 0, TT_MUTABLE_REG) // f11 +REG_SPEC(F12_64, F12, f12, fa2, triton::bitsize::dqword-1, 0, TT_MUTABLE_REG) // f12 +REG_SPEC(F13_64, F13, f13, fa3, triton::bitsize::dqword-1, 0, TT_MUTABLE_REG) // f13 +REG_SPEC(F14_64, F14, f14, fa4, triton::bitsize::dqword-1, 0, TT_MUTABLE_REG) // f14 +REG_SPEC(F15_64, F15, f15, fa5, triton::bitsize::dqword-1, 0, TT_MUTABLE_REG) // f15 +REG_SPEC(F16_64, F16, f16, fa6, triton::bitsize::dqword-1, 0, TT_MUTABLE_REG) // f16 +REG_SPEC(F17_64, F17, f17, fa7, triton::bitsize::dqword-1, 0, TT_MUTABLE_REG) // f17 +REG_SPEC(F18_64, F18, f18, fs2, triton::bitsize::dqword-1, 0, TT_MUTABLE_REG) // f18 +REG_SPEC(F19_64, F19, f19, fs3, triton::bitsize::dqword-1, 0, TT_MUTABLE_REG) // f19 +REG_SPEC(F20_64, F20, f20, fs4, triton::bitsize::dqword-1, 0, TT_MUTABLE_REG) // f20 +REG_SPEC(F21_64, F21, f21, fs5, triton::bitsize::dqword-1, 0, TT_MUTABLE_REG) // f21 +REG_SPEC(F22_64, F22, f22, fs6, triton::bitsize::dqword-1, 0, TT_MUTABLE_REG) // f22 +REG_SPEC(F23_64, F23, f23, fs7, triton::bitsize::dqword-1, 0, TT_MUTABLE_REG) // f23 +REG_SPEC(F24_64, F24, f24, fs8, triton::bitsize::dqword-1, 0, TT_MUTABLE_REG) // f24 +REG_SPEC(F25_64, F25, f25, fs9, triton::bitsize::dqword-1, 0, TT_MUTABLE_REG) // f25 +REG_SPEC(F26_64, F26, f26, fs10, triton::bitsize::dqword-1, 0, TT_MUTABLE_REG) // f26 +REG_SPEC(F27_64, F27, f27, fs11, triton::bitsize::dqword-1, 0, TT_MUTABLE_REG) // f27 +REG_SPEC(F28_64, F28, f28, ft8, triton::bitsize::dqword-1, 0, TT_MUTABLE_REG) // f28 +REG_SPEC(F29_64, F29, f29, ft9, triton::bitsize::dqword-1, 0, TT_MUTABLE_REG) // f29 +REG_SPEC(F30_64, F30, f30, ft10, triton::bitsize::dqword-1, 0, TT_MUTABLE_REG) // f30 +REG_SPEC(F31_64, F31, f31, ft11, triton::bitsize::dqword-1, 0, TT_MUTABLE_REG) // f31 + +#undef REG_SPEC +#undef REG_SPEC_NO_CAPSTONE +#undef SYS_REG_SPEC +#undef TT_IMMUTABLE_REG +#undef TT_MUTABLE_REG + +#pragma warning(default:4067) diff --git a/src/libtriton/includes/triton/riscv64Cpu.hpp b/src/libtriton/includes/triton/riscv64Cpu.hpp new file mode 100644 index 000000000..7914d7263 --- /dev/null +++ b/src/libtriton/includes/triton/riscv64Cpu.hpp @@ -0,0 +1,284 @@ +//! \file +/* +** Copyright (C) - Triton +** +** This program is under the terms of the Apache License 2.0. +*/ + +#ifndef TRITON_RISCV64CPU_HPP +#define TRITON_RISCV64CPU_HPP + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + + +//! The Triton namespace +namespace triton { +/*! + * \addtogroup triton + * @{ + */ + + //! The Architecture namespace + namespace arch { + /*! + * \ingroup triton + * \addtogroup arch + * @{ + */ + + //! The riscv namespace + namespace riscv { + /*! + * \ingroup arch + * \addtogroup riscv + * @{ + */ + + //! \class riscv64Cpu + /*! \brief This class is used to describe the RV64 spec. */ + class riscv64Cpu : public CpuInterface, public riscvSpecifications { + + static const triton::arch::register_e pcId = triton::arch::ID_REG_RV64_PC; + static const triton::arch::register_e spId = triton::arch::ID_REG_RV64_SP; + + private: + //! Callbacks API + triton::callbacks::Callbacks* callbacks; + + //! Capstone context + std::size_t handle; + + //! Copies a riscv64Cpu class. + void copy(const riscv64Cpu& other); + + //! Initializes the disassembler + void disassInit(void); + + protected: + /*! \brief map of address -> concrete value + * + * \details + * + * **item1**: memory address
    + * **item2**: concrete value + */ + std::unordered_map> memory; + + //! Concrete value of x0 + triton::uint8 x0[triton::size::qword]; + //! Concrete value of x1 + triton::uint8 x1[triton::size::qword]; + //! Concrete value of sp + triton::uint8 sp[triton::size::qword]; + //! Concrete value of x3 + triton::uint8 x3[triton::size::qword]; + //! Concrete value of x4 + triton::uint8 x4[triton::size::qword]; + //! Concrete value of x5 + triton::uint8 x5[triton::size::qword]; + //! Concrete value of x6 + triton::uint8 x6[triton::size::qword]; + //! Concrete value of x7 + triton::uint8 x7[triton::size::qword]; + //! Concrete value of x8 + triton::uint8 x8[triton::size::qword]; + //! Concrete value of x9 + triton::uint8 x9[triton::size::qword]; + //! Concrete value of x10 + triton::uint8 x10[triton::size::qword]; + //! Concrete value of x11 + triton::uint8 x11[triton::size::qword]; + //! Concrete value of x12 + triton::uint8 x12[triton::size::qword]; + //! Concrete value of x13 + triton::uint8 x13[triton::size::qword]; + //! Concrete value of x14 + triton::uint8 x14[triton::size::qword]; + //! Concrete value of x15 + triton::uint8 x15[triton::size::qword]; + //! Concrete value of x16 + triton::uint8 x16[triton::size::qword]; + //! Concrete value of x17 + triton::uint8 x17[triton::size::qword]; + //! Concrete value of x18 + triton::uint8 x18[triton::size::qword]; + //! Concrete value of x19 + triton::uint8 x19[triton::size::qword]; + //! Concrete value of x20 + triton::uint8 x20[triton::size::qword]; + //! Concrete value of x21 + triton::uint8 x21[triton::size::qword]; + //! Concrete value of x22 + triton::uint8 x22[triton::size::qword]; + //! Concrete value of x23 + triton::uint8 x23[triton::size::qword]; + //! Concrete value of x24 + triton::uint8 x24[triton::size::qword]; + //! Concrete value of x25 + triton::uint8 x25[triton::size::qword]; + //! Concrete value of x26 + triton::uint8 x26[triton::size::qword]; + //! Concrete value of x27 + triton::uint8 x27[triton::size::qword]; + //! Concrete value of x28 + triton::uint8 x28[triton::size::qword]; + //! Concrete value of x29 + triton::uint8 x29[triton::size::qword]; + //! Concrete value of x30 + triton::uint8 x30[triton::size::qword]; + //! Concrete value of x31 + triton::uint8 x31[triton::size::qword]; + //! Concrete value of f0 + triton::uint8 f0[triton::size::dqword]; + //! Concrete value of f1 + triton::uint8 f1[triton::size::dqword]; + //! Concrete value of f2 + triton::uint8 f2[triton::size::dqword]; + //! Concrete value of f3 + triton::uint8 f3[triton::size::dqword]; + //! Concrete value of f4 + triton::uint8 f4[triton::size::dqword]; + //! Concrete value of f5 + triton::uint8 f5[triton::size::dqword]; + //! Concrete value of f6 + triton::uint8 f6[triton::size::dqword]; + //! Concrete value of f7 + triton::uint8 f7[triton::size::dqword]; + //! Concrete value of f8 + triton::uint8 f8[triton::size::dqword]; + //! Concrete value of f9 + triton::uint8 f9[triton::size::dqword]; + //! Concrete value of f10 + triton::uint8 f10[triton::size::dqword]; + //! Concrete value of f11 + triton::uint8 f11[triton::size::dqword]; + //! Concrete value of f12 + triton::uint8 f12[triton::size::dqword]; + //! Concrete value of f13 + triton::uint8 f13[triton::size::dqword]; + //! Concrete value of f14 + triton::uint8 f14[triton::size::dqword]; + //! Concrete value of f15 + triton::uint8 f15[triton::size::dqword]; + //! Concrete value of f16 + triton::uint8 f16[triton::size::dqword]; + //! Concrete value of f17 + triton::uint8 f17[triton::size::dqword]; + //! Concrete value of f18 + triton::uint8 f18[triton::size::dqword]; + //! Concrete value of f19 + triton::uint8 f19[triton::size::dqword]; + //! Concrete value of f20 + triton::uint8 f20[triton::size::dqword]; + //! Concrete value of f21 + triton::uint8 f21[triton::size::dqword]; + //! Concrete value of f22 + triton::uint8 f22[triton::size::dqword]; + //! Concrete value of f23 + triton::uint8 f23[triton::size::dqword]; + //! Concrete value of f24 + triton::uint8 f24[triton::size::dqword]; + //! Concrete value of f25 + triton::uint8 f25[triton::size::dqword]; + //! Concrete value of f26 + triton::uint8 f26[triton::size::dqword]; + //! Concrete value of f27 + triton::uint8 f27[triton::size::dqword]; + //! Concrete value of f28 + triton::uint8 f28[triton::size::dqword]; + //! Concrete value of f29 + triton::uint8 f29[triton::size::dqword]; + //! Concrete value of f30 + triton::uint8 f30[triton::size::dqword]; + //! Concrete value of f31 + triton::uint8 f31[triton::size::dqword]; + //! Concrete value of pc + triton::uint8 pc[triton::size::qword]; + + //! System registers + #define SYS_REG_SPEC(_, LOWER_NAME, _2, _3, _4, _5, _6) \ + triton::uint8 LOWER_NAME[triton::size::qword]; + #define REG_SPEC(_1, _2, _3, _4, _5, _6, _7) + #define REG_SPEC_NO_CAPSTONE(_1, _2, _3, _4, _5, _6, _7) + #include "triton/riscv64.spec" + + public: + //! Constructor. + TRITON_EXPORT riscv64Cpu(triton::callbacks::Callbacks* callbacks=nullptr); + + //! Constructor + TRITON_EXPORT riscv64Cpu(const riscv64Cpu& other); + + //! Destructor. + TRITON_EXPORT virtual ~riscv64Cpu(); + + //! Copies a riscv64Cpu class. + TRITON_EXPORT riscv64Cpu& operator=(const riscv64Cpu& other); + + //! Returns true if regId is a GRP. + TRITON_EXPORT bool isGPR(triton::arch::register_e regId) const; + + //! Returns true if regId is a FPU register. + TRITON_EXPORT bool isFPU(triton::arch::register_e regId) const; + + /* Virtual pure inheritance ================================================= */ + TRITON_EXPORT bool isFlag(triton::arch::register_e regId) const; + TRITON_EXPORT bool isRegister(triton::arch::register_e regId) const; + TRITON_EXPORT bool isRegisterValid(triton::arch::register_e regId) const; + TRITON_EXPORT bool isThumb(void) const; + TRITON_EXPORT bool isMemoryExclusive(const triton::arch::MemoryAccess& mem) const; + TRITON_EXPORT const std::unordered_map& getAllRegisters(void) const; + TRITON_EXPORT const std::unordered_map>& getConcreteMemory(void) const; + TRITON_EXPORT const triton::arch::Register& getParentRegister(const triton::arch::Register& reg) const; + TRITON_EXPORT const triton::arch::Register& getParentRegister(triton::arch::register_e id) const; + TRITON_EXPORT const triton::arch::Register& getProgramCounter(void) const; + TRITON_EXPORT const triton::arch::Register& getRegister(triton::arch::register_e id) const; + TRITON_EXPORT const triton::arch::Register& getRegister(const std::string& name) const; + TRITON_EXPORT const triton::arch::Register& getStackPointer(void) const; + TRITON_EXPORT std::set getParentRegisters(void) const; + TRITON_EXPORT std::vector getConcreteMemoryAreaValue(triton::uint64 baseAddr, triton::usize size, bool execCallbacks=true) const; + TRITON_EXPORT triton::arch::endianness_e getEndianness(void) const; + TRITON_EXPORT triton::uint32 numberOfRegisters(void) const; + TRITON_EXPORT triton::uint32 gprBitSize(void) const; + TRITON_EXPORT triton::uint32 gprSize(void) const; + TRITON_EXPORT triton::uint512 getConcreteMemoryValue(const triton::arch::MemoryAccess& mem, bool execCallbacks=true) const; + TRITON_EXPORT triton::uint512 getConcreteRegisterValue(const triton::arch::Register& reg, bool execCallbacks=true) const; + TRITON_EXPORT triton::uint8 getConcreteMemoryValue(triton::uint64 addr, bool execCallbacks=true) const; + TRITON_EXPORT void clear(void); + TRITON_EXPORT void disassembly(triton::arch::Instruction& inst); + TRITON_EXPORT void setConcreteMemoryAreaValue(triton::uint64 baseAddr, const std::vector& values, bool execCallbacks=true); + TRITON_EXPORT void setConcreteMemoryAreaValue(triton::uint64 baseAddr, const void* area, triton::usize size, bool execCallbacks=true); + TRITON_EXPORT void setConcreteMemoryValue(const triton::arch::MemoryAccess& mem, const triton::uint512& value, bool execCallbacks=true); + TRITON_EXPORT void setConcreteMemoryValue(triton::uint64 addr, triton::uint8 value, bool execCallbacks=true); + TRITON_EXPORT void setConcreteRegisterValue(const triton::arch::Register& reg, const triton::uint512& value, bool execCallbacks=true); + TRITON_EXPORT void setThumb(bool state); + TRITON_EXPORT void setMemoryExclusiveTag(const triton::arch::MemoryAccess& mem, bool tag); + TRITON_EXPORT bool isConcreteMemoryValueDefined(const triton::arch::MemoryAccess& mem) const; + TRITON_EXPORT bool isConcreteMemoryValueDefined(triton::uint64 baseAddr, triton::usize size=1) const; + TRITON_EXPORT void clearConcreteMemoryValue(const triton::arch::MemoryAccess& mem); + TRITON_EXPORT void clearConcreteMemoryValue(triton::uint64 baseAddr, triton::usize size=1); + /* End of virtual pure inheritance ========================================== */ + }; + + /*! @} End of riscv namespace */ + }; + /*! @} End of arch namespace */ + }; +/*! @} End of triton namespace */ +}; + +#endif /* TRITON_RISCV64CPU_HPP */ diff --git a/src/libtriton/includes/triton/riscvSemantics.hpp b/src/libtriton/includes/triton/riscvSemantics.hpp new file mode 100644 index 000000000..05a0c5cf5 --- /dev/null +++ b/src/libtriton/includes/triton/riscvSemantics.hpp @@ -0,0 +1,388 @@ +//! \file +/* +** Copyright (C) - Triton +** +** This program is under the terms of the Apache License 2.0. +*/ + +#ifndef TRITON_RISCVSEMANTICS_H +#define TRITON_RISCVSEMANTICS_H + +#include +#include +#include +#include +#include +#include +#include +#include + + + +//! The Triton namespace +namespace triton { +/*! + * \addtogroup triton + * @{ + */ + + //! The Architecture namespace + namespace arch { + /*! + * \ingroup triton + * \addtogroup arch + * @{ + */ + + //! The x86 namespace + namespace riscv { + /*! + * \ingroup arch + * \addtogroup riscv + * @{ + */ + + /*! \class riscvSemantics + \brief The RISCV ISA semantics. */ + class riscvSemantics : public SemanticsInterface { + private: + //! Architecture API + triton::arch::Architecture* architecture; + + //! Symbolic Engine API + triton::engines::symbolic::SymbolicEngine* symbolicEngine; + + //! Taint Engine API + triton::engines::taint::TaintEngine* taintEngine; + + //! The Modes API + triton::modes::SharedModes modes; + + //! The AST Context API + triton::ast::SharedAstContext astCtxt; + + //! Exception status + triton::arch::exception_e exception; + + public: + //! Constructor. + TRITON_EXPORT riscvSemantics(triton::arch::Architecture* architecture, + triton::engines::symbolic::SymbolicEngine* symbolicEngine, + triton::engines::taint::TaintEngine* taintEngine, + const triton::modes::SharedModes& modes, + const triton::ast::SharedAstContext& astCtxt); + + //! Builds the semantics of the instruction. Returns `triton::arch::NO_FAULT` if succeed. + TRITON_EXPORT triton::arch::exception_e buildSemantics(triton::arch::Instruction& inst); + + private: + //! Control flow semantics. Used to represent PC. + void controlFlow_s(triton::arch::Instruction& inst); + + //! The ADD semantics. + void add_s(triton::arch::Instruction& inst); + + //! The ADDI semantics. + void addi_s(triton::arch::Instruction& inst); + + //! The MV (ADDI pseudo instruction) semantics. + void addi_mv_s(triton::arch::Instruction& inst); + + //! The ADDIW semantics. + void addiw_s(triton::arch::Instruction& inst); + + //! The ADDW semantics. + void addw_s(triton::arch::Instruction& inst); + + //! The AND semantics. + void and_s(triton::arch::Instruction& inst); + + //! The ANDI semantics. + void andi_s(triton::arch::Instruction& inst); + + //! The AUIPC semantics. + void auipc_s(triton::arch::Instruction& inst); + + //! The BEQ semantics. + void beq_s(triton::arch::Instruction& inst); + + //! The BGE semantics. + void bge_s(triton::arch::Instruction& inst); + + //! The BGEU semantics. + void bgeu_s(triton::arch::Instruction& inst); + + //! The BLT semantics. + void blt_s(triton::arch::Instruction& inst); + + //! The BLTU semantics. + void bltu_s(triton::arch::Instruction& inst); + + //! The BNE semantics. + void bne_s(triton::arch::Instruction& inst); + + //! The compressed ADD semantics. + void c_add_s(triton::arch::Instruction& inst); + + //! The compressed ADDI semantics. + void c_addi_s(triton::arch::Instruction& inst); + + //! The compressed ADDI16SP semantics. + void c_addi16sp_s(triton::arch::Instruction& inst); + + //! The compressed ADDI4SPN semantics. + void c_addi4spn_s(triton::arch::Instruction& inst); + + //! The compressed ADDIW semantics. + void c_addiw_s(triton::arch::Instruction& inst); + + //! The compressed ADDW semantics. + void c_addw_s(triton::arch::Instruction& inst); + + //! The compressed AND semantics. + void c_and_s(triton::arch::Instruction& inst); + + //! The compressed ANDI semantics. + void c_andi_s(triton::arch::Instruction& inst); + + //! The compressed BEQZ semantics. + void c_beqz_s(triton::arch::Instruction& inst); + + //! The compressed BNEZ semantics. + void c_bnez_s(triton::arch::Instruction& inst); + + //! The compressed JAL semantics. + void c_jal_s(triton::arch::Instruction& inst); + + //! The compressed JALR semantics. + void c_jalr_s(triton::arch::Instruction& inst); + + //! The compressed LD semantics. + void c_ld_s(triton::arch::Instruction& inst); + + //! The compressed LDSP semantics. + void c_ldsp_s(triton::arch::Instruction& inst); + + //! The compressed LI semantics. + void c_li_s(triton::arch::Instruction& inst); + + //! The compressed LW semantics. + void c_lw_s(triton::arch::Instruction& inst); + + //! The compressed LWSP semantics. + void c_lwsp_s(triton::arch::Instruction& inst); + + //! The compressed MV semantics. + void c_mv_s(triton::arch::Instruction& inst); + + //! The compressed NOP semantics. + void c_nop_s(triton::arch::Instruction& inst); + + //! The compressed OR semantics. + void c_or_s(triton::arch::Instruction& inst); + + //! The compressed SD semantics. + void c_sd_s(triton::arch::Instruction& inst); + + //! The compressed SDSP semantics. + void c_sdsp_s(triton::arch::Instruction& inst); + + //! The compressed SLLI semantics. + void c_slli_s(triton::arch::Instruction& inst); + + //! The compressed SRAI semantics. + void c_srai_s(triton::arch::Instruction& inst); + + //! The compressed SRLI semantics. + void c_srli_s(triton::arch::Instruction& inst); + + //! The compressed SUB semantics. + void c_sub_s(triton::arch::Instruction& inst); + + //! The compressed SUBW semantics. + void c_subw_s(triton::arch::Instruction& inst); + + //! The compressed SW semantics. + void c_sw_s(triton::arch::Instruction& inst); + + //! The compressed SWSP semantics. + void c_swsp_s(triton::arch::Instruction& inst); + + //! The compressed XOR semantics. + void c_xor_s(triton::arch::Instruction& inst); + + //! The DIV semantics. + void div_s(triton::arch::Instruction& inst); + + //! The DIVU semantics. + void divu_s(triton::arch::Instruction& inst); + + //! The DIVUW semantics. + void divuw_s(triton::arch::Instruction& inst); + + //! The DIVW semantics. + void divw_s(triton::arch::Instruction& inst); + + //! The JAL semantics. + void jal_s(triton::arch::Instruction& inst); + + //! The J (JAL pseudo instruction) semantics. + void jal_j_s(triton::arch::Instruction& inst); + + //! The JALR semantics. + void jalr_s(triton::arch::Instruction& inst); + + //! The RET/JR (JALR pseudo instruction) semantics. + void jalr_no_link_s(triton::arch::Instruction& inst); + + //! The LB semantics. + void lb_s(triton::arch::Instruction& inst); + + //! The LBU semantics. + void lbu_s(triton::arch::Instruction& inst); + + //! The LD semantics. + void ld_s(triton::arch::Instruction& inst); + + //! The LH semantics. + void lh_s(triton::arch::Instruction& inst); + + //! The LHU semantics. + void lhu_s(triton::arch::Instruction& inst); + + //! The LUI semantics. + void lui_s(triton::arch::Instruction& inst); + + //! The LW semantics. + void lw_s(triton::arch::Instruction& inst); + + //! The LWU semantics. + void lwu_s(triton::arch::Instruction& inst); + + //! The MUL semantics. + void mul_s(triton::arch::Instruction& inst); + + //! The MULH semantics. + void mulh_s(triton::arch::Instruction& inst); + + //! The MULHSU semantics. + void mulhsu_s(triton::arch::Instruction& inst); + + //! The MULHU semantics. + void mulhu_s(triton::arch::Instruction& inst); + + //! The MULW semantics. + void mulw_s(triton::arch::Instruction& inst); + + //! The OR semantics. + void or_s(triton::arch::Instruction& inst); + + //! The ORI semantics. + void ori_s(triton::arch::Instruction& inst); + + //! The REM semantics. + void rem_s(triton::arch::Instruction& inst); + + //! The REMU semantics. + void remu_s(triton::arch::Instruction& inst); + + //! The REMUW semantics. + void remuw_s(triton::arch::Instruction& inst); + + //! The REMW semantics. + void remw_s(triton::arch::Instruction& inst); + + //! The SB semantics. + void sb_s(triton::arch::Instruction& inst); + + //! The SD semantics. + void sd_s(triton::arch::Instruction& inst); + + //! The SH semantics. + void sh_s(triton::arch::Instruction& inst); + + //! The SLL semantics. + void sll_s(triton::arch::Instruction& inst); + + //! The SLLI semantics. + void slli_s(triton::arch::Instruction& inst); + + //! The SLLIW semantics. + void slliw_s(triton::arch::Instruction& inst); + + //! The SLLW semantics. + void sllw_s(triton::arch::Instruction& inst); + + //! The SLT semantics. + void slt_s(triton::arch::Instruction& inst); + + //! The SGTZ (SLT pseudo instruction) semantics. + void slt_sgtz_s(triton::arch::Instruction& inst); + + //! The SLTZ (SLT pseudo instruction) semantics. + void slt_sltz_s(triton::arch::Instruction& inst); + + //! The SLTI semantics. + void slti_s(triton::arch::Instruction& inst); + + //! The SLTIU semantics. + void sltiu_s(triton::arch::Instruction& inst); + + //! The The SEQZ (SLTIU pseudo instruction) semantics. + void sltiu_seqz_s(triton::arch::Instruction& inst); + + //! The SLTU semantics. + void sltu_s(triton::arch::Instruction& inst); + + //! The The SNEZ (SLTU pseudo instruction) semantics. + void sltu_snez_s(triton::arch::Instruction& inst); + + //! The SRA semantics. + void sra_s(triton::arch::Instruction& inst); + + //! The SRAI semantics. + void srai_s(triton::arch::Instruction& inst); + + //! The SRAIW semantics. + void sraiw_s(triton::arch::Instruction& inst); + + //! The SRAW semantics. + void sraw_s(triton::arch::Instruction& inst); + + //! The SRL semantics. + void srl_s(triton::arch::Instruction& inst); + + //! The SRLI semantics. + void srli_s(triton::arch::Instruction& inst); + + //! The SRLIW semantics. + void srliw_s(triton::arch::Instruction& inst); + + //! The SRLW semantics. + void srlw_s(triton::arch::Instruction& inst); + + //! The SUB semantics. + void sub_s(triton::arch::Instruction& inst); + + //! The SUBW semantics. + void subw_s(triton::arch::Instruction& inst); + + //! The SW semantics. + void sw_s(triton::arch::Instruction& inst); + + //! The XOR semantics. + void xor_s(triton::arch::Instruction& inst); + + //! The XORI semantics. + void xori_s(triton::arch::Instruction& inst); + }; + + /*! @} End of riscv namespace */ + }; + /*! @} End of arch namespace */ + }; +/*! @} End of triton namespace */ +}; + +#endif /* TRITON_RISCVSEMANTICS_H */ + diff --git a/src/libtriton/includes/triton/riscvSpecifications.hpp b/src/libtriton/includes/triton/riscvSpecifications.hpp new file mode 100644 index 000000000..4756eed37 --- /dev/null +++ b/src/libtriton/includes/triton/riscvSpecifications.hpp @@ -0,0 +1,365 @@ +// +//! \file +/* +** Copyright (C) - Triton +** +** This program is under the terms of the Apache License 2.0. +*/ + +#ifndef TRITON_RISCVSPECIFICATIONS_H +#define TRITON_RISCVSPECIFICATIONS_H + +#include +#include + +#include +#include +#include +#include + + + +//! The Triton namespace +namespace triton { +/*! + * \addtogroup triton + * @{ + */ + + //! The Architecture namespace + namespace arch { + /*! + * \ingroup triton + * \addtogroup arch + * @{ + */ + + //! The RISCV namespace + namespace riscv { + /*! + * \ingroup arch + * \addtogroup riscv + * @{ + */ + + //! \class riscvSpecifications + /*! \brief The riscvSpecifications class defines specifications about the RV32 and RV64 CPU */ + class riscvSpecifications { + protected: + //! List of registers specification available for this architecture. + std::unordered_map id2reg; + std::unordered_map name2id; + + public: + //! Constructor. + TRITON_EXPORT riscvSpecifications(triton::arch::architecture_e); + + //! Converts a capstone's register id to a triton's register id for RV64. + TRITON_EXPORT triton::arch::register_e capstoneRegisterToTritonRegister64(triton::uint32 id) const; + + //! Converts a capstone's register id to a triton's register id for RV32. + TRITON_EXPORT triton::arch::register_e capstoneRegisterToTritonRegister32(triton::uint32 id) const; + + //! Converts a capstone's instruction id to a triton's instruction id. + TRITON_EXPORT triton::uint32 capstoneInstructionToTritonInstruction(triton::uint32 id) const; + + //! Converts a capstone's group id to a triton's group id. + TRITON_EXPORT triton::arch::riscv::insn_group_e capstoneGroupToTritonGroup(triton::uint32 id) const; + + //! Returns memory access size if it is specified by instruction. + TRITON_EXPORT triton::uint32 getMemoryOperandSpecialSize(triton::uint32 id) const; + }; + + //! RISCV NOP instruction -- ADDI x0, x0, 0 + const triton::arch::Instruction nop = triton::arch::Instruction("\x13\x00\x00\x00", 4); + + //! The list of opcodes. + enum instruction_e { + ID_INS_INVALID = 0, + + ID_INS_ADD, + ID_INS_ADDI, + ID_INS_ADDIW, + ID_INS_ADDW, + ID_INS_AMOADD_D, + ID_INS_AMOADD_D_AQ, + ID_INS_AMOADD_D_AQ_RL, + ID_INS_AMOADD_D_RL, + ID_INS_AMOADD_W, + ID_INS_AMOADD_W_AQ, + ID_INS_AMOADD_W_AQ_RL, + ID_INS_AMOADD_W_RL, + ID_INS_AMOAND_D, + ID_INS_AMOAND_D_AQ, + ID_INS_AMOAND_D_AQ_RL, + ID_INS_AMOAND_D_RL, + ID_INS_AMOAND_W, + ID_INS_AMOAND_W_AQ, + ID_INS_AMOAND_W_AQ_RL, + ID_INS_AMOAND_W_RL, + ID_INS_AMOMAXU_D, + ID_INS_AMOMAXU_D_AQ, + ID_INS_AMOMAXU_D_AQ_RL, + ID_INS_AMOMAXU_D_RL, + ID_INS_AMOMAXU_W, + ID_INS_AMOMAXU_W_AQ, + ID_INS_AMOMAXU_W_AQ_RL, + ID_INS_AMOMAXU_W_RL, + ID_INS_AMOMAX_D, + ID_INS_AMOMAX_D_AQ, + ID_INS_AMOMAX_D_AQ_RL, + ID_INS_AMOMAX_D_RL, + ID_INS_AMOMAX_W, + ID_INS_AMOMAX_W_AQ, + ID_INS_AMOMAX_W_AQ_RL, + ID_INS_AMOMAX_W_RL, + ID_INS_AMOMINU_D, + ID_INS_AMOMINU_D_AQ, + ID_INS_AMOMINU_D_AQ_RL, + ID_INS_AMOMINU_D_RL, + ID_INS_AMOMINU_W, + ID_INS_AMOMINU_W_AQ, + ID_INS_AMOMINU_W_AQ_RL, + ID_INS_AMOMINU_W_RL, + ID_INS_AMOMIN_D, + ID_INS_AMOMIN_D_AQ, + ID_INS_AMOMIN_D_AQ_RL, + ID_INS_AMOMIN_D_RL, + ID_INS_AMOMIN_W, + ID_INS_AMOMIN_W_AQ, + ID_INS_AMOMIN_W_AQ_RL, + ID_INS_AMOMIN_W_RL, + ID_INS_AMOOR_D, + ID_INS_AMOOR_D_AQ, + ID_INS_AMOOR_D_AQ_RL, + ID_INS_AMOOR_D_RL, + ID_INS_AMOOR_W, + ID_INS_AMOOR_W_AQ, + ID_INS_AMOOR_W_AQ_RL, + ID_INS_AMOOR_W_RL, + ID_INS_AMOSWAP_D, + ID_INS_AMOSWAP_D_AQ, + ID_INS_AMOSWAP_D_AQ_RL, + ID_INS_AMOSWAP_D_RL, + ID_INS_AMOSWAP_W, + ID_INS_AMOSWAP_W_AQ, + ID_INS_AMOSWAP_W_AQ_RL, + ID_INS_AMOSWAP_W_RL, + ID_INS_AMOXOR_D, + ID_INS_AMOXOR_D_AQ, + ID_INS_AMOXOR_D_AQ_RL, + ID_INS_AMOXOR_D_RL, + ID_INS_AMOXOR_W, + ID_INS_AMOXOR_W_AQ, + ID_INS_AMOXOR_W_AQ_RL, + ID_INS_AMOXOR_W_RL, + ID_INS_AND, + ID_INS_ANDI, + ID_INS_AUIPC, + ID_INS_BEQ, + ID_INS_BGE, + ID_INS_BGEU, + ID_INS_BLT, + ID_INS_BLTU, + ID_INS_BNE, + ID_INS_CSRRC, + ID_INS_CSRRCI, + ID_INS_CSRRS, + ID_INS_CSRRSI, + ID_INS_CSRRW, + ID_INS_CSRRWI, + /* Compressed instructions */ + ID_INS_C_ADD, + ID_INS_C_ADDI, + ID_INS_C_ADDI16SP, + ID_INS_C_ADDI4SPN, + ID_INS_C_ADDIW, + ID_INS_C_ADDW, + ID_INS_C_AND, + ID_INS_C_ANDI, + ID_INS_C_BEQZ, + ID_INS_C_BNEZ, + ID_INS_C_EBREAK, + ID_INS_C_FLD, + ID_INS_C_FLDSP, + ID_INS_C_FLW, + ID_INS_C_FLWSP, + ID_INS_C_FSD, + ID_INS_C_FSDSP, + ID_INS_C_FSW, + ID_INS_C_FSWSP, + ID_INS_C_J, + ID_INS_C_JAL, + ID_INS_C_JALR, + ID_INS_C_JR, + ID_INS_C_LD, + ID_INS_C_LDSP, + ID_INS_C_LI, + ID_INS_C_LUI, + ID_INS_C_LW, + ID_INS_C_LWSP, + ID_INS_C_MV, + ID_INS_C_NOP, + ID_INS_C_OR, + ID_INS_C_SD, + ID_INS_C_SDSP, + ID_INS_C_SLLI, + ID_INS_C_SRAI, + ID_INS_C_SRLI, + ID_INS_C_SUB, + ID_INS_C_SUBW, + ID_INS_C_SW, + ID_INS_C_SWSP, + ID_INS_C_UNIMP, + ID_INS_C_XOR, + /* End of compressed instructions */ + ID_INS_DIV, + ID_INS_DIVU, + ID_INS_DIVUW, + ID_INS_DIVW, + ID_INS_EBREAK, + ID_INS_ECALL, + ID_INS_FADD_D, + ID_INS_FADD_S, + ID_INS_FCLASS_D, + ID_INS_FCLASS_S, + ID_INS_FCVT_D_L, + ID_INS_FCVT_D_LU, + ID_INS_FCVT_D_S, + ID_INS_FCVT_D_W, + ID_INS_FCVT_D_WU, + ID_INS_FCVT_LU_D, + ID_INS_FCVT_LU_S, + ID_INS_FCVT_L_D, + ID_INS_FCVT_L_S, + ID_INS_FCVT_S_D, + ID_INS_FCVT_S_L, + ID_INS_FCVT_S_LU, + ID_INS_FCVT_S_W, + ID_INS_FCVT_S_WU, + ID_INS_FCVT_WU_D, + ID_INS_FCVT_WU_S, + ID_INS_FCVT_W_D, + ID_INS_FCVT_W_S, + ID_INS_FDIV_D, + ID_INS_FDIV_S, + ID_INS_FENCE, + ID_INS_FENCE_I, + ID_INS_FENCE_TSO, + ID_INS_FEQ_D, + ID_INS_FEQ_S, + ID_INS_FLD, + ID_INS_FLE_D, + ID_INS_FLE_S, + ID_INS_FLT_D, + ID_INS_FLT_S, + ID_INS_FLW, + ID_INS_FMADD_D, + ID_INS_FMADD_S, + ID_INS_FMAX_D, + ID_INS_FMAX_S, + ID_INS_FMIN_D, + ID_INS_FMIN_S, + ID_INS_FMSUB_D, + ID_INS_FMSUB_S, + ID_INS_FMUL_D, + ID_INS_FMUL_S, + ID_INS_FMV_D_X, + ID_INS_FMV_W_X, + ID_INS_FMV_X_D, + ID_INS_FMV_X_W, + ID_INS_FNMADD_D, + ID_INS_FNMADD_S, + ID_INS_FNMSUB_D, + ID_INS_FNMSUB_S, + ID_INS_FSD, + ID_INS_FSGNJN_D, + ID_INS_FSGNJN_S, + ID_INS_FSGNJX_D, + ID_INS_FSGNJX_S, + ID_INS_FSGNJ_D, + ID_INS_FSGNJ_S, + ID_INS_FSQRT_D, + ID_INS_FSQRT_S, + ID_INS_FSUB_D, + ID_INS_FSUB_S, + ID_INS_FSW, + ID_INS_JAL, + ID_INS_JALR, + ID_INS_LB, + ID_INS_LBU, + ID_INS_LD, + ID_INS_LH, + ID_INS_LHU, + ID_INS_LR_D, + ID_INS_LR_D_AQ, + ID_INS_LR_D_AQ_RL, + ID_INS_LR_D_RL, + ID_INS_LR_W, + ID_INS_LR_W_AQ, + ID_INS_LR_W_AQ_RL, + ID_INS_LR_W_RL, + ID_INS_LUI, + ID_INS_LW, + ID_INS_LWU, + ID_INS_MRET, + ID_INS_MUL, + ID_INS_MULH, + ID_INS_MULHSU, + ID_INS_MULHU, + ID_INS_MULW, + ID_INS_OR, + ID_INS_ORI, + ID_INS_REM, + ID_INS_REMU, + ID_INS_REMUW, + ID_INS_REMW, + ID_INS_SB, + ID_INS_SC_D, + ID_INS_SC_D_AQ, + ID_INS_SC_D_AQ_RL, + ID_INS_SC_D_RL, + ID_INS_SC_W, + ID_INS_SC_W_AQ, + ID_INS_SC_W_AQ_RL, + ID_INS_SC_W_RL, + ID_INS_SD, + ID_INS_SFENCE_VMA, + ID_INS_SH, + ID_INS_SLL, + ID_INS_SLLI, + ID_INS_SLLIW, + ID_INS_SLLW, + ID_INS_SLT, + ID_INS_SLTI, + ID_INS_SLTIU, + ID_INS_SLTU, + ID_INS_SRA, + ID_INS_SRAI, + ID_INS_SRAIW, + ID_INS_SRAW, + ID_INS_SRET, + ID_INS_SRL, + ID_INS_SRLI, + ID_INS_SRLIW, + ID_INS_SRLW, + ID_INS_SUB, + ID_INS_SUBW, + ID_INS_SW, + ID_INS_UNIMP, + ID_INS_URET, + ID_INS_WFI, + ID_INS_XOR, + ID_INS_XORI, + + ID_INS_ENDING, //! + }; + + /*! @} End of RISCV namespace */ + }; + /*! @} End of arch namespace */ + }; +/*! @} End of triton namespace */ +}; + +#endif /* TRITON_RISCVSPECIFICATIONS_H */ diff --git a/src/libtriton/includes/triton/shortcutRegister.hpp b/src/libtriton/includes/triton/shortcutRegister.hpp index eb1e6fc7c..d17088233 100644 --- a/src/libtriton/includes/triton/shortcutRegister.hpp +++ b/src/libtriton/includes/triton/shortcutRegister.hpp @@ -49,6 +49,14 @@ namespace triton { #define REG_SPEC_NO_CAPSTONE REG_SPEC #include "triton/arm32.spec" + #ifdef COMPILE_RISCV + // ShortcutRegister set for RV32 is the same, + #define REG_SPEC(_0, _1, LOWER_NAME, _2, _3, _4, _5) \ + triton::arch::Register riscv_##LOWER_NAME; + #define REG_SPEC_NO_CAPSTONE REG_SPEC + #include "triton/riscv64.spec" + #endif + /*! Constructor */ ShortcutRegister() {}; @@ -69,6 +77,14 @@ namespace triton { this->arm32_##LOWER_NAME = triton::arch::Register(); #define REG_SPEC_NO_CAPSTONE REG_SPEC #include "triton/arm32.spec" + + #ifdef COMPILE_RISCV + // ShortcutRegister set for RV32 is the same, + #define REG_SPEC(_0, _1, LOWER_NAME, _2, _3, _4, _5) \ + this->riscv_##LOWER_NAME = triton::arch::Register(); + #define REG_SPEC_NO_CAPSTONE REG_SPEC + #include "triton/riscv64.spec" + #endif }; /*! Inits the shortcut */ @@ -130,6 +146,34 @@ namespace triton { } break; + #ifdef COMPILE_RISCV + case triton::arch::ARCH_RV64: { + #define REG_SPEC(CS_UPPER_NAME, UPPER_NAME, LOWER_NAME, ABI_NAME, RISCV_UPPER, RISCV_LOWER, MUTABLE) \ + this->riscv_##LOWER_NAME = triton::arch::Register(triton::arch::ID_REG_RV64_##UPPER_NAME, \ + #LOWER_NAME, \ + triton::arch::ID_REG_RV64_##UPPER_NAME, \ + RISCV_UPPER, \ + RISCV_LOWER, \ + MUTABLE); + #define REG_SPEC_NO_CAPSTONE REG_SPEC + #include "triton/riscv64.spec" + } + break; + + case triton::arch::ARCH_RV32: { + #define REG_SPEC(CS_UPPER_NAME, UPPER_NAME, LOWER_NAME, ABI_NAME, RISCV_UPPER, RISCV_LOWER, MUTABLE) \ + this->riscv_##LOWER_NAME = triton::arch::Register(triton::arch::ID_REG_RV32_##UPPER_NAME, \ + #LOWER_NAME, \ + triton::arch::ID_REG_RV32_##UPPER_NAME, \ + RISCV_UPPER, \ + RISCV_LOWER, \ + MUTABLE); + #define REG_SPEC_NO_CAPSTONE REG_SPEC + #include "triton/riscv32.spec" + } + break; + #endif + default: throw triton::exceptions::Architecture("ShortcutRegister::init(): Invalid architecture."); } diff --git a/src/libtriton/includes/triton/tritonTypes.hpp b/src/libtriton/includes/triton/tritonTypes.hpp index 5e59c81f7..2deb56bbb 100644 --- a/src/libtriton/includes/triton/tritonTypes.hpp +++ b/src/libtriton/includes/triton/tritonTypes.hpp @@ -105,7 +105,7 @@ namespace triton { //! unsigned MAX_INT 32 or 64 bits according to the CPU. typedef std::size_t usize; - #if defined(__x86_64__) || defined(_M_X64) || defined(__aarch64__) + #if defined(__x86_64__) || defined(_M_X64) || defined(__aarch64__) || defined(__riscv64__) //! unsigned long long if the arch is 64-bits. typedef unsigned long long __uint; diff --git a/src/scripts/docker/Dockerfile b/src/scripts/docker/Dockerfile index 6e027846f..cf08bac3b 100644 --- a/src/scripts/docker/Dockerfile +++ b/src/scripts/docker/Dockerfile @@ -58,5 +58,5 @@ RUN echo "[+] Download, build and install Capstone" && \ wget -q https://github.com/capstone-engine/capstone/archive/refs/tags/5.0.1.tar.gz -O capstone-5.0.1.tar.gz && \ tar xf capstone-5.0.1.tar.gz && \ cd ./capstone-5.0.1 && \ - ./make.sh && \ + CAPSTONE_ARCHS="arm aarch64 riscv x86" ./make.sh && \ sudo make install diff --git a/src/testers/CMakeLists.txt b/src/testers/CMakeLists.txt index 745a809eb..74b65ee05 100644 --- a/src/testers/CMakeLists.txt +++ b/src/testers/CMakeLists.txt @@ -5,6 +5,10 @@ if((${CMAKE_SYSTEM_NAME} MATCHES "Linux" OR ${CMAKE_SYSTEM_NAME} MATCHES "Darwin add_test(NAME UnicornAArch64Semantics COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_LIST_DIR}/aarch64/unicorn_test_aarch64.py) add_test(NAME UnicornX86Semantics COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_LIST_DIR}/x86/unicorn_test_x86.py) + if(${CS_VERSION_MAJOR} GREATER_EQUAL 5) + add_test(NAME UnicornRiscv64Semantics COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_LIST_DIR}/riscv/unicorn_test_riscv64.py) + add_test(NAME UnicornRiscv32Semantics COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_LIST_DIR}/riscv/unicorn_test_riscv32.py) + endif() add_test(NAME UnicornARM32Semantics1 COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_LIST_DIR}/arm32/unicorn_test_arm32_branch_arm_1.py) add_test(NAME UnicornARM32Semantics2 COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_LIST_DIR}/arm32/unicorn_test_arm32_branch_arm_2.py) add_test(NAME UnicornARM32Semantics3 COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_LIST_DIR}/arm32/unicorn_test_arm32_branch_pc_arm_1.py) @@ -81,4 +85,12 @@ if((${CMAKE_SYSTEM_NAME} MATCHES "Linux" OR ${CMAKE_SYSTEM_NAME} MATCHES "Darwin UnicornARM32Semantics35 PROPERTY ENVIRONMENT "PYTHONPATH=$" ) + if(${CS_VERSION_MAJOR} GREATER_EQUAL 5) + set_property(TEST + UnicornRiscv64Semantics + UnicornRiscv32Semantics + APPEND + PROPERTY ENVIRONMENT "PYTHONPATH=$" + ) + endif() endif() diff --git a/src/testers/riscv/unicorn_test_riscv32.py b/src/testers/riscv/unicorn_test_riscv32.py new file mode 100644 index 000000000..946963014 --- /dev/null +++ b/src/testers/riscv/unicorn_test_riscv32.py @@ -0,0 +1,646 @@ +#!/usr/bin/env python3 +## -*- coding: utf-8 -*- + +from __future__ import print_function + +from triton import * +from unicorn import * +from unicorn.riscv_const import * +from struct import pack + +import sys +import pprint + +ADDR = 0x100000 +STACK = 0x200000 +HEAP = 0x300000 +SIZE = 5 * 1024 * 1024 + +CODE = [ + # ADDI + (b"\x93\x05\x16\x00", "addi x11, x12, #1"), + (b"\x13\x00\xe0\x00", "addi x0, x0, #0xe"), + (b"\x13\x05\x00\x00", "addi x10, x0, #0"), + (b"\x13\x00\x00\x00", "addi x0, x0, #0"), # nop + (b"\x13\x00\x00\x00", "addi x0, x0, #0"), # nop + (b"\x13\x00\x00\x00", "addi x0, x0, #0"), # nop + (b"\x93\x05\x16\x00", "addi x11, x12, #1"), + (b"\x93\x05\x06\x00", "addi x11, x12, #0"), + (b"\x13\x05\xe0\x00", "addi x10, x0, #0xe"), + (b"\x13\x03\x43\x00", "addi x6, x6, #4"), + (b"\x49\x13", "c.addi x1, x1, #1"), + (b"\x49\x13", "c.addi x6, x6, #-0xe"), + (b"\x09\x16", "c.addi x12, x12, #-30"), + (b"\x11\x01", "c.addi x2, x2, #4"), + (b"\x75\x61", "c.addi16sp x2, x2, #368"), + (b"\x40\x00", "c.addi4spn x8, x2, #4"), + (b"\x8c\x02", "c.addi4spn x10, x2, #320"), + (b"\x85\x47", "c.li x15, #1"), + (b"\x49\x4c", "c.li x24, #18"), + (b"\x09\x54", "c.li x8, #-30"), + (b"\x01\x00", "c.nop"), + (b"\x5d\x00", "c.nop 23"), + (b"\x65\x00", "c.nop 25"), + + # ADD + (b"\x33\x05\x00\x00", "add x10, x0, x0"), + (b"\x33\x86\xb0\x00", "add x12, x1, x11"), + (b"\xb3\x05\x06\x00", "add x11, x12, x0"), + (b"\xb3\x05\xc0\x00", "add x11, x0, x12"), + (b"\xbe\x95", "c.add x11, x11, x15"), + (b"\x0a\x9a", "c.add x20, x20, x2"), + (b"\x0a\x88", "c.mv x16, x2"), + (b"\xb2\x8a", "c.mv x21, x12"), + + # AND(I) + (b"\x13\xf0\xf0\x0f", "andi x0, x1, #0xff"), + (b"\x13\x75\xf0\x0f", "andi x10, x0, #0xff"), + (b"\x93\x76\x17\x00", "andi x13, x14, #0x01"), + (b"\x93\x76\x07\x01", "andi x13, x14, #0x10"), + (b"\x49\x13", "c.andi x14, x14, #2"), + (b"\x19\x98", "c.andi x8, x8, #-26"), + (b"\xb3\x71\x52\x00", "and x3, x4, x5"), + (b"\xb3\x75\xc5\x00", "and x11, x10, x12"), + (b"\x71\x8f", "c.and x14, x14, x12"), + + # AUIPC + (b"\x17\xe5\xcd\xab", "auipc x10, #0xabcde"), + (b"\x17\x15\x00\x00", "auipc x10, #0x1"), + (b"\x17\xd9\xf1\xe2", "auipc x18, #0xf1e2d"), + (b"\x17\x10\x00\x00", "auipc x0, #0x1"), + + # SB / SH / SW + (b"\x23\x0c\xa1\x00", "sb x10, 0x18(sp)"), + (b"\xa3\x0c\xa1\x00", "sb x10, 0x19(sp)"), + (b"\x23\x00\xc1\x02", "sb x12, 0x20(sp)"), + (b"\x23\x2a\xe1\x00", "sw x14, 0x14(sp)"), + (b"\x23\x20\xa1\x02", "sw x10, 0x20(sp)"), + (b"\x23\x11\xe1\x02", "sh x14, 0x22(sp)"), + (b"\x23\x10\x01\x00", "sh x0, 0(sp)"), + (b"\x23\x12\xa1\x02", "sh x10, 0x24(sp)"), + (b"\x23\x20\xe1\x00", "sw x14, 0(sp)"), + + # LB / LH / LW + (b"\x03\x25\x01\x00", "lw x10, 0(sp)"), + (b"\x03\x07\x01\x00", "lb x14, 0(sp)"), + (b"\x03\x07\x01\x02", "lb x14, 0x20(sp)"), + (b"\x83\x15\x81\x01", "lh x11, 0x18(sp)"), + # LBU / LHU + (b"\x03\x4a\x91\x01", "lbu x20, 0x19(sp)"), + (b"\x83\x55\x41\x02", "lhu x11, 0x24(sp)"), + + # Compressed load/store + (b"\x0a\x85", "c.mv x10, x2"), + (b"\x4c\x49", "c.lw x11, 0x14(x10)"), + (b"\x42\x43", "c.lwsp x6, 0x10(sp)"), + (b"\x10\xcd", "c.sw x12, 0x18(x10)"), + (b"\x42\xc8", "c.swsp x16, 0x10(sp)"), + + #(b"\x01\x25", "c.jal 0x600"), # 32-bit only + + # LUI + (b"\x37\xfa\xff\xff", "lui x20, #0xfffff"), + (b"\xb7\x0a\x01\x01", "lui x21, #0x1010"), + (b"\x37\x5b\x34\x12", "lui x22, #0x12345"), + (b"\x37\x00\x00\x00", "lui x0, #0"), + (b"\x65\x67", "c.lui x14, #0x19"), + (b"\x75\x74", "c.lui x8, #0xffffd"), + + # OR(I) + (b"\x93\x65\x05\x0f", "ori x11, x10, #0xf0"), + (b"\x93\x65\x76\x00", "ori x11, x12, #0x7"), + (b"\x33\x66\xb5\x00", "or x12, x10, x11"), + (b"\x51\x8f", "c.or x14, x14, x12"), + + # MUL + (b"\x33\x85\xb5\x02", "mul x10, x11, x11"), + (b"\x33\x86\xc5\x02", "mul x12, x11, x12"), + (b"\x33\x86\xc5\x02", "mul x12, x11, x12"), + (b"\x33\x86\xc5\x02", "mul x12, x11, x12"), + (b"\x33\x86\xc5\x02", "mul x12, x11, x12"), + (b"\x33\x86\xc5\x02", "mul x12, x11, x12"), + (b"\x33\x86\xc5\x02", "mul x12, x11, x12"), + (b"\x33\x86\xc5\x02", "mul x12, x11, x12"), + (b"\x33\x86\xc5\x02", "mul x12, x11, x12"), + (b"\x33\x86\xc5\x02", "mul x12, x11, x12"), + (b"\x33\x86\xc5\x02", "mul x12, x11, x12"), + (b"\x33\x86\xc5\x02", "mul x12, x11, x12"), + (b"\x33\x86\xc5\x02", "mul x12, x11, x12"), + (b"\x33\x86\xc5\x02", "mul x12, x11, x12"), + (b"\x33\x86\xc5\x02", "mul x12, x11, x12"), + (b"\x33\x86\xc5\x02", "mul x12, x11, x12"), + (b"\x33\x07\xa0\x02", "mul x14, x0, x10"), + (b"\x33\x17\xc6\x02", "mulh x14, x12, x12"), + (b"\x33\x27\xc6\x02", "mulhsu x14, x12, x12"), + (b"\x33\x27\xe6\x02", "mulhsu x14, x12, x14"), + (b"\x33\x27\xe6\x02", "mulhsu x14, x12, x14"), + (b"\x33\x27\xe6\x02", "mulhsu x14, x12, x14"), + (b"\xb3\x26\xb5\x02", "mulhsu x13, x10, x11"), + (b"\x33\x37\xe6\x02", "mulhu x14, x12, x14"), + (b"\xb3\x36\xe5\x02", "mulhu x13, x10, x14"), + + # DIV/U + (b"\x33\x46\xa6\x02", "div x12, x12, x10"), + (b"\x33\x56\xa6\x02", "divu x12, x12, x10"), + # div-by-zero corner case + (b"\xb7\x08\x00\x00", "lui x17, #0"), + (b"\xb3\x45\x16\x03", "div x11, x12, x17"), + (b"\xb3\x58\x16\x03", "divu x17, x12, x17"), + + # REM/U + (b"\xb3\x65\xa6\x02", "rem x11, x12, x10"), + (b"\xb3\x75\xa6\x02", "remu x11, x12, x10"), + # corner cases + (b"\xb7\x08\x00\x00", "lui x17, #0"), + (b"\xb3\x65\x16\x03", "rem x11, x12, x17"), # division by zero + (b"\xb3\x75\x17\x03", "remu x11, x14, x17"), + (b"\xb7\xf8\xff\xff", "lui x17, #0xfffff"), + (b"\x93\x98\x38\x01", "slli x17, x17, #19"), + (b"\x13\x05\xf0\xff", "addi x10, x0, #-1"), + (b"\xb3\xe5\xa8\x02", "rem x11, x17, x10"), # signed overflow + + # SUB/W + (b"\xb3\x05\xa0\x40", "sub x11, x0, x10"), + (b"\xb3\x05\xb0\x40", "sub x11, x0, x11"), # neg + (b"\xb3\x05\xa7\x40", "sub x11, x14, x10"), + (b"\x33\x00\xe7\x40", "sub x0, x14, x14"), + (b"\x89\x8d", "c.sub x11, x11, x10"), + + # XOR(I) + (b"\xb3\x45\xb5\x00", "xor x11, x10, x11"), + (b"\x33\x45\xa5\x00", "xor x10, x10, x10"), + (b"\x33\x45\x00\x00", "xor x10, x0, x0"), + (b"\xb9\x8f", "c.xor x15, x15, x14"), + (b"\x93\x47\x36\x0f", "xori x15, x12, #0xf3"), + (b"\x93\x47\xe6\xff", "xori x15, x12, #-2"), + (b"\x93\x47\xf6\xff", "xori x15, x12, #-1"), # not + + # SLT + (b"\x33\x28\xb5\x00", "slt x16, x10, x11"), + (b"\x33\x28\x84\x00", "slt x16, x8, x8"), + (b"\xb3\xa0\x05\x00", "slt x1, x11, x0"), # sltz + (b"\xb3\x20\xb0\x00", "slt x1, x0, x11"), # sgtz + (b"\xb3\x20\x00\x00", "slt x1, x0, x0"), # sltz + (b"\xb3\xa0\xa0\x00", "slt x1, x1, x10"), + # SLTI + (b"\x13\xa8\x15\x00", "slti x16, x11, #1"), + (b"\x13\x28\x87\xff", "slti x16, x14, #-8"), + (b"\x13\x28\xd7\x01", "slti x16, x14, #29"), + # SLT(I)U + (b"\x93\x30\x15\x00", "sltiu x1, x10, #1"), # seqz + (b"\x13\xb8\x05\x01", "sltiu x16, x11, #0x10"), + (b"\x13\xb8\xb5\xff", "sltiu x16, x11, #-5"), + (b"\x33\xb8\xb5\x00", "sltu x16, x11, x11"), + (b"\x33\x38\xb5\x00", "sltu x16, x10, x11"), + (b"\xb3\x30\xa0\x00", "sltu x1, x0, x10"), # snez + (b"\xb3\x30\xb0\x00", "sltu x1, x0, x11"), # snez + + # SLL + (b"\x13\xe5\xf5\x0f", "ori x10, x11, #0xff"), + (b"\x93\x65\xe6\x0f", "ori x11, x12, #0xfe"), + (b"\x33\x15\xb5\x00", "sll x10, x10, x11"), + (b"\xb3\x15\xb5\x00", "sll x11, x10, x11"), + (b"\xb3\x15\xb5\x00", "sll x12, x13, x12"), + (b"\x33\x16\xf8\x00", "sll x12, x16, x15"), + (b"\x93\x10\x85\x00", "slli x1, x10, #8"), + (b"\x93\x15\xf5\x00", "slli x11, x10, #0xf"), + (b"\x12\x06", "c.slli x12, x12, #0x4"), + (b"\xf2\x0f", "c.slli x31, x31, #0x1c"), + # SRA + (b"\x13\xe5\xf5\x0f", "ori x10, x11, #0xff"), + (b"\x93\x65\xe6\x0f", "ori x11, x12, #0xfe"), + (b"\x33\x55\xb5\x40", "sra x10, x10, x11"), + (b"\xb3\x55\xb5\x40", "sra x11, x10, x11"), + (b"\x33\xd6\xe7\x40", "sra x12, x15, x14"), + (b"\xb3\x55\xb5\x40", "sra x11, x10, x11"), + (b"\x93\x55\x85\x40", "srai x11, x10, #8"), + (b"\x93\x55\xf5\x40", "srai x11, x10, #0xf"), + (b"\x85\x85", "c.srai x11, x11, #0x1"), + (b"\xb7\x05\x00\x88", "lui x11, #0x88000"), + (b"\xfd\x85", "c.srai x11, x11, #0x1f"), + # SRL + (b"\x13\xe5\xf5\x0f", "ori x10, x11, #0xff"), + (b"\x93\x65\xe6\x0f", "ori x11, x12, #0xfe"), + (b"\x33\x55\xb5\x00", "srl x10, x10, x11"), + (b"\xb3\x55\xb5\x00", "srl x11, x10, x11"), + (b"\x33\xd6\xe7\x00", "srl x12, x15, x14"), + (b"\xb3\x55\xb5\x00", "srl x11, x10, x11"), + (b"\x93\x55\x85\x00", "srli x11, x10, #8"), + (b"\x93\x55\xf5\x00", "srli x11, x10, #0xf"), + (b"\x85\x81", "c.srli x11, x11, #0x1"), + (b"\xb7\x05\x00\x88", "lui x11, #0x88000"), + (b"\xfd\x81", "c.srli x11, x11, #0x1f"), + +] + +def emu_with_unicorn(opcode, istate): + # Initialize emulator in RV32 mode + mu = Uc(UC_ARCH_RISCV, UC_MODE_RISCV32) + + # map memory for this emulation + mu.mem_map(ADDR, SIZE) + + # write machine code to be emulated to memory + index = 0 + for op, _ in CODE: + mu.mem_write(ADDR+index, op) + index += len(op) + + mu.mem_write(STACK, bytes(istate['stack'])) + mu.mem_write(HEAP, bytes(istate['heap'])) + mu.reg_write(UC_RISCV_REG_X0, istate['x0']) + mu.reg_write(UC_RISCV_REG_X1, istate['x1']) + mu.reg_write(UC_RISCV_REG_X2, istate['x2']) + mu.reg_write(UC_RISCV_REG_X3, istate['x3']) + mu.reg_write(UC_RISCV_REG_X4, istate['x4']) + mu.reg_write(UC_RISCV_REG_X5, istate['x5']) + mu.reg_write(UC_RISCV_REG_X6, istate['x6']) + mu.reg_write(UC_RISCV_REG_X7, istate['x7']) + mu.reg_write(UC_RISCV_REG_X8, istate['x8']) + mu.reg_write(UC_RISCV_REG_X9, istate['x9']) + mu.reg_write(UC_RISCV_REG_X10, istate['x10']) + mu.reg_write(UC_RISCV_REG_X11, istate['x11']) + mu.reg_write(UC_RISCV_REG_X12, istate['x12']) + mu.reg_write(UC_RISCV_REG_X13, istate['x13']) + mu.reg_write(UC_RISCV_REG_X14, istate['x14']) + mu.reg_write(UC_RISCV_REG_X15, istate['x15']) + mu.reg_write(UC_RISCV_REG_X16, istate['x16']) + mu.reg_write(UC_RISCV_REG_X17, istate['x17']) + mu.reg_write(UC_RISCV_REG_X18, istate['x18']) + mu.reg_write(UC_RISCV_REG_X19, istate['x19']) + mu.reg_write(UC_RISCV_REG_X20, istate['x20']) + mu.reg_write(UC_RISCV_REG_X21, istate['x21']) + mu.reg_write(UC_RISCV_REG_X22, istate['x22']) + mu.reg_write(UC_RISCV_REG_X23, istate['x23']) + mu.reg_write(UC_RISCV_REG_X24, istate['x24']) + mu.reg_write(UC_RISCV_REG_X25, istate['x25']) + mu.reg_write(UC_RISCV_REG_X26, istate['x26']) + mu.reg_write(UC_RISCV_REG_X27, istate['x27']) + mu.reg_write(UC_RISCV_REG_X28, istate['x28']) + mu.reg_write(UC_RISCV_REG_X29, istate['x29']) + mu.reg_write(UC_RISCV_REG_X30, istate['x30']) + mu.reg_write(UC_RISCV_REG_X31, istate['x31']) + mu.reg_write(UC_RISCV_REG_F0, istate['f0']) + mu.reg_write(UC_RISCV_REG_F1, istate['f1']) + mu.reg_write(UC_RISCV_REG_F2, istate['f2']) + mu.reg_write(UC_RISCV_REG_F3, istate['f3']) + mu.reg_write(UC_RISCV_REG_F4, istate['f4']) + mu.reg_write(UC_RISCV_REG_F5, istate['f5']) + mu.reg_write(UC_RISCV_REG_F6, istate['f6']) + mu.reg_write(UC_RISCV_REG_F7, istate['f7']) + mu.reg_write(UC_RISCV_REG_F8, istate['f8']) + mu.reg_write(UC_RISCV_REG_F9, istate['f9']) + mu.reg_write(UC_RISCV_REG_F10, istate['f10']) + mu.reg_write(UC_RISCV_REG_F11, istate['f11']) + mu.reg_write(UC_RISCV_REG_F12, istate['f12']) + mu.reg_write(UC_RISCV_REG_F13, istate['f13']) + mu.reg_write(UC_RISCV_REG_F14, istate['f14']) + mu.reg_write(UC_RISCV_REG_F15, istate['f15']) + mu.reg_write(UC_RISCV_REG_F16, istate['f16']) + mu.reg_write(UC_RISCV_REG_F17, istate['f17']) + mu.reg_write(UC_RISCV_REG_F18, istate['f18']) + mu.reg_write(UC_RISCV_REG_F19, istate['f19']) + mu.reg_write(UC_RISCV_REG_F20, istate['f20']) + mu.reg_write(UC_RISCV_REG_F21, istate['f21']) + mu.reg_write(UC_RISCV_REG_F22, istate['f22']) + mu.reg_write(UC_RISCV_REG_F23, istate['f23']) + mu.reg_write(UC_RISCV_REG_F24, istate['f24']) + mu.reg_write(UC_RISCV_REG_F25, istate['f25']) + mu.reg_write(UC_RISCV_REG_F26, istate['f26']) + mu.reg_write(UC_RISCV_REG_F27, istate['f27']) + mu.reg_write(UC_RISCV_REG_F28, istate['f28']) + mu.reg_write(UC_RISCV_REG_F29, istate['f29']) + mu.reg_write(UC_RISCV_REG_F30, istate['f30']) + mu.reg_write(UC_RISCV_REG_F31, istate['f31']) + mu.reg_write(UC_RISCV_REG_PC, istate['pc']) + + # emulate code in infinite time & unlimited instructions + mu.emu_start(istate['pc'], istate['pc'] + len(opcode), 0, 1) + + ostate = { + "stack": mu.mem_read(STACK, 0x100), + "heap": mu.mem_read(HEAP, 0x100), + "x0": mu.reg_read(UC_RISCV_REG_X0), + "x1": mu.reg_read(UC_RISCV_REG_X1), + "x2": mu.reg_read(UC_RISCV_REG_X2), + "x3": mu.reg_read(UC_RISCV_REG_X3), + "x4": mu.reg_read(UC_RISCV_REG_X4), + "x5": mu.reg_read(UC_RISCV_REG_X5), + "x6": mu.reg_read(UC_RISCV_REG_X6), + "x7": mu.reg_read(UC_RISCV_REG_X7), + "x8": mu.reg_read(UC_RISCV_REG_X8), + "x9": mu.reg_read(UC_RISCV_REG_X9), + "x10": mu.reg_read(UC_RISCV_REG_X10), + "x11": mu.reg_read(UC_RISCV_REG_X11), + "x12": mu.reg_read(UC_RISCV_REG_X12), + "x13": mu.reg_read(UC_RISCV_REG_X13), + "x14": mu.reg_read(UC_RISCV_REG_X14), + "x15": mu.reg_read(UC_RISCV_REG_X15), + "x16": mu.reg_read(UC_RISCV_REG_X16), + "x17": mu.reg_read(UC_RISCV_REG_X17), + "x18": mu.reg_read(UC_RISCV_REG_X18), + "x19": mu.reg_read(UC_RISCV_REG_X19), + "x20": mu.reg_read(UC_RISCV_REG_X20), + "x21": mu.reg_read(UC_RISCV_REG_X21), + "x22": mu.reg_read(UC_RISCV_REG_X22), + "x23": mu.reg_read(UC_RISCV_REG_X23), + "x24": mu.reg_read(UC_RISCV_REG_X24), + "x25": mu.reg_read(UC_RISCV_REG_X25), + "x26": mu.reg_read(UC_RISCV_REG_X26), + "x27": mu.reg_read(UC_RISCV_REG_X27), + "x28": mu.reg_read(UC_RISCV_REG_X28), + "x29": mu.reg_read(UC_RISCV_REG_X29), + "x30": mu.reg_read(UC_RISCV_REG_X30), + "x31": mu.reg_read(UC_RISCV_REG_X31), + "f0": mu.reg_read(UC_RISCV_REG_F0), + "f1": mu.reg_read(UC_RISCV_REG_F1), + "f2": mu.reg_read(UC_RISCV_REG_F2), + "f3": mu.reg_read(UC_RISCV_REG_F3), + "f4": mu.reg_read(UC_RISCV_REG_F4), + "f5": mu.reg_read(UC_RISCV_REG_F5), + "f6": mu.reg_read(UC_RISCV_REG_F6), + "f7": mu.reg_read(UC_RISCV_REG_F7), + "f8": mu.reg_read(UC_RISCV_REG_F8), + "f9": mu.reg_read(UC_RISCV_REG_F9), + "f10": mu.reg_read(UC_RISCV_REG_F10), + "f11": mu.reg_read(UC_RISCV_REG_F11), + "f12": mu.reg_read(UC_RISCV_REG_F12), + "f13": mu.reg_read(UC_RISCV_REG_F13), + "f14": mu.reg_read(UC_RISCV_REG_F14), + "f15": mu.reg_read(UC_RISCV_REG_F15), + "f16": mu.reg_read(UC_RISCV_REG_F16), + "f17": mu.reg_read(UC_RISCV_REG_F17), + "f18": mu.reg_read(UC_RISCV_REG_F18), + "f19": mu.reg_read(UC_RISCV_REG_F19), + "f20": mu.reg_read(UC_RISCV_REG_F20), + "f21": mu.reg_read(UC_RISCV_REG_F21), + "f22": mu.reg_read(UC_RISCV_REG_F22), + "f23": mu.reg_read(UC_RISCV_REG_F23), + "f24": mu.reg_read(UC_RISCV_REG_F24), + "f25": mu.reg_read(UC_RISCV_REG_F25), + "f26": mu.reg_read(UC_RISCV_REG_F26), + "f27": mu.reg_read(UC_RISCV_REG_F27), + "f28": mu.reg_read(UC_RISCV_REG_F28), + "f29": mu.reg_read(UC_RISCV_REG_F29), + "f30": mu.reg_read(UC_RISCV_REG_F30), + "f31": mu.reg_read(UC_RISCV_REG_F31), + "pc": mu.reg_read(UC_RISCV_REG_PC), + } + return ostate + + +def emu_with_triton(opcode, istate): + ctx = TritonContext() + ctx.setArchitecture(ARCH.RV32) + + inst = Instruction(opcode) + inst.setAddress(istate['pc']) + + ctx.setConcreteMemoryAreaValue(STACK, bytes(istate['stack'])) + ctx.setConcreteMemoryAreaValue(HEAP, bytes(istate['heap'])) + ctx.setConcreteRegisterValue(ctx.registers.x0, 0) + ctx.setConcreteRegisterValue(ctx.registers.x1, istate['x1']) + ctx.setConcreteRegisterValue(ctx.registers.x2, istate['x2']) + ctx.setConcreteRegisterValue(ctx.registers.x3, istate['x3']) + ctx.setConcreteRegisterValue(ctx.registers.x4, istate['x4']) + ctx.setConcreteRegisterValue(ctx.registers.x5, istate['x5']) + ctx.setConcreteRegisterValue(ctx.registers.x6, istate['x6']) + ctx.setConcreteRegisterValue(ctx.registers.x7, istate['x7']) + ctx.setConcreteRegisterValue(ctx.registers.x8, istate['x8']) + ctx.setConcreteRegisterValue(ctx.registers.x9, istate['x9']) + ctx.setConcreteRegisterValue(ctx.registers.x10, istate['x10']) + ctx.setConcreteRegisterValue(ctx.registers.x11, istate['x11']) + ctx.setConcreteRegisterValue(ctx.registers.x12, istate['x12']) + ctx.setConcreteRegisterValue(ctx.registers.x13, istate['x13']) + ctx.setConcreteRegisterValue(ctx.registers.x14, istate['x14']) + ctx.setConcreteRegisterValue(ctx.registers.x15, istate['x15']) + ctx.setConcreteRegisterValue(ctx.registers.x16, istate['x16']) + ctx.setConcreteRegisterValue(ctx.registers.x17, istate['x17']) + ctx.setConcreteRegisterValue(ctx.registers.x18, istate['x18']) + ctx.setConcreteRegisterValue(ctx.registers.x19, istate['x19']) + ctx.setConcreteRegisterValue(ctx.registers.x20, istate['x20']) + ctx.setConcreteRegisterValue(ctx.registers.x21, istate['x21']) + ctx.setConcreteRegisterValue(ctx.registers.x22, istate['x22']) + ctx.setConcreteRegisterValue(ctx.registers.x23, istate['x23']) + ctx.setConcreteRegisterValue(ctx.registers.x24, istate['x24']) + ctx.setConcreteRegisterValue(ctx.registers.x25, istate['x25']) + ctx.setConcreteRegisterValue(ctx.registers.x26, istate['x26']) + ctx.setConcreteRegisterValue(ctx.registers.x27, istate['x27']) + ctx.setConcreteRegisterValue(ctx.registers.x28, istate['x28']) + ctx.setConcreteRegisterValue(ctx.registers.x29, istate['x29']) + ctx.setConcreteRegisterValue(ctx.registers.x30, istate['x30']) + ctx.setConcreteRegisterValue(ctx.registers.x31, istate['x31']) + ctx.setConcreteRegisterValue(ctx.registers.f0, istate['f0']) + ctx.setConcreteRegisterValue(ctx.registers.f1, istate['f1']) + ctx.setConcreteRegisterValue(ctx.registers.f2, istate['f2']) + ctx.setConcreteRegisterValue(ctx.registers.f3, istate['f3']) + ctx.setConcreteRegisterValue(ctx.registers.f4, istate['f4']) + ctx.setConcreteRegisterValue(ctx.registers.f5, istate['f5']) + ctx.setConcreteRegisterValue(ctx.registers.f6, istate['f6']) + ctx.setConcreteRegisterValue(ctx.registers.f7, istate['f7']) + ctx.setConcreteRegisterValue(ctx.registers.f8, istate['f8']) + ctx.setConcreteRegisterValue(ctx.registers.f9, istate['f9']) + ctx.setConcreteRegisterValue(ctx.registers.f10, istate['f10']) + ctx.setConcreteRegisterValue(ctx.registers.f11, istate['f11']) + ctx.setConcreteRegisterValue(ctx.registers.f12, istate['f12']) + ctx.setConcreteRegisterValue(ctx.registers.f13, istate['f13']) + ctx.setConcreteRegisterValue(ctx.registers.f14, istate['f14']) + ctx.setConcreteRegisterValue(ctx.registers.f15, istate['f15']) + ctx.setConcreteRegisterValue(ctx.registers.f16, istate['f16']) + ctx.setConcreteRegisterValue(ctx.registers.f17, istate['f17']) + ctx.setConcreteRegisterValue(ctx.registers.f18, istate['f18']) + ctx.setConcreteRegisterValue(ctx.registers.f19, istate['f19']) + ctx.setConcreteRegisterValue(ctx.registers.f20, istate['f20']) + ctx.setConcreteRegisterValue(ctx.registers.f21, istate['f21']) + ctx.setConcreteRegisterValue(ctx.registers.f22, istate['f22']) + ctx.setConcreteRegisterValue(ctx.registers.f23, istate['f23']) + ctx.setConcreteRegisterValue(ctx.registers.f24, istate['f24']) + ctx.setConcreteRegisterValue(ctx.registers.f25, istate['f25']) + ctx.setConcreteRegisterValue(ctx.registers.f26, istate['f26']) + ctx.setConcreteRegisterValue(ctx.registers.f27, istate['f27']) + ctx.setConcreteRegisterValue(ctx.registers.f28, istate['f28']) + ctx.setConcreteRegisterValue(ctx.registers.f29, istate['f29']) + ctx.setConcreteRegisterValue(ctx.registers.f30, istate['f30']) + ctx.setConcreteRegisterValue(ctx.registers.f31, istate['f31']) + ctx.setConcreteRegisterValue(ctx.registers.pc, istate['pc']) + + ctx.processing(inst) + + #print + #print(inst) + #for x in inst.getSymbolicExpressions(): + # print(x) + #print + + ostate = { + "stack": ctx.getConcreteMemoryAreaValue(STACK, 0x100), + "heap": ctx.getConcreteMemoryAreaValue(HEAP, 0x100), + + "x0": 0, + "x1": ctx.getSymbolicRegisterValue(ctx.registers.x1), + "x2": ctx.getSymbolicRegisterValue(ctx.registers.x2), + "x3": ctx.getSymbolicRegisterValue(ctx.registers.x3), + "x4": ctx.getSymbolicRegisterValue(ctx.registers.x4), + "x5": ctx.getSymbolicRegisterValue(ctx.registers.x5), + "x6": ctx.getSymbolicRegisterValue(ctx.registers.x6), + "x7": ctx.getSymbolicRegisterValue(ctx.registers.x7), + "x8": ctx.getSymbolicRegisterValue(ctx.registers.x8), + "x9": ctx.getSymbolicRegisterValue(ctx.registers.x9), + "x10": ctx.getSymbolicRegisterValue(ctx.registers.x10), + "x11": ctx.getSymbolicRegisterValue(ctx.registers.x11), + "x12": ctx.getSymbolicRegisterValue(ctx.registers.x12), + "x13": ctx.getSymbolicRegisterValue(ctx.registers.x13), + "x14": ctx.getSymbolicRegisterValue(ctx.registers.x14), + "x15": ctx.getSymbolicRegisterValue(ctx.registers.x15), + "x16": ctx.getSymbolicRegisterValue(ctx.registers.x16), + "x17": ctx.getSymbolicRegisterValue(ctx.registers.x17), + "x18": ctx.getSymbolicRegisterValue(ctx.registers.x18), + "x19": ctx.getSymbolicRegisterValue(ctx.registers.x19), + "x20": ctx.getSymbolicRegisterValue(ctx.registers.x20), + "x21": ctx.getSymbolicRegisterValue(ctx.registers.x21), + "x22": ctx.getSymbolicRegisterValue(ctx.registers.x22), + "x23": ctx.getSymbolicRegisterValue(ctx.registers.x23), + "x24": ctx.getSymbolicRegisterValue(ctx.registers.x24), + "x25": ctx.getSymbolicRegisterValue(ctx.registers.x25), + "x26": ctx.getSymbolicRegisterValue(ctx.registers.x26), + "x27": ctx.getSymbolicRegisterValue(ctx.registers.x27), + "x28": ctx.getSymbolicRegisterValue(ctx.registers.x28), + "x29": ctx.getSymbolicRegisterValue(ctx.registers.x29), + "x30": ctx.getSymbolicRegisterValue(ctx.registers.x30), + "x31": ctx.getSymbolicRegisterValue(ctx.registers.x31), + "f0": ctx.getSymbolicRegisterValue(ctx.registers.f0), + "f1": ctx.getSymbolicRegisterValue(ctx.registers.f1), + "f2": ctx.getSymbolicRegisterValue(ctx.registers.f2), + "f3": ctx.getSymbolicRegisterValue(ctx.registers.f3), + "f4": ctx.getSymbolicRegisterValue(ctx.registers.f4), + "f5": ctx.getSymbolicRegisterValue(ctx.registers.f5), + "f6": ctx.getSymbolicRegisterValue(ctx.registers.f6), + "f7": ctx.getSymbolicRegisterValue(ctx.registers.f7), + "f8": ctx.getSymbolicRegisterValue(ctx.registers.f8), + "f9": ctx.getSymbolicRegisterValue(ctx.registers.f9), + "f10": ctx.getSymbolicRegisterValue(ctx.registers.f10), + "f11": ctx.getSymbolicRegisterValue(ctx.registers.f11), + "f12": ctx.getSymbolicRegisterValue(ctx.registers.f12), + "f13": ctx.getSymbolicRegisterValue(ctx.registers.f13), + "f14": ctx.getSymbolicRegisterValue(ctx.registers.f14), + "f15": ctx.getSymbolicRegisterValue(ctx.registers.f15), + "f16": ctx.getSymbolicRegisterValue(ctx.registers.f16), + "f17": ctx.getSymbolicRegisterValue(ctx.registers.f17), + "f18": ctx.getSymbolicRegisterValue(ctx.registers.f18), + "f19": ctx.getSymbolicRegisterValue(ctx.registers.f19), + "f20": ctx.getSymbolicRegisterValue(ctx.registers.f20), + "f21": ctx.getSymbolicRegisterValue(ctx.registers.f21), + "f22": ctx.getSymbolicRegisterValue(ctx.registers.f22), + "f23": ctx.getSymbolicRegisterValue(ctx.registers.f23), + "f24": ctx.getSymbolicRegisterValue(ctx.registers.f24), + "f25": ctx.getSymbolicRegisterValue(ctx.registers.f25), + "f26": ctx.getSymbolicRegisterValue(ctx.registers.f26), + "f27": ctx.getSymbolicRegisterValue(ctx.registers.f27), + "f28": ctx.getSymbolicRegisterValue(ctx.registers.f28), + "f29": ctx.getSymbolicRegisterValue(ctx.registers.f29), + "f30": ctx.getSymbolicRegisterValue(ctx.registers.f30), + "f31": ctx.getSymbolicRegisterValue(ctx.registers.f31), + "pc": ctx.getSymbolicRegisterValue(ctx.registers.pc), + } + return ostate + + +def diff_state(state1, state2): + for k, v in list(state1.items()): + if (k == 'heap' or k == 'stack') and v != state2[k]: + print('\t%s: (UC) != (TT)' %(k)) + elif not (k == 'heap' or k == 'stack') and v != state2[k]: + print('\t%s: %#x (UC) != %#x (TT)' %(k, v, state2[k])) + return + + +if __name__ == '__main__': + # initial state + state = { + "stack": bytearray(b"".join([pack('B', 255 - i) for i in range(256)])), + "heap": bytearray(b"".join([pack('B', i) for i in range(256)])), + "x0": 0x0, + "x1": 0x0, + "x2": STACK, + "x3": 0x0, + "x4": 0x0, + "x5": 0x0, + "x6": 0x0, + "x7": 0x0, + "x8": 0x0, + "x9": 0x0, + "x10": 0x0, + "x11": 0x0, + "x12": 0x0, + "x13": 0x0, + "x14": 0x0, + "x15": 0x0, + "x16": 0x0, + "x17": 0x0, + "x18": 0x0, + "x19": 0x0, + "x20": 0x0, + "x21": 0x0, + "x22": 0x0, + "x23": 0x0, + "x24": 0x0, + "x25": 0x0, + "x26": 0x0, + "x27": 0x0, + "x28": 0x0, + "x29": 0x0, + "x30": 0x0, + "x31": 0x2107ff, + "f0": 0x0123456789abcdef, + "f1": 0xfedcba9876543210, + "f2": 0xfefedcdc56567878, + "f3": 0x123456789098cd01, + "f4": 0x0, + "f5": 0x0, + "f6": 0x0, + "f7": 0x0, + "f8": 0x0, + "f9": 0x0, + "f10": 0x0, + "f11": 0x0, + "f12": 0x0, + "f13": 0x0, + "f14": 0x0, + "f15": 0x0, + "f16": 0x0, + "f17": 0x0, + "f18": 0x0, + "f19": 0x0, + "f20": 0x0, + "f21": 0x0, + "f22": 0x0, + "f23": 0x0, + "f24": 0x0, + "f25": 0x0, + "f26": 0x0, + "f27": 0x0, + "f28": 0x0, + "f29": 0x0, + "f30": 0x0, + "f31": 0x0, + "pc": ADDR, + } + + for opcode, disassembly in CODE: + try: + uc_state = emu_with_unicorn(opcode, state) + tt_state = emu_with_triton(opcode, state) + except Exception as e: + print('[KO] %s' %(disassembly)) + print('\t%s' %(e)) + sys.exit(-1) + + if uc_state != tt_state: + print('[KO] %s' %(disassembly)) + diff_state(uc_state, tt_state) + sys.exit(-1) + + print('[OK] %s' %(disassembly)) + state = tt_state + + sys.exit(0) diff --git a/src/testers/riscv/unicorn_test_riscv64.py b/src/testers/riscv/unicorn_test_riscv64.py new file mode 100644 index 000000000..24a764873 --- /dev/null +++ b/src/testers/riscv/unicorn_test_riscv64.py @@ -0,0 +1,718 @@ +#!/usr/bin/env python3 +## -*- coding: utf-8 -*- + +from __future__ import print_function + +from triton import * +from unicorn import * +from unicorn.riscv_const import * +from struct import pack + +import sys +import pprint + +ADDR = 0x100000 +STACK = 0x200000 +HEAP = 0x300000 +SIZE = 5 * 1024 * 1024 + +CODE = [ + # ADDI + (b"\x93\x05\x16\x00", "addi x11, x12, #1"), + (b"\x13\x00\xe0\x00", "addi x0, x0, #0xe"), + (b"\x13\x05\x00\x00", "addi x10, x0, #0"), + (b"\x13\x00\x00\x00", "addi x0, x0, #0"), # nop + (b"\x13\x00\x00\x00", "addi x0, x0, #0"), # nop + (b"\x13\x00\x00\x00", "addi x0, x0, #0"), # nop + (b"\x93\x05\x16\x00", "addi x11, x12, #1"), + (b"\x93\x05\x06\x00", "addi x11, x12, #0"), + (b"\x13\x05\xe0\x00", "addi x10, x0, #0xe"), + (b"\x13\x03\x43\x00", "addi x6, x6, #4"), + (b"\x49\x13", "c.addi x1, x1, #1"), + (b"\x49\x13", "c.addi x6, x6, #-0xe"), + (b"\x09\x16", "c.addi x12, x12, #-30"), + (b"\x11\x01", "c.addi x2, x2, #4"), + (b"\x75\x61", "c.addi16sp x2, x2, #368"), + (b"\x40\x00", "c.addi4spn x8, x2, #4"), + (b"\x8c\x02", "c.addi4spn x10, x2, #320"), + (b"\x85\x47", "c.li x15, #1"), + (b"\x49\x4c", "c.li x24, #18"), + (b"\x09\x54", "c.li x8, #-30"), + (b"\x01\x00", "c.nop"), + (b"\x5d\x00", "c.nop 23"), + (b"\x65\x00", "c.nop 25"), + + # ADD + (b"\x33\x05\x00\x00", "add x10, x0, x0"), + (b"\x33\x86\xb0\x00", "add x12, x1, x11"), + (b"\xb3\x05\x06\x00", "add x11, x12, x0"), + (b"\xb3\x05\xc0\x00", "add x11, x0, x12"), + (b"\xbe\x95", "c.add x11, x11, x15"), + (b"\x0a\x9a", "c.add x20, x20, x2"), + (b"\x0a\x88", "c.mv x16, x2"), + (b"\xb2\x8a", "c.mv x21, x12"), + + # ADDIW + (b"\x1b\x87\xb7\x0a", "addiw x14, x15, #0xab"), + (b"\x9b\x07\x07\x00", "addiw x15, x14, #0"), # sext.w + (b"\x85\x27", "c.addiw x15, x15, #1"), + (b"\x81\x37", "c.addiw x15, x15, #-0z20"), + + # ADDW + (b"\x3b\x87\x07\x01", "addw x14, x15, x16"), + (b"\x3b\x08\x00\x01", "addw x16, x0, x16"), + (b"\xbb\x08\x05\x00", "addw x17, x10, x0"), + (b"\xb9\x9f", "c.addw x15, x15, x14"), + + # AND/I + (b"\x13\xf0\xf0\x0f", "andi x0, x1, #0xff"), + (b"\x13\x75\xf0\x0f", "andi x10, x0, #0xff"), + (b"\x93\x76\x17\x00", "andi x13, x14, #0x01"), + (b"\x93\x76\x07\x01", "andi x13, x14, #0x10"), + (b"\x49\x13", "c.andi x14, x14, #2"), + (b"\x19\x98", "c.andi x8, x8, #-26"), + (b"\xb3\x71\x52\x00", "and x3, x4, x5"), + (b"\xb3\x75\xc5\x00", "and x11, x10, x12"), + (b"\x71\x8f", "c.and x14, x14, x12"), + + # AUIPC + (b"\x17\xe5\xcd\xab", "auipc x10, #0xabcde"), + (b"\x17\x15\x00\x00", "auipc x10, #0x1"), + (b"\x17\xd9\xf1\xe2", "auipc x18, #0xf1e2d"), + (b"\x17\x10\x00\x00", "auipc x0, #0x1"), + + # SB / SH / SW / SD + (b"\x23\x0c\xa1\x00", "sb x10, 0x18(sp)"), + (b"\xa3\x0c\xa1\x00", "sb x10, 0x19(sp)"), + (b"\x23\x00\xc1\x02", "sb x12, 0x20(sp)"), + (b"\x23\x2a\xe1\x00", "sw x14, 0x14(sp)"), + (b"\x23\x20\xa1\x02", "sw x10, 0x20(sp)"), + (b"\x23\x11\xe1\x02", "sh x14, 0x22(sp)"), + (b"\x23\x10\x01\x00", "sh x0, 0(sp)"), + (b"\x23\x3c\xb1\x00", "sd x11, 0x18(sp)"), + (b"\x23\x30\xa1\x00", "sd x10, 0(sp)"), + (b"\x23\x30\xe1\x02", "sd x14, 0x20(sp)"), + (b"\x23\x12\xa1\x02", "sh x10, 0x24(sp)"), + (b"\x23\x20\xe1\x00", "sw x14, 0(sp)"), + + # LB / LH / LW / LD + (b"\x03\x35\x01\x02", "ld x10, 0x20(sp)"), + (b"\x03\x25\x01\x00", "lw x10, 0(sp)"), + (b"\x03\x07\x01\x00", "lb x14, 0(sp)"), + (b"\x03\x07\x01\x02", "lb x14, 0x20(sp)"), + (b"\x83\x15\x81\x01", "lh x11, 0x18(sp)"), + + # LBU / LHU / LWU + (b"\x03\x4a\x91\x01", "lbu x20, 0x19(sp)"), + (b"\x83\x55\x41\x02", "lhu x11, 0x24(sp)"), + (b"\x03\x66\x01\x02", "lwu x12, 0x20(sp)"), + + # Compressed load/store + (b"\x0a\x85", "c.mv x10, x2"), + (b"\x4c\x49", "c.lw x11, 0x14(x10)"), + (b"\x42\x43", "c.lwsp x6, 0x10(sp)"), + (b"\x00\x61", "c.ld x8, 0x0(x10)"), + (b"\x42\x6a", "c.ldsp x20, 0x10(sp)"), + (b"\x08\xe9", "c.sd x10, 0x10(x10)"), + (b"\x10\xf5", "c.sd x12, 0x28(x10)"), + (b"\x22\xe0", "c.sdsp x8, 0x0(sp)"), + (b"\x10\xcd", "c.sw x12, 0x18(x10)"), + (b"\x42\xc8", "c.swsp x16, 0x10(sp)"), + + #(b"\x7d\xd4", "c.beqz x8, -0x12"), + #(b"\x7d\xd5", "c.beqz x10, -0x12"), + #(b"\x7d\xf4", "c.bnez x8, -0x12"), + #(b"\x7d\xf5", "c.bnez x10, -0x12"), + + #(b"\x69\xbf", "c.j x10, 0x6ac"), + #(b"\x02\x81", "c.jr x2"), + #(b"\x02\x91", "c.jalr x2"), + + # LUI + (b"\x37\xfa\xff\xff", "lui x20, #0xfffff"), + (b"\xb7\x0a\x01\x01", "lui x21, #0x1010"), + (b"\x37\x5b\x34\x12", "lui x22, #0x12345"), + (b"\x37\x00\x00\x00", "lui x0, #0"), + (b"\x65\x67", "c.lui x14, #0x19"), + (b"\x75\x74", "c.lui x8, #0xffffd"), + + # OR/I + (b"\x93\x65\x05\x0f", "ori x11, x10, #0xf0"), + (b"\x93\x65\x76\x00", "ori x11, x12, #0x7"), + (b"\x33\x66\xb5\x00", "or x12, x10, x11"), + (b"\x51\x8f", "c.or x14, x14, x12"), + + # MUL + (b"\x33\x85\xb5\x02", "mul x10, x11, x11"), + (b"\x33\x86\xc5\x02", "mul x12, x11, x12"), + (b"\x33\x86\xc5\x02", "mul x12, x11, x12"), + (b"\x33\x86\xc5\x02", "mul x12, x11, x12"), + (b"\x33\x86\xc5\x02", "mul x12, x11, x12"), + (b"\x33\x86\xc5\x02", "mul x12, x11, x12"), + (b"\x33\x86\xc5\x02", "mul x12, x11, x12"), + (b"\x33\x86\xc5\x02", "mul x12, x11, x12"), + (b"\x33\x86\xc5\x02", "mul x12, x11, x12"), + (b"\x33\x86\xc5\x02", "mul x12, x11, x12"), + (b"\x33\x86\xc5\x02", "mul x12, x11, x12"), + (b"\x33\x86\xc5\x02", "mul x12, x11, x12"), + (b"\x33\x86\xc5\x02", "mul x12, x11, x12"), + (b"\x33\x86\xc5\x02", "mul x12, x11, x12"), + (b"\x33\x86\xc5\x02", "mul x12, x11, x12"), + (b"\x33\x86\xc5\x02", "mul x12, x11, x12"), + (b"\x33\x07\xa0\x02", "mul x14, x0, x10"), + (b"\x33\x17\xc6\x02", "mulh x14, x12, x12"), + (b"\xbb\x06\xb5\x02", "mulw x13, x10, x11"), + (b"\x33\x27\xc6\x02", "mulhsu x14, x12, x12"), + (b"\x33\x27\xe6\x02", "mulhsu x14, x12, x14"), + (b"\x33\x27\xe6\x02", "mulhsu x14, x12, x14"), + (b"\x33\x27\xe6\x02", "mulhsu x14, x12, x14"), + (b"\xb3\x26\xb5\x02", "mulhsu x13, x10, x11"), + (b"\x33\x37\xe6\x02", "mulhu x14, x12, x14"), + (b"\xb3\x36\xe5\x02", "mulhu x13, x10, x14"), + + # DIV/U/W + (b"\x33\x46\xa6\x02", "div x12, x12, x10"), + (b"\x33\x56\xa6\x02", "divu x12, x12, x10"), + (b"\xbb\x56\xa6\x02", "divuw x13, x12, x10"), + (b"\x3b\x47\xb6\x02", "divw x14, x12, x11"), + (b"\x3b\x40\xa6\x02", "divw x0, x12, x10"), + # div-by-zero corner case + (b"\xb7\x08\x00\x00", "lui x17, #0"), + (b"\xb3\x45\x16\x03", "div x11, x12, x17"), + (b"\xb3\x55\x16\x03", "divu x11, x12, x17"), + (b"\xbb\x55\x16\x03", "divuw x11, x12, x17"), + (b"\xbb\x40\x16\x03", "divw x11, x12, x17"), + + # REM/U/W + (b"\xb3\x65\xa6\x02", "rem x11, x12, x10"), + (b"\xb3\x75\xa6\x02", "remu x11, x12, x10"), + (b"\xbb\x75\xa7\x02", "remuw x11, x14, x10"), + (b"\xbb\x65\xa7\x02", "remw x11, x14, x10"), + # div-by-zero corner case + (b"\xb7\x08\x00\x00", "lui x17, #0"), + (b"\xb3\x65\x16\x03", "rem x11, x12, x17"), + (b"\xbb\x75\x17\x03", "remuw x11, x14, x17"), + (b"\xb3\x75\x16\x03", "remu x11, x12, x17"), + (b"\xbb\x65\x17\x03", "remw x11, x14, x17"), + # signed overflow + (b"\xb7\xf8\xff\xff", "lui x17, #0xfffff"), + (b"\x93\x98\x38\x01", "slli x17, x17, #19"), + (b"\x13\x05\xf0\xff", "addi x10, x0, #-1"), + (b"\xbb\xe5\xa8\x02", "remw x11, x17, x10"), + (b"\x93\x05\x16\x00", "addi x11, x12, #1"), + (b"\x93\x98\x08\x02", "slli x17, x17, #32"), + (b"\xb3\xe5\xa8\x02", "rem x11, x17, x10"), + + # SUB/W + (b"\xb3\x05\xa0\x40", "sub x11, x0, x10"), + (b"\xb3\x05\xb0\x40", "sub x11, x0, x11"), # neg + (b"\xb3\x05\xa7\x40", "sub x11, x14, x10"), + (b"\x33\x00\xe7\x40", "sub x0, x14, x14"), + (b"\x89\x8d", "c.sub x11, x11, x10"), + (b"\xbb\x85\xa5\x40", "subw x11, x11, x10"), + (b"\x3b\x05\xb0\x40", "subw x10, x0, x11"), # negw + (b"\x3b\x02\x00\x40", "subw x4, x0, x0"), # negw + (b"\x01\x9c", "c.subw x8, x8, x8"), + + # XOR/I + (b"\xb3\x45\xb5\x00", "xor x11, x10, x11"), + (b"\x33\x45\xa5\x00", "xor x10, x10, x10"), + (b"\x33\x45\x00\x00", "xor x10, x0, x0"), + (b"\xb9\x8f", "c.xor x15, x15, x14"), + (b"\x93\x47\x36\x0f", "xori x15, x12, #0xf3"), + (b"\x93\x47\xe6\xff", "xori x15, x12, #-2"), + (b"\x93\x47\xf6\xff", "xori x15, x12, #-1"), # not + + # SLT + (b"\x33\x28\xb5\x00", "slt x16, x10, x11"), + (b"\x33\x28\x84\x00", "slt x16, x8, x8"), + (b"\xb3\xa0\x05\x00", "slt x1, x11, x0"), # sltz + (b"\xb3\x20\xb0\x00", "slt x1, x0, x11"), # sgtz + (b"\xb3\x20\x00\x00", "slt x1, x0, x0"), # sltz + (b"\xb3\xa0\xa0\x00", "slt x1, x1, x10"), + # SLTI + (b"\x13\xa8\x15\x00", "slti x16, x11, #1"), + (b"\x13\x28\x87\xff", "slti x16, x14, #-8"), + (b"\x13\x28\xd7\x01", "slti x16, x14, #29"), + # SLT(I)U + (b"\x93\x30\x15\x00", "sltiu x1, x10, #1"), # seqz + (b"\x13\xb8\x05\x01", "sltiu x16, x11, #0x10"), + (b"\x13\xb8\xb5\xff", "sltiu x16, x11, #-5"), + (b"\x33\xb8\xb5\x00", "sltu x16, x11, x11"), + (b"\x33\x38\xb5\x00", "sltu x16, x10, x11"), + (b"\xb3\x30\xa0\x00", "sltu x1, x0, x10"), # snez + (b"\xb3\x30\xb0\x00", "sltu x1, x0, x11"), # snez + + # SLL + (b"\x13\xe5\xf5\x0f", "ori x10, x11, #0xff"), + (b"\x93\x65\xe6\x0f", "ori x11, x12, #0xfe"), + (b"\x33\x15\xb5\x00", "sll x10, x10, x11"), + (b"\xb3\x15\xb5\x00", "sll x11, x10, x11"), + (b"\xb3\x15\xb5\x00", "sll x12, x13, x12"), + (b"\x33\x16\xf8\x00", "sll x12, x16, x15"), + (b"\x93\x10\x85\x00", "slli x1, x10, #8"), + (b"\x93\x15\xf5\x00", "slli x11, x10, #0xf"), + (b"\x12\x06", "c.slli x12, x12, #0x4"), + (b"\xf2\x1f", "c.slli x31, x31, #0x3c"), + (b"\xbb\x15\xa5\x00", "sllw x11, x10, x10"), + (b"\xbb\x15\x05\x00", "sllw x11, x10, x0"), + (b"\x9b\x15\xb5\x00", "slliw x11, x10, #0xb"), + (b"\x1b\x15\x15\x00", "slliw x10, x10, #0x1"), + (b"\xb7\xe8\xcd\xab", "lui x17, #0xabcde"), + (b"\x93\x88\x78\x45", "addi x17, x17, #0x457"), + (b"\x1b\x95\xc8\x00", "slliw x10, x17, #0xc"), + (b"\x1b\x95\xf8\x01", "slliw x10, x17, #0x1f"), + (b"\x3b\x95\x18\x01", "sllw x10, x17, x17"), + (b"\x3b\x95\x28\x01", "sllw x10, x17, x18"), + # SRA + (b"\x13\xe5\xf5\x0f", "ori x10, x11, #0xff"), + (b"\x93\x65\xe6\x0f", "ori x11, x12, #0xfe"), + (b"\x33\x55\xb5\x40", "sra x10, x10, x11"), + (b"\xb3\x55\xb5\x40", "sra x11, x10, x11"), + (b"\x33\xd6\xe7\x40", "sra x12, x15, x14"), + (b"\x93\x55\x85\x40", "srai x11, x10, #8"), + (b"\x93\x55\xf5\x40", "srai x11, x10, #0xf"), + (b"\x85\x85", "c.srai x11, x11, #0x1"), + (b"\xb7\x05\x00\x88", "lui x11, #0x88000"), + (b"\xfd\x95", "c.srai x11, x11, #0x3f"), + (b"\xbb\x55\xa5\x40", "sraw x11, x10, x10"), + (b"\xbb\x55\x05\x40", "sraw x11, x10, x0"), + (b"\x9b\x55\xb5\x40", "sraiw x11, x10, #0xb"), + (b"\x1b\x55\x15\x40", "sraiw x10, x10, #0x1"), + (b"\x1b\xd5\xc8\x40", "sraiw x10, x17, #0xc"), + (b"\x1b\xd5\xf8\x41", "sraiw x10, x17, #0x1f"), + (b"\x3b\xd5\x18\x41", "sraw x10, x17, x17"), + (b"\x3b\xd5\x28\x41", "sraw x10, x17, x18"), + # SRL + (b"\x13\xe5\xf5\x0f", "ori x10, x11, #0xff"), + (b"\x93\x65\xe6\x0f", "ori x11, x12, #0xfe"), + (b"\x33\x55\xb5\x00", "srl x10, x10, x11"), + (b"\xb3\x55\xb5\x00", "srl x11, x10, x11"), + (b"\x33\xd6\xe7\x00", "srl x12, x15, x14"), + (b"\x93\x55\x85\x00", "srli x11, x10, #8"), + (b"\x93\x55\xf5\x00", "srli x11, x10, #0xf"), + (b"\x85\x81", "c.srli x11, x11, #0x1"), + (b"\xb7\x05\x00\x80", "lui x11, #0x80000"), + (b"\xfd\x91", "c.srli x11, x11, #0x3f"), + (b"\xbb\x55\xa5\x00", "srlw x11, x10, x10"), + (b"\xbb\x55\x05\x00", "srlw x11, x10, x0"), + (b"\x9b\x55\xb5\x00", "srliw x11, x10, #0xb"), + (b"\x1b\x55\x15\x00", "srliw x10, x10, #0x1"), + (b"\x1b\xd5\xc8\x00", "srliw x10, x17, #0xc"), + (b"\x1b\xd5\xf8\x01", "srliw x10, x17, #0x1f"), + (b"\x3b\xd5\x18\x01", "srlw x10, x17, x17"), + (b"\x3b\xd5\x28\x01", "srlw x10, x17, x18"), + +] + +def emu_with_unicorn(opcode, istate): + # Initialize emulator in RV64 mode + mu = Uc(UC_ARCH_RISCV, UC_MODE_RISCV64) + + # map memory for this emulation + mu.mem_map(ADDR, SIZE) + + # write machine code to be emulated to memory + index = 0 + for op, _ in CODE: + mu.mem_write(ADDR+index, op) + index += len(op) + + mu.mem_write(STACK, bytes(istate['stack'])) + mu.mem_write(HEAP, bytes(istate['heap'])) + mu.reg_write(UC_RISCV_REG_X0, istate['x0']) + mu.reg_write(UC_RISCV_REG_X1, istate['x1']) + mu.reg_write(UC_RISCV_REG_X2, istate['x2']) + mu.reg_write(UC_RISCV_REG_X3, istate['x3']) + mu.reg_write(UC_RISCV_REG_X4, istate['x4']) + mu.reg_write(UC_RISCV_REG_X5, istate['x5']) + mu.reg_write(UC_RISCV_REG_X6, istate['x6']) + mu.reg_write(UC_RISCV_REG_X7, istate['x7']) + mu.reg_write(UC_RISCV_REG_X8, istate['x8']) + mu.reg_write(UC_RISCV_REG_X9, istate['x9']) + mu.reg_write(UC_RISCV_REG_X10, istate['x10']) + mu.reg_write(UC_RISCV_REG_X11, istate['x11']) + mu.reg_write(UC_RISCV_REG_X12, istate['x12']) + mu.reg_write(UC_RISCV_REG_X13, istate['x13']) + mu.reg_write(UC_RISCV_REG_X14, istate['x14']) + mu.reg_write(UC_RISCV_REG_X15, istate['x15']) + mu.reg_write(UC_RISCV_REG_X16, istate['x16']) + mu.reg_write(UC_RISCV_REG_X17, istate['x17']) + mu.reg_write(UC_RISCV_REG_X18, istate['x18']) + mu.reg_write(UC_RISCV_REG_X19, istate['x19']) + mu.reg_write(UC_RISCV_REG_X20, istate['x20']) + mu.reg_write(UC_RISCV_REG_X21, istate['x21']) + mu.reg_write(UC_RISCV_REG_X22, istate['x22']) + mu.reg_write(UC_RISCV_REG_X23, istate['x23']) + mu.reg_write(UC_RISCV_REG_X24, istate['x24']) + mu.reg_write(UC_RISCV_REG_X25, istate['x25']) + mu.reg_write(UC_RISCV_REG_X26, istate['x26']) + mu.reg_write(UC_RISCV_REG_X27, istate['x27']) + mu.reg_write(UC_RISCV_REG_X28, istate['x28']) + mu.reg_write(UC_RISCV_REG_X29, istate['x29']) + mu.reg_write(UC_RISCV_REG_X30, istate['x30']) + mu.reg_write(UC_RISCV_REG_X31, istate['x31']) + mu.reg_write(UC_RISCV_REG_F0, istate['f0']) + mu.reg_write(UC_RISCV_REG_F1, istate['f1']) + mu.reg_write(UC_RISCV_REG_F2, istate['f2']) + mu.reg_write(UC_RISCV_REG_F3, istate['f3']) + mu.reg_write(UC_RISCV_REG_F4, istate['f4']) + mu.reg_write(UC_RISCV_REG_F5, istate['f5']) + mu.reg_write(UC_RISCV_REG_F6, istate['f6']) + mu.reg_write(UC_RISCV_REG_F7, istate['f7']) + mu.reg_write(UC_RISCV_REG_F8, istate['f8']) + mu.reg_write(UC_RISCV_REG_F9, istate['f9']) + mu.reg_write(UC_RISCV_REG_F10, istate['f10']) + mu.reg_write(UC_RISCV_REG_F11, istate['f11']) + mu.reg_write(UC_RISCV_REG_F12, istate['f12']) + mu.reg_write(UC_RISCV_REG_F13, istate['f13']) + mu.reg_write(UC_RISCV_REG_F14, istate['f14']) + mu.reg_write(UC_RISCV_REG_F15, istate['f15']) + mu.reg_write(UC_RISCV_REG_F16, istate['f16']) + mu.reg_write(UC_RISCV_REG_F17, istate['f17']) + mu.reg_write(UC_RISCV_REG_F18, istate['f18']) + mu.reg_write(UC_RISCV_REG_F19, istate['f19']) + mu.reg_write(UC_RISCV_REG_F20, istate['f20']) + mu.reg_write(UC_RISCV_REG_F21, istate['f21']) + mu.reg_write(UC_RISCV_REG_F22, istate['f22']) + mu.reg_write(UC_RISCV_REG_F23, istate['f23']) + mu.reg_write(UC_RISCV_REG_F24, istate['f24']) + mu.reg_write(UC_RISCV_REG_F25, istate['f25']) + mu.reg_write(UC_RISCV_REG_F26, istate['f26']) + mu.reg_write(UC_RISCV_REG_F27, istate['f27']) + mu.reg_write(UC_RISCV_REG_F28, istate['f28']) + mu.reg_write(UC_RISCV_REG_F29, istate['f29']) + mu.reg_write(UC_RISCV_REG_F30, istate['f30']) + mu.reg_write(UC_RISCV_REG_F31, istate['f31']) + mu.reg_write(UC_RISCV_REG_PC, istate['pc']) + + # emulate code in infinite time & unlimited instructions + mu.emu_start(istate['pc'], istate['pc'] + len(opcode), 0, 1) + + ostate = { + "stack": mu.mem_read(STACK, 0x100), + "heap": mu.mem_read(HEAP, 0x100), + "x0": mu.reg_read(UC_RISCV_REG_X0), + "x1": mu.reg_read(UC_RISCV_REG_X1), + "x2": mu.reg_read(UC_RISCV_REG_X2), + "x3": mu.reg_read(UC_RISCV_REG_X3), + "x4": mu.reg_read(UC_RISCV_REG_X4), + "x5": mu.reg_read(UC_RISCV_REG_X5), + "x6": mu.reg_read(UC_RISCV_REG_X6), + "x7": mu.reg_read(UC_RISCV_REG_X7), + "x8": mu.reg_read(UC_RISCV_REG_X8), + "x9": mu.reg_read(UC_RISCV_REG_X9), + "x10": mu.reg_read(UC_RISCV_REG_X10), + "x11": mu.reg_read(UC_RISCV_REG_X11), + "x12": mu.reg_read(UC_RISCV_REG_X12), + "x13": mu.reg_read(UC_RISCV_REG_X13), + "x14": mu.reg_read(UC_RISCV_REG_X14), + "x15": mu.reg_read(UC_RISCV_REG_X15), + "x16": mu.reg_read(UC_RISCV_REG_X16), + "x17": mu.reg_read(UC_RISCV_REG_X17), + "x18": mu.reg_read(UC_RISCV_REG_X18), + "x19": mu.reg_read(UC_RISCV_REG_X19), + "x20": mu.reg_read(UC_RISCV_REG_X20), + "x21": mu.reg_read(UC_RISCV_REG_X21), + "x22": mu.reg_read(UC_RISCV_REG_X22), + "x23": mu.reg_read(UC_RISCV_REG_X23), + "x24": mu.reg_read(UC_RISCV_REG_X24), + "x25": mu.reg_read(UC_RISCV_REG_X25), + "x26": mu.reg_read(UC_RISCV_REG_X26), + "x27": mu.reg_read(UC_RISCV_REG_X27), + "x28": mu.reg_read(UC_RISCV_REG_X28), + "x29": mu.reg_read(UC_RISCV_REG_X29), + "x30": mu.reg_read(UC_RISCV_REG_X30), + "x31": mu.reg_read(UC_RISCV_REG_X31), + "f0": mu.reg_read(UC_RISCV_REG_F0), + "f1": mu.reg_read(UC_RISCV_REG_F1), + "f2": mu.reg_read(UC_RISCV_REG_F2), + "f3": mu.reg_read(UC_RISCV_REG_F3), + "f4": mu.reg_read(UC_RISCV_REG_F4), + "f5": mu.reg_read(UC_RISCV_REG_F5), + "f6": mu.reg_read(UC_RISCV_REG_F6), + "f7": mu.reg_read(UC_RISCV_REG_F7), + "f8": mu.reg_read(UC_RISCV_REG_F8), + "f9": mu.reg_read(UC_RISCV_REG_F9), + "f10": mu.reg_read(UC_RISCV_REG_F10), + "f11": mu.reg_read(UC_RISCV_REG_F11), + "f12": mu.reg_read(UC_RISCV_REG_F12), + "f13": mu.reg_read(UC_RISCV_REG_F13), + "f14": mu.reg_read(UC_RISCV_REG_F14), + "f15": mu.reg_read(UC_RISCV_REG_F15), + "f16": mu.reg_read(UC_RISCV_REG_F16), + "f17": mu.reg_read(UC_RISCV_REG_F17), + "f18": mu.reg_read(UC_RISCV_REG_F18), + "f19": mu.reg_read(UC_RISCV_REG_F19), + "f20": mu.reg_read(UC_RISCV_REG_F20), + "f21": mu.reg_read(UC_RISCV_REG_F21), + "f22": mu.reg_read(UC_RISCV_REG_F22), + "f23": mu.reg_read(UC_RISCV_REG_F23), + "f24": mu.reg_read(UC_RISCV_REG_F24), + "f25": mu.reg_read(UC_RISCV_REG_F25), + "f26": mu.reg_read(UC_RISCV_REG_F26), + "f27": mu.reg_read(UC_RISCV_REG_F27), + "f28": mu.reg_read(UC_RISCV_REG_F28), + "f29": mu.reg_read(UC_RISCV_REG_F29), + "f30": mu.reg_read(UC_RISCV_REG_F30), + "f31": mu.reg_read(UC_RISCV_REG_F31), + "pc": mu.reg_read(UC_RISCV_REG_PC), + } + return ostate + + +def emu_with_triton(opcode, istate): + ctx = TritonContext() + ctx.setArchitecture(ARCH.RV64) + + inst = Instruction(opcode) + inst.setAddress(istate['pc']) + + ctx.setConcreteMemoryAreaValue(STACK, bytes(istate['stack'])) + ctx.setConcreteMemoryAreaValue(HEAP, bytes(istate['heap'])) + ctx.setConcreteRegisterValue(ctx.registers.x0, 0) + ctx.setConcreteRegisterValue(ctx.registers.x1, istate['x1']) + ctx.setConcreteRegisterValue(ctx.registers.x2, istate['x2']) + ctx.setConcreteRegisterValue(ctx.registers.x3, istate['x3']) + ctx.setConcreteRegisterValue(ctx.registers.x4, istate['x4']) + ctx.setConcreteRegisterValue(ctx.registers.x5, istate['x5']) + ctx.setConcreteRegisterValue(ctx.registers.x6, istate['x6']) + ctx.setConcreteRegisterValue(ctx.registers.x7, istate['x7']) + ctx.setConcreteRegisterValue(ctx.registers.x8, istate['x8']) + ctx.setConcreteRegisterValue(ctx.registers.x9, istate['x9']) + ctx.setConcreteRegisterValue(ctx.registers.x10, istate['x10']) + ctx.setConcreteRegisterValue(ctx.registers.x11, istate['x11']) + ctx.setConcreteRegisterValue(ctx.registers.x12, istate['x12']) + ctx.setConcreteRegisterValue(ctx.registers.x13, istate['x13']) + ctx.setConcreteRegisterValue(ctx.registers.x14, istate['x14']) + ctx.setConcreteRegisterValue(ctx.registers.x15, istate['x15']) + ctx.setConcreteRegisterValue(ctx.registers.x16, istate['x16']) + ctx.setConcreteRegisterValue(ctx.registers.x17, istate['x17']) + ctx.setConcreteRegisterValue(ctx.registers.x18, istate['x18']) + ctx.setConcreteRegisterValue(ctx.registers.x19, istate['x19']) + ctx.setConcreteRegisterValue(ctx.registers.x20, istate['x20']) + ctx.setConcreteRegisterValue(ctx.registers.x21, istate['x21']) + ctx.setConcreteRegisterValue(ctx.registers.x22, istate['x22']) + ctx.setConcreteRegisterValue(ctx.registers.x23, istate['x23']) + ctx.setConcreteRegisterValue(ctx.registers.x24, istate['x24']) + ctx.setConcreteRegisterValue(ctx.registers.x25, istate['x25']) + ctx.setConcreteRegisterValue(ctx.registers.x26, istate['x26']) + ctx.setConcreteRegisterValue(ctx.registers.x27, istate['x27']) + ctx.setConcreteRegisterValue(ctx.registers.x28, istate['x28']) + ctx.setConcreteRegisterValue(ctx.registers.x29, istate['x29']) + ctx.setConcreteRegisterValue(ctx.registers.x30, istate['x30']) + ctx.setConcreteRegisterValue(ctx.registers.x31, istate['x31']) + ctx.setConcreteRegisterValue(ctx.registers.f0, istate['f0']) + ctx.setConcreteRegisterValue(ctx.registers.f1, istate['f1']) + ctx.setConcreteRegisterValue(ctx.registers.f2, istate['f2']) + ctx.setConcreteRegisterValue(ctx.registers.f3, istate['f3']) + ctx.setConcreteRegisterValue(ctx.registers.f4, istate['f4']) + ctx.setConcreteRegisterValue(ctx.registers.f5, istate['f5']) + ctx.setConcreteRegisterValue(ctx.registers.f6, istate['f6']) + ctx.setConcreteRegisterValue(ctx.registers.f7, istate['f7']) + ctx.setConcreteRegisterValue(ctx.registers.f8, istate['f8']) + ctx.setConcreteRegisterValue(ctx.registers.f9, istate['f9']) + ctx.setConcreteRegisterValue(ctx.registers.f10, istate['f10']) + ctx.setConcreteRegisterValue(ctx.registers.f11, istate['f11']) + ctx.setConcreteRegisterValue(ctx.registers.f12, istate['f12']) + ctx.setConcreteRegisterValue(ctx.registers.f13, istate['f13']) + ctx.setConcreteRegisterValue(ctx.registers.f14, istate['f14']) + ctx.setConcreteRegisterValue(ctx.registers.f15, istate['f15']) + ctx.setConcreteRegisterValue(ctx.registers.f16, istate['f16']) + ctx.setConcreteRegisterValue(ctx.registers.f17, istate['f17']) + ctx.setConcreteRegisterValue(ctx.registers.f18, istate['f18']) + ctx.setConcreteRegisterValue(ctx.registers.f19, istate['f19']) + ctx.setConcreteRegisterValue(ctx.registers.f20, istate['f20']) + ctx.setConcreteRegisterValue(ctx.registers.f21, istate['f21']) + ctx.setConcreteRegisterValue(ctx.registers.f22, istate['f22']) + ctx.setConcreteRegisterValue(ctx.registers.f23, istate['f23']) + ctx.setConcreteRegisterValue(ctx.registers.f24, istate['f24']) + ctx.setConcreteRegisterValue(ctx.registers.f25, istate['f25']) + ctx.setConcreteRegisterValue(ctx.registers.f26, istate['f26']) + ctx.setConcreteRegisterValue(ctx.registers.f27, istate['f27']) + ctx.setConcreteRegisterValue(ctx.registers.f28, istate['f28']) + ctx.setConcreteRegisterValue(ctx.registers.f29, istate['f29']) + ctx.setConcreteRegisterValue(ctx.registers.f30, istate['f30']) + ctx.setConcreteRegisterValue(ctx.registers.f31, istate['f31']) + ctx.setConcreteRegisterValue(ctx.registers.pc, istate['pc']) + + ctx.processing(inst) + + #print + #print(inst) + #for x in inst.getSymbolicExpressions(): + # print(x) + #print + + ostate = { + "stack": ctx.getConcreteMemoryAreaValue(STACK, 0x100), + "heap": ctx.getConcreteMemoryAreaValue(HEAP, 0x100), + + "x0": 0, + "x1": ctx.getSymbolicRegisterValue(ctx.registers.x1), + "x2": ctx.getSymbolicRegisterValue(ctx.registers.x2), + "x3": ctx.getSymbolicRegisterValue(ctx.registers.x3), + "x4": ctx.getSymbolicRegisterValue(ctx.registers.x4), + "x5": ctx.getSymbolicRegisterValue(ctx.registers.x5), + "x6": ctx.getSymbolicRegisterValue(ctx.registers.x6), + "x7": ctx.getSymbolicRegisterValue(ctx.registers.x7), + "x8": ctx.getSymbolicRegisterValue(ctx.registers.x8), + "x9": ctx.getSymbolicRegisterValue(ctx.registers.x9), + "x10": ctx.getSymbolicRegisterValue(ctx.registers.x10), + "x11": ctx.getSymbolicRegisterValue(ctx.registers.x11), + "x12": ctx.getSymbolicRegisterValue(ctx.registers.x12), + "x13": ctx.getSymbolicRegisterValue(ctx.registers.x13), + "x14": ctx.getSymbolicRegisterValue(ctx.registers.x14), + "x15": ctx.getSymbolicRegisterValue(ctx.registers.x15), + "x16": ctx.getSymbolicRegisterValue(ctx.registers.x16), + "x17": ctx.getSymbolicRegisterValue(ctx.registers.x17), + "x18": ctx.getSymbolicRegisterValue(ctx.registers.x18), + "x19": ctx.getSymbolicRegisterValue(ctx.registers.x19), + "x20": ctx.getSymbolicRegisterValue(ctx.registers.x20), + "x21": ctx.getSymbolicRegisterValue(ctx.registers.x21), + "x22": ctx.getSymbolicRegisterValue(ctx.registers.x22), + "x23": ctx.getSymbolicRegisterValue(ctx.registers.x23), + "x24": ctx.getSymbolicRegisterValue(ctx.registers.x24), + "x25": ctx.getSymbolicRegisterValue(ctx.registers.x25), + "x26": ctx.getSymbolicRegisterValue(ctx.registers.x26), + "x27": ctx.getSymbolicRegisterValue(ctx.registers.x27), + "x28": ctx.getSymbolicRegisterValue(ctx.registers.x28), + "x29": ctx.getSymbolicRegisterValue(ctx.registers.x29), + "x30": ctx.getSymbolicRegisterValue(ctx.registers.x30), + "x31": ctx.getSymbolicRegisterValue(ctx.registers.x31), + "f0": ctx.getSymbolicRegisterValue(ctx.registers.f0), + "f1": ctx.getSymbolicRegisterValue(ctx.registers.f1), + "f2": ctx.getSymbolicRegisterValue(ctx.registers.f2), + "f3": ctx.getSymbolicRegisterValue(ctx.registers.f3), + "f4": ctx.getSymbolicRegisterValue(ctx.registers.f4), + "f5": ctx.getSymbolicRegisterValue(ctx.registers.f5), + "f6": ctx.getSymbolicRegisterValue(ctx.registers.f6), + "f7": ctx.getSymbolicRegisterValue(ctx.registers.f7), + "f8": ctx.getSymbolicRegisterValue(ctx.registers.f8), + "f9": ctx.getSymbolicRegisterValue(ctx.registers.f9), + "f10": ctx.getSymbolicRegisterValue(ctx.registers.f10), + "f11": ctx.getSymbolicRegisterValue(ctx.registers.f11), + "f12": ctx.getSymbolicRegisterValue(ctx.registers.f12), + "f13": ctx.getSymbolicRegisterValue(ctx.registers.f13), + "f14": ctx.getSymbolicRegisterValue(ctx.registers.f14), + "f15": ctx.getSymbolicRegisterValue(ctx.registers.f15), + "f16": ctx.getSymbolicRegisterValue(ctx.registers.f16), + "f17": ctx.getSymbolicRegisterValue(ctx.registers.f17), + "f18": ctx.getSymbolicRegisterValue(ctx.registers.f18), + "f19": ctx.getSymbolicRegisterValue(ctx.registers.f19), + "f20": ctx.getSymbolicRegisterValue(ctx.registers.f20), + "f21": ctx.getSymbolicRegisterValue(ctx.registers.f21), + "f22": ctx.getSymbolicRegisterValue(ctx.registers.f22), + "f23": ctx.getSymbolicRegisterValue(ctx.registers.f23), + "f24": ctx.getSymbolicRegisterValue(ctx.registers.f24), + "f25": ctx.getSymbolicRegisterValue(ctx.registers.f25), + "f26": ctx.getSymbolicRegisterValue(ctx.registers.f26), + "f27": ctx.getSymbolicRegisterValue(ctx.registers.f27), + "f28": ctx.getSymbolicRegisterValue(ctx.registers.f28), + "f29": ctx.getSymbolicRegisterValue(ctx.registers.f29), + "f30": ctx.getSymbolicRegisterValue(ctx.registers.f30), + "f31": ctx.getSymbolicRegisterValue(ctx.registers.f31), + "pc": ctx.getSymbolicRegisterValue(ctx.registers.pc), + } + return ostate + + +def diff_state(state1, state2): + for k, v in list(state1.items()): + if (k == 'heap' or k == 'stack') and v != state2[k]: + print('\t%s: (UC) != (TT)' %(k)) + elif not (k == 'heap' or k == 'stack') and v != state2[k]: + print('\t%s: %#x (UC) != %#x (TT)' %(k, v, state2[k])) + return + + +if __name__ == '__main__': + # initial state + state = { + "stack": bytearray(b"".join([pack('B', 255 - i) for i in range(256)])), + "heap": bytearray(b"".join([pack('B', i) for i in range(256)])), + "x0": 0x0, + "x1": 0x0, + "x2": STACK, + "x3": 0x0, + "x4": 0x0, + "x5": 0x0, + "x6": 0x0, + "x7": 0x0, + "x8": 0x0, + "x9": 0x0, + "x10": 0x0, + "x11": 0x0, + "x12": 0x0, + "x13": 0x0, + "x14": 0x0, + "x15": 0x0, + "x16": 0x0, + "x17": 0x0, + "x18": 0x0, + "x19": 0x0, + "x20": 0x0, + "x21": 0x0, + "x22": 0x0, + "x23": 0x0, + "x24": 0x0, + "x25": 0x0, + "x26": 0x0, + "x27": 0x0, + "x28": 0x0, + "x29": 0x0, + "x30": 0x0, + "x31": 0xabcdef2107ff, + "f0": 0x00112233445566778899aabbccddeeff, + "f1": 0xffeeddccbbaa99887766554433221100, + "f2": 0xfefedcdc5656787889892692dfeccaa0, + "f3": 0x1234567890987654321bcdffccddee01, + "f4": 0x0, + "f5": 0x0, + "f6": 0x0, + "f7": 0x0, + "f8": 0x0, + "f9": 0x0, + "f10": 0x0, + "f11": 0x0, + "f12": 0x0, + "f13": 0x0, + "f14": 0x0, + "f15": 0x0, + "f16": 0x0, + "f17": 0x0, + "f18": 0x0, + "f19": 0x0, + "f20": 0x0, + "f21": 0x0, + "f22": 0x0, + "f23": 0x0, + "f24": 0x0, + "f25": 0x0, + "f26": 0x0, + "f27": 0x0, + "f28": 0x0, + "f29": 0x0, + "f30": 0x0, + "f31": 0x0, + "pc": ADDR, + } + + for opcode, disassembly in CODE: + try: + uc_state = emu_with_unicorn(opcode, state) + tt_state = emu_with_triton(opcode, state) + except Exception as e: + print('[KO] %s' %(disassembly)) + print('\t%s' %(e)) + sys.exit(-1) + + if uc_state != tt_state: + print('[KO] %s' %(disassembly)) + diff_state(uc_state, tt_state) + sys.exit(-1) + + print('[OK] %s' %(disassembly)) + state = tt_state + + sys.exit(0) diff --git a/src/testers/unittests/test_examples.py b/src/testers/unittests/test_examples.py index c37c9b9a1..46e1c49bd 100644 --- a/src/testers/unittests/test_examples.py +++ b/src/testers/unittests/test_examples.py @@ -34,6 +34,8 @@ def _test_example(self, example_name=example): if ('TRAVIS' in os.environ or 'APPVEYOR' in os.environ) and example_name.find('hackcon-2016-angry-reverser') >= 0: # FIXME: Doesn't work on Travis and Appveyor... return + if ('APPVEYOR' in os.environ or not 'COMPILE_RISCV' in os.environ) and example_name.find('riscv') >= 0: + return p = subprocess.Popen([sys.executable, example_name] + args, stdout=subprocess.PIPE, stderr=subprocess.PIPE) out, err = p.communicate() diff --git a/src/testers/unittests/test_github_issues.py b/src/testers/unittests/test_github_issues.py index 1bfd03291..ac742298c 100644 --- a/src/testers/unittests/test_github_issues.py +++ b/src/testers/unittests/test_github_issues.py @@ -3,6 +3,7 @@ """Issue from Github.""" import unittest +import os from triton import * @@ -662,34 +663,40 @@ def test_1(self): self.assertEqual(x17, 0x72) -# FIXME: Uncomment this one when we will move to Capstone 5 as min version -#class TestIssue1195(unittest.TestCase): -# """Testing #1195.""" -# -# def test_1(self): -# ctx = TritonContext(ARCH.AARCH64) -# -# ctx.setConcreteRegisterValue(ctx.registers.x20, 0) -# ctx.setConcreteRegisterValue(ctx.registers.tpidr_el0, 0x1122334455667788) -# -# self.assertEqual(ctx.getConcreteRegisterValue(ctx.registers.tpidr_el0), 0x1122334455667788) -# self.assertEqual(ctx.getConcreteRegisterValue(ctx.registers.x20), 0) -# -# ctx.processing(Instruction(b"\x54\xD0\x3B\xD5")) # mrs x20, tpidr_el0 -# -# self.assertEqual(ctx.getConcreteRegisterValue(ctx.registers.tpidr_el0), 0x1122334455667788) -# self.assertEqual(ctx.getConcreteRegisterValue(ctx.registers.x20), 0x1122334455667788) -# -# def test_2(self): -# ctx = TritonContext(ARCH.AARCH64) -# -# ctx.setConcreteRegisterValue(ctx.registers.x20, 0x1122334455667788) -# ctx.setConcreteRegisterValue(ctx.registers.tpidr_el0, 0) -# -# self.assertEqual(ctx.getConcreteRegisterValue(ctx.registers.tpidr_el0), 0) -# self.assertEqual(ctx.getConcreteRegisterValue(ctx.registers.x20), 0x1122334455667788) -# -# ctx.processing(Instruction(b"\x54\xd0\x1b\xd5")) # msr tpidr_el0, x20 -# -# self.assertEqual(ctx.getConcreteRegisterValue(ctx.registers.tpidr_el0), 0x1122334455667788) -# self.assertEqual(ctx.getConcreteRegisterValue(ctx.registers.x20), 0x1122334455667788) +# FIXME: Add Appveyor when we will move to Capstone 5 as min version +class TestIssue1195(unittest.TestCase): + """Testing #1195.""" + + def test_1(self): + if ('APPVEYOR' in os.environ): + pass + else: + ctx = TritonContext(ARCH.AARCH64) + + ctx.setConcreteRegisterValue(ctx.registers.x20, 0) + ctx.setConcreteRegisterValue(ctx.registers.tpidr_el0, 0x1122334455667788) + + self.assertEqual(ctx.getConcreteRegisterValue(ctx.registers.tpidr_el0), 0x1122334455667788) + self.assertEqual(ctx.getConcreteRegisterValue(ctx.registers.x20), 0) + + ctx.processing(Instruction(b"\x54\xD0\x3B\xD5")) # mrs x20, tpidr_el0 + + self.assertEqual(ctx.getConcreteRegisterValue(ctx.registers.tpidr_el0), 0x1122334455667788) + self.assertEqual(ctx.getConcreteRegisterValue(ctx.registers.x20), 0x1122334455667788) + + def test_2(self): + if ('APPVEYOR' in os.environ): + pass + else: + ctx = TritonContext(ARCH.AARCH64) + + ctx.setConcreteRegisterValue(ctx.registers.x20, 0x1122334455667788) + ctx.setConcreteRegisterValue(ctx.registers.tpidr_el0, 0) + + self.assertEqual(ctx.getConcreteRegisterValue(ctx.registers.tpidr_el0), 0) + self.assertEqual(ctx.getConcreteRegisterValue(ctx.registers.x20), 0x1122334455667788) + + ctx.processing(Instruction(b"\x54\xd0\x1b\xd5")) # msr tpidr_el0, x20 + + self.assertEqual(ctx.getConcreteRegisterValue(ctx.registers.tpidr_el0), 0x1122334455667788) + self.assertEqual(ctx.getConcreteRegisterValue(ctx.registers.x20), 0x1122334455667788) diff --git a/vcpkg.json b/vcpkg.json index 1586c9351..c158b2d69 100644 --- a/vcpkg.json +++ b/vcpkg.json @@ -11,10 +11,10 @@ "boost-math", "boost-multiprecision", "boost-numeric-conversion", - { "name": "capstone", "default-features": false, "features": ["arm", "arm64", "x86"] }, + { "name": "capstone", "default-features": false, "features": ["arm", "arm64", "riscv", "x86"] }, "z3" ], "overrides": [ - { "name":"capstone", "version-semver":"5.0.0-rc2" } + { "name":"capstone", "version-semver":"5.0.1", "port-version": 1 } ] }