Compare commits

...

5 Commits

@ -143,6 +143,6 @@ jobs:
run: sudo apt install -y cppcheck
- name: Run cppcheck
run: cppcheck --error-exitcode=1 --language=c \
--enable=all --suppress=missingIncludeSystem --suppress=unusedStructMember --suppress=unusedFunction \
--enable=all --suppress=missingIncludeSystem --suppress=unusedStructMember --suppress=unusedFunction --suppress=objectIndex \
-I inc/ -I bddisasm/include bddisasm/ bdshemu/ \
/

8
.gitignore vendored

@ -57,7 +57,9 @@ compile_commands.json
pydis/.eggs
bdshemu_fuzz/out
bdshemu_fuzz/shfuzz
bdshemu_fuzz/in-32
bdshemu_fuzz/out-32
bdshemu_fuzz/in-64
bdshemu_fuzz/out-64
docs/build
libbddisasm.pc
@ -67,3 +69,9 @@ disasmtool_lix/_build
bindings/rsbddisasm/target
bindings/rsbddisasm/Cargo.lock
bindings/pybddisasm/pybddisasm.egg-info
bindings/rsbddisasm/bddisasm/target
bindings/pybddisasm/pybddisasm/pybddisasm.py
bindings/pybddisasm/pybddisasm/pybddisasm_wrap.c
bddfuzz.tar
bindings/pybddisasm/.eggs

@ -0,0 +1,54 @@
# Changelog
All notable (user-facing) changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
## [2.1.0] - 2024-02-20
### Added
- Support in bddisasm for Intel REX2 prefix.
- Support in bddisasm for Intel APX extensions.
- Support in bddisasm for Intel USERMSR extensions.
- Support in bddisasm for prefix activation fields inside `INSTRUX` - these fields can be consulted to determine whether a particular prefix is present, accepted & active.
- New feature in bdshemu: `SHEMU_OPT_DIRECT_MAPPED_SHELL` - allows emulation with a smaller `IntBuff` at the cost of not having `WRITE_SELF` detections. The shellcode can be provided directly from its original location, without the need to allocate it in a dedicated memory region.
- New feature in bdshemu: `SHEMU_OPT_TRACK_LOOPS` - loops can now be tracked by bdshemu. `SHEMU_OPT_TRACE_LOOPS` can be used to log loop information.
- Support in bdshemu for APX instructions (both REX2 and EVEX encoded instructions) - the new `SHEMU_OPT_SUPPORT_APX` must be set in order to enable APX emulation.
### Changed
- Reduced the size of the `INSTRUX` structure from 856 bytes to 488 bytes (almost -43%!).
- Increased decoding performance from average 300 clocks/instruction to average 235 clocks/instruction (almost +20%!).
- New decode options - do not decode implicit operands - this further increases performance from average 235 clocks/instruction to 200 clocks/instruction (almost +15%!).
- Re-worked the Python scripts - both `disasmlib.py` and `generate_tables.py` have been significantly reworked, improving readability, and making them more efficient.
- `disasmtool` builds on Linux.
### Removed
- Support for Cyrix & VIA instructions - only current Intel & AMD instructions remain supported.
- disasmtool_lix has been removed. `disasmtool` is available on Linux as well.
### Breaking changes
#### Inside INSTRUX
- Removed `Iclass` field - it was aliased over `Instruction` field, which must be used from now on.
- Removed `OperandsEncodingMap` field - one can consult the `Encoding` field in each operand to determine the encoding.
- Removed `ExceptionClass` field - only `ExceptionType` remains, which contains an enum with all the exception types.
- Removed `Predicate` field - only `Condition` remains, which was aliased over `Predicate`.
- Removed `HasImm3`, `Immediate3`, `Imm3Length` and `Imm3Offset` fields, as they were not used/needed.
- Removed `Bhint`, `SseCondition`, `SignDisp` fields, as they were not used.
- Moved `FlagsAccess.RegAccess` outside and renamed it to `RflAccess`, to save more space.
- Switched from `char Mnemonic[32]` to `const char *Mnemonic` - this decreases INSTRUX size by almost 32 bytes, and increases perf.
#### Inside ND_OPERAND
- Removed `RawSize` - in most cases, `Size` and `RawSize` are identical; the only case where they might differ is for `Immediate` and `RelativeOffset` operands - in that case, one can consult the `RawSize` field in `Immediate` or `RelativeOffset`.
#### Inside ND_OPERAND_DECORATOR
- Removed `Broadcast` field, moved it inside `ND_OPDESC_MEMORY`.
- Removed `HasSae`, `HasEr` - they are per instruction, not per operand, and can be consulted directly inside `INSTRUX`.
- Moved `Msk` one level up, inside the `ND_OPERAND_DECORATOR` structure.
#### Defines & constants
- Removed `ND_PRED_*` defines - search & replace them with `ND_COND_*`.
- Removed `ND_HAS_PREDICATE` - use `ND_HAS_CONDITION` instead.
- Removed `ND_VEND_GEODE` and `ND_VEND_CYRIX`.

@ -1,16 +1,18 @@
cmake_minimum_required(VERSION 3.16)
option(BDD_INCLUDE_TOOL "Include the disasmtool executable" ON)
option(BDD_INCLUDE_ISAGENERATOR "Include the isagenerator target (if a python interpreter is found)" ON)
option(BDD_INCLUDE_ISAGENERATOR_X86 "Include the x86 isagenerator target (if a python interpreter is found)" ON)
option(BDD_INCLUDE_FUZZERS "Include the bdshemu fuzzer" OFF)
option(BDD_USE_EXTERNAL_VSNPRINTF "Expect nd_vsnprintf_s implementation from the integrator" OFF)
option(BDD_USE_EXTERNAL_MEMSET "Expect nd_memset implementation from the integrator" OFF)
option(BDD_ASAN "Build with ASAN" OFF)
option(BDD_UBSAN "Build with UBSAN" OFF)
set(BDD_VER_FILE ${CMAKE_CURRENT_LIST_DIR}/inc/version.h)
set(BDD_VER_FILE ${CMAKE_CURRENT_LIST_DIR}/inc/bddisasm_version.h)
file(STRINGS ${BDD_VER_FILE} disasm_ver_major REGEX "DISASM_VERSION_MAJOR")
file(STRINGS ${BDD_VER_FILE} disasm_ver_minor REGEX "DISASM_VERSION_MINOR")
file(STRINGS ${BDD_VER_FILE} disasm_ver_patch REGEX "DISASM_VERSION_REVISION")
file(STRINGS ${BDD_VER_FILE} disasm_ver_major REGEX "#define DISASM_VERSION_MAJOR")
file(STRINGS ${BDD_VER_FILE} disasm_ver_minor REGEX "#define DISASM_VERSION_MINOR")
file(STRINGS ${BDD_VER_FILE} disasm_ver_patch REGEX "#define DISASM_VERSION_REVISION")
string(REGEX REPLACE "#define DISASM_VERSION_MAJOR[ \t\r\n]*" "" disasm_ver_major ${disasm_ver_major})
string(REGEX REPLACE "#define DISASM_VERSION_MINOR[ \t\r\n]*" "" disasm_ver_minor ${disasm_ver_minor})
@ -25,7 +27,7 @@ project(
LANGUAGES C
HOMEPAGE_URL https://github.com/bitdefender/bddisasm)
# Use Release as the build type if no build type was specified and we're not using a multi-config generator .
# Use Release as the build type if no build type was specified and we're not using a multi-config generator.
if (NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
message(STATUS "No build type given. Will use 'Release'")
set(CMAKE_BUILD_TYPE
@ -79,12 +81,17 @@ endif ()
set(BDDISASM_PUBLIC_HEADERS
"inc/bddisasm.h"
"inc/constants.h"
"inc/cpuidflags.h"
"inc/disasmstatus.h"
"inc/disasmtypes.h"
"inc/registers.h"
"inc/version.h")
"inc/bddisasm_status.h"
"inc/bddisasm_types.h"
"inc/bddisasm_version.h"
"inc/bdx86_constants.h"
"inc/bdx86_core.h"
"inc/bdx86_cpuidflags.h"
"inc/bdx86_registers.h")
set(BDSHEMU_PUBLIC_HEADERS
"inc/bdshemu_x86.h"
"inc/bdshemu.h")
include(GNUInstallDirs)
@ -100,20 +107,20 @@ include(CheckCCompilerFlag)
add_library(
bddisasm STATIC
bddisasm/crt.c
bddisasm/bddisasm.c
bddisasm/bdformat.c
bddisasm/bdhelpers.c
bddisasm/bddisasm_crt.c
bddisasm/bdx86_decoder.c
bddisasm/bdx86_formatter.c
bddisasm/bdx86_helpers.c
# Add the headers so they will show up in IDEs.
bddisasm/include/instructions.h
bddisasm/include/mnemonics.h
bddisasm/include/nd_crt.h
bddisasm/include/prefixes.h
bddisasm/include/table_evex.h
bddisasm/include/table_root.h
bddisasm/include/table_vex.h
bddisasm/include/table_xop.h
bddisasm/include/tabledefs.h
bddisasm/include/bddisasm_crt.h
bddisasm/include/bdx86_instructions.h
bddisasm/include/bdx86_mnemonics.h
bddisasm/include/bdx86_prefixes.h
bddisasm/include/bdx86_tabledefs.h
bddisasm/include/bdx86_table_evex.h
bddisasm/include/bdx86_table_root.h
bddisasm/include/bdx86_table_vex.h
bddisasm/include/bdx86_table_xop.h
"${BDDISASM_PUBLIC_HEADERS}")
if (NOT BDD_USE_EXTERNAL_VSNPRINTF)
@ -154,6 +161,20 @@ set_target_properties(
VERSION ${CMAKE_PROJECT_VERSION}
SOVERSION ${CMAKE_PROJECT_VERSION_MAJOR})
if (BDD_ASAN)
target_compile_options(bddisasm PUBLIC "-fsanitize=address")
target_link_libraries(bddisasm PUBLIC "-fsanitize=address")
endif ()
if (BDD_UBSAN)
target_compile_options(bddisasm PUBLIC
"-fsanitize=undefined"
"-fno-sanitize=alignment")
target_link_libraries(bddisasm PUBLIC
"-fsanitize=undefined"
"-fno-sanitize=alignment")
endif ()
add_library(bddisasm::bddisasm ALIAS bddisasm)
# -- bdshemu --
@ -161,8 +182,10 @@ add_library(bddisasm::bddisasm ALIAS bddisasm)
add_library(
bdshemu STATIC
bdshemu/bdshemu.c
bdshemu/bdshemu_x86.c
# Add the headers so they will show up in IDEs.
inc/bdshemu.h)
bdshemu/include/bdshemu_common.h
"${BDSHEMU_PUBLIC_HEADERS}")
set_target_properties(
bdshemu
@ -185,7 +208,7 @@ endif ()
set_target_properties(
bdshemu
PROPERTIES PUBLIC_HEADER "inc/bdshemu.h"
PROPERTIES PUBLIC_HEADER "${BDSHEMU_PUBLIC_HEADERS}"
VERSION ${CMAKE_PROJECT_VERSION}
SOVERSION ${CMAKE_PROJECT_VERSION_MAJOR})
@ -193,19 +216,14 @@ add_library(bddisasm::bdshemu ALIAS bdshemu)
# If this is the master project (and if the user requested it) add disasmtool.
if ((${CMAKE_PROJECT_NAME} STREQUAL ${PROJECT_NAME}) AND BDD_INCLUDE_TOOL)
if (WIN32)
add_subdirectory(disasmtool)
else ()
add_subdirectory(disasmtool_lix)
endif ()
add_subdirectory(disasmtool)
endif ()
# If this is the master project (and if the user requested it) add isagenerator.
if ((${CMAKE_PROJECT_NAME} STREQUAL ${PROJECT_NAME}) AND BDD_INCLUDE_ISAGENERATOR)
if ((${CMAKE_PROJECT_NAME} STREQUAL ${PROJECT_NAME}) AND BDD_INCLUDE_ISAGENERATOR_X86)
add_subdirectory(isagenerator)
endif ()
# If this is the master project (and if the user requested it) add the fuzzer.
if ((${CMAKE_PROJECT_NAME} STREQUAL ${PROJECT_NAME}) AND BDD_INCLUDE_FUZZERS)
add_subdirectory(bdshemu_fuzz)
endif ()
@ -236,7 +254,7 @@ if (${CMAKE_PROJECT_NAME} STREQUAL ${PROJECT_NAME})
COMPONENT bddisasm_Runtime
NAMELINK_COMPONENT bddisasm_Development
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT bddisasm_Development)
if (BDD_INCLUDE_TOOL)
install(
TARGETS disasmtool

@ -0,0 +1,118 @@
FROM ubuntu:22.04 as build
WORKDIR /bddfuzz
# Install everything we need to build AFL++ and honggfuzz and bdshemu
# We install both clang-13 and clang-15 because honggfuzz does not support newer versions of clang, but AFL++ wants
# the latest version so it is what it is
RUN apt-get update && apt-get install -y \
cmake make git \
binutils-dev \
libunwind-dev \
libblocksruntime-dev \
clang-13 \
clang-15 \
llvm-15 llvm-15-dev llvm-15-linker-tools llvm-15-runtime llvm-15-tools lld-15
# Cleanup
RUN apt-get clean && rm -rf /var/lib/apt/lists/*
RUN mkdir /bddfuzz/fuzzers
# Build and install AFL++
RUN cd /bddfuzz/fuzzers && git clone https://github.com/AFLplusplus/AFLplusplus.git
RUN cd /bddfuzz/fuzzers/AFLplusplus && \
CC=clang-15 CXX=clang++-15 make source-only install LLVM_CONFIG=llvm-config-15 NO_NYX=1
# Build and install honggfuzz
RUN cd /bddfuzz/fuzzers && git clone --depth 1 --branch 2.5 https://github.com/google/honggfuzz.git
RUN cd /bddfuzz/fuzzers/honggfuzz && make install
# Remove the fuzzer source files as we no longer need them
RUN cd /bddfuzz/fuzzers/AFLplusplus && git clean -dxf && git clean -dXf && rm -rf /bddfuzz/fuzzers/AFLplusplus
RUN rm -rf /bddfuzz/fuzzers/honggfuzz
RUN rm -rf /bddfuzz/fuzzers/
ENV SRC /bddfuzz/src/
# Copy the relevant bddisasm sources
RUN mkdir "${SRC}"
COPY CMakeLists.txt "${SRC}"/CMakeLists.txt
COPY bddisasm.pc.in "${SRC}"/bddisasm.pc.in
COPY bddisasmConfig.cmake "${SRC}"/bddisasmConfig.cmake
COPY bddisasm "${SRC}"/bddisasm
COPY bdshemu "${SRC}"/bdshemu
COPY bdshemu_fuzz "${SRC}"/bdshemu_fuzz
COPY inc "${SRC}"/inc
# Now build all the variants
RUN mkdir build
# Build for AFL++ with afl-clang-lto
RUN mkdir /bddfuzz/build/afllto && cd /bddfuzz/build/afllto && \
cmake "${SRC}" -DCMAKE_C_COMPILER=afl-clang-lto -DCMAKE_CXX_COMPILER=afl-clang-lto++ \
-DCMAKE_BUILD_TYPE=Releaase \
-DBDD_INCLUDE_TOOL=OFF -DBDD_INCLUDE_ISAGENERATOR_X86=OFF \
-DBDD_INCLUDE_FUZZERS=ON && \
make shfuzz
# Build for honggfuzz
RUN mkdir /bddfuzz/build/hfuzz && cd /bddfuzz/build/hfuzz && \
cmake "${SRC}" -DCMAKE_C_COMPILER=hfuzz-clang -DCMAKE_CXX_COMPILER=hfuzz-clang++ \
-DCMAKE_BUILD_TYPE=Releaase \
-DBDD_INCLUDE_TOOL=OFF -DBDD_INCLUDE_ISAGENERATOR_X86=OFF \
-DBDD_INCLUDE_FUZZERS=ON && \
make shfuzz
# Build for libfuzzer with ASAN and UBSAN
RUN mkdir /bddfuzz/build/san && cd /bddfuzz/build/san && \
cmake "${SRC}" -DCMAKE_C_COMPILER=clang-15 -DCMAKE_CXX_COMPILER=clang-15++ \
-DCMAKE_BUILD_TYPE=Releaase \
-DBDD_INCLUDE_TOOL=OFF -DBDD_INCLUDE_ISAGENERATOR_X86=OFF \
-DBDD_INCLUDE_FUZZERS=ON -DBDD_FUZZ_WITH_LOGS=ON \
-DBDD_ASAN=ON -DBDD_UBSAN=ON && \
make shfuzz
RUN rm -rf "${SRC}"
# Save the fuzzers
RUN mkdir /bddfuzz/shf && cd /bddfuzz/shf && \
for d in /bddfuzz/build/*; do \
mkdir ./`basename "${d}"` && \
cp -v "${d}"/bdshemu_fuzz/shfuzz* ./`basename "${d}"`; \
done
# Remove the build directory
RUN rm -rf build
FROM ubuntu:22.04 as run
WORKDIR /bddfuzz
# Copy the fuzzers from the build stage
COPY --from=build /bddfuzz/shf /bddfuzz/shf
# Copy AFL++ and honggfuzz binaries
COPY --from=build /usr/local/bin/afl-* /usr/local/bin/
COPY --from=build /usr/local/bin/hfuzz-* /usr/local/bin/
COPY --from=build /usr/local/bin/honggfuzz /usr/local/bin/
RUN mkdir /bddfuzz/inputs
COPY bdshemu_fuzz/in-32 /bddfuzz/inputs/in-32
COPY bdshemu_fuzz/in-64 /bddfuzz/inputs/in-64
# Runtime dependencies for honggfuzz
RUN apt-get update && apt-get install -y binutils-dev libunwind-dev libblocksruntime-dev
# Cleanup
RUN apt-get clean && rm -rf /var/lib/apt/lists/*
# So we can share files between the host and the container (we don't want to loose the results when we stop the
# container).
ENV SHARE_DIR share
COPY bdshemu_fuzz/fuzzing_image_entrypoint.sh /bddfuzz/fuzzing_image_entrypoint.sh
RUN chmod +x /bddfuzz/fuzzing_image_entrypoint.sh
ENTRYPOINT ["/bddfuzz/fuzzing_image_entrypoint.sh"]

@ -5,12 +5,10 @@ The Bitdefender disassembler (bddisasm) is a lightweight, x86/x64 only instructi
## Projects
1. [bddisasm](https://github.com/bitdefender/bddisasm/tree/master/bddisasm) - this is the main disassembler project. In order to use the Bitdefender disassembler, all you have to do is build this project, and link with the output library. The only headers you need are located inside the `inc` folder.
2. [bdshemu](https://github.com/bitdefender/bddisasm/tree/master/bdshemu) - this project makes use of the main bddisasm lib in order to build a simple, lightweight, fast, instructions emulator, designated to target shellcodes. This project is also integrated inside the disasmtool, so you can
emulate raw binary files, and see their output. Note that this simple emulator supports basic x86/x64 instructions, and does not support emulating any kind of API call. In addition, the only supported memory accesses are inside the shellcode itself, and on the emulated stack.
3. [isagenerator](https://github.com/bitdefender/bddisasm/tree/master/isagenerator) - this project contains the instruction definitions and the scripts required to generate the disassembly tables. If you wish to add support for a new instruction, this is the place. This project will automatically generate several header files (instructions.h, mnemonics.h, constants.h, table_\*.h), so please make sure you don't manually edit any of these files. You will need Python 3 to run the generation scripts.
2. [bdshemu](https://github.com/bitdefender/bddisasm/tree/master/bdshemu) - this project makes use of the main bddisasm lib in order to build a simple, lightweight, fast, instructions emulator, designated to target shellcodes. This project is also integrated inside the disasmtool, so you can emulate raw binary files, and see their output. Note that this simple emulator supports basic x86/x64 instructions, and does not support emulating any kind of API call. In addition, the only supported memory accesses are inside the shellcode itself, and on the emulated stack.
3. [isagenerator_x86](https://github.com/bitdefender/bddisasm/tree/master/isagenerator) - this project contains the instruction definitions and the scripts required to generate the disassembly tables. If you wish to add support for a new instruction, this is the place. This project will automatically generate several header files (instructions.h, mnemonics.h, constants.h, table_\*.h), so please make sure you don't manually edit any of these files. You will need Python 3 to run the generation scripts.
4. [disasmtool](https://github.com/bitdefender/bddisasm/tree/master/disasmtool) - this project is a command line disassembler tool, used mainly as an example of how to integrate the bddisasm and bdshemu libraries.
5. [disasmtool_lix](https://github.com/bitdefender/bddisasm/tree/master/disasmtool_lix) - like disasmtool, but for Linux.
6. [bindings](https://github.com/bitdefender/bddisasm/tree/master/bindings) - bindings for [python](https://github.com/bitdefender/bddisasm/tree/master/bindings/pybddisasm), and [Rust](https://github.com/bitdefender/bddisasm/tree/master/bindings/rsbddisasm).
5. [bindings](https://github.com/bitdefender/bddisasm/tree/master/bindings) - bindings for [python](https://github.com/bitdefender/bddisasm/tree/master/bindings/pybddisasm), and [Rust](https://github.com/bitdefender/bddisasm/tree/master/bindings/rsbddisasm).
## Objectives
@ -161,13 +159,13 @@ The results will be in the bin directory in the root of the repository.
[nd_vsnprintf_s and nd_memset](#nd_vsnprintf_s-and-nd_memset) will not be defined by `bddisasm`, integrators must provide these functions.
## Decoding instructions
## Decoding x86 instructions
### Decoding API
There are 4 decoding functions, but internally, they all do the same, albeit some of them with implicit arguments:
- `NDSTATUS NdDecode(INSTRUX *Instrux, const uint8_t *Code, uint8_t DefCode, uint8_t DefData)` - this API should be used only if you don't care about the length of the input buffer;
- `NDSTATUS NdDecode(INSTRUX *Instrux, const uint8_t *Code, uint8_t DefCode, uint8_t DefData)` - this API should be used only if you don't care about the length of the input buffer;
- `NDSTATUS NdDecodeEx(INSTRUX *Instrux, const uint8_t *Code, size_t Size, uint8_t DefCode, uint8_t DefData);` - decode instruction from a buffer with maximum length `Size`;
- `NDSTATUS NdDecodeEx2(INSTRUX *Instrux, const uint8_t *Code, size_t Size, uint8_t DefCode, uint8_t DefData, uint8_t DefStack, uint8_t PreferedVendor);` - decode instructions with a preferred vendor;
- `NDSTATUS NdDecodeWithContext(INSTRUX *Instrux, const uint8_t *Code, size_t Size, ND_CONTEXT *Context);` - base decode API; the input parameters - `DefCode`, `DefData`, `DefStack`, `VendMode` and `FeatMode` must all be filled in the `Context` structure before calling this function. The Context structure should also be initialized using `NdInitContext` before the first decode call.
@ -277,10 +275,10 @@ Working with the extended API is also trivial:
INSTRUX ix;
ND_CONTEXT ctx;
uint8_t code[] = { 0x48, 0x8B, 0x48, 0x28 };
// This has to be done only once.
NdInitContext(&ctx);
ctx.DefCode = ND_CODE_64;
ctx.DefData = ND_DATA_64;
ctx.DefStack = ND_STACK_64;

@ -15,7 +15,11 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bdshemu", "bdshemu\bdshemu.
{3653AA19-048B-410E-B5C4-FF78E1D84C12} = {3653AA19-048B-410E-B5C4-FF78E1D84C12}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "isagenerator", "isagenerator\isagenerator.vcxproj", "{0E9D2957-34FA-40EE-B4B2-0D008D2FE317}"
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "isagenerator_x86", "isagenerator\isagenerator.vcxproj", "{0E9D2957-34FA-40EE-B4B2-0D008D2FE317}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "core", "core", "{3114F0D4-BEBA-4574-A349-D03477C64C60}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tools", "tools", "{1F8BBB39-7787-4A50-8170-27EB5FA104D0}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@ -85,6 +89,12 @@ Global
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{94F1B65D-3305-4CCB-9DF1-50B56900D867} = {1F8BBB39-7787-4A50-8170-27EB5FA104D0}
{3653AA19-048B-410E-B5C4-FF78E1D84C12} = {3114F0D4-BEBA-4574-A349-D03477C64C60}
{3C9B2CA7-CF4F-471B-BB72-6490C476CDCA} = {3114F0D4-BEBA-4574-A349-D03477C64C60}
{0E9D2957-34FA-40EE-B4B2-0D008D2FE317} = {3114F0D4-BEBA-4574-A349-D03477C64C60}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {E950FA16-07C1-4613-8328-906BC10C7C02}
EndGlobalSection

@ -1,6 +1,6 @@
.PHONY: clean
SRC_FILES := crt.c bddisasm.c bdformat.c bdhelpers.c
SRC_FILES := bddisasm_crt.c bdx86_decoder.c bdx86_formatter.c bdx86_helpers.c
OBJECTS := $(SRC_FILES:.c=.o)

@ -115,7 +115,8 @@
<PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
<WholeProgramOptimization>true</WholeProgramOptimization>
<TargetVersion></TargetVersion>
<TargetVersion>
</TargetVersion>
<DriverTargetPlatform>Desktop</DriverTargetPlatform>
<SupportsPackaging>false</SupportsPackaging>
<ALLOW_DATE_TIME>1</ALLOW_DATE_TIME>
@ -143,7 +144,8 @@
<ConfigurationType>StaticLibrary</ConfigurationType>
<PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
<TargetVersion></TargetVersion>
<TargetVersion>
</TargetVersion>
<DriverTargetPlatform>Desktop</DriverTargetPlatform>
<SupportsPackaging>false</SupportsPackaging>
<ALLOW_DATE_TIME>1</ALLOW_DATE_TIME>
@ -643,10 +645,10 @@
</Lib>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="bdformat.c" />
<ClCompile Include="bdhelpers.c" />
<ClCompile Include="crt.c" />
<ClCompile Include="bddisasm.c">
<ClCompile Include="bdx86_formatter.c" />
<ClCompile Include="bdx86_helpers.c" />
<ClCompile Include="bddisasm_crt.c" />
<ClCompile Include="bdx86_decoder.c">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='ReleaseKernel|Win32'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='ReleaseKernel|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='ReleaseKernel|ARM64'">NotUsing</PrecompiledHeader>
@ -665,22 +667,23 @@
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\inc\constants.h" />
<ClInclude Include="..\inc\cpuidflags.h" />
<ClInclude Include="..\inc\bdx86_core.h" />
<ClInclude Include="..\inc\bdx86_constants.h" />
<ClInclude Include="..\inc\bdx86_cpuidflags.h" />
<ClInclude Include="..\inc\bddisasm.h" />
<ClInclude Include="..\inc\disasmstatus.h" />
<ClInclude Include="..\inc\disasmtypes.h" />
<ClInclude Include="..\inc\registers.h" />
<ClInclude Include="..\inc\version.h" />
<ClInclude Include="include\instructions.h" />
<ClInclude Include="include\mnemonics.h" />
<ClInclude Include="include\nd_crt.h" />
<ClInclude Include="include\prefixes.h" />
<ClInclude Include="include\tabledefs.h" />
<ClInclude Include="include\table_evex.h" />
<ClInclude Include="include\table_root.h" />
<ClInclude Include="include\table_vex.h" />
<ClInclude Include="include\table_xop.h" />
<ClInclude Include="..\inc\bddisasm_status.h" />
<ClInclude Include="..\inc\bddisasm_types.h" />
<ClInclude Include="..\inc\bdx86_registers.h" />
<ClInclude Include="..\inc\bddisasm_version.h" />
<ClInclude Include="include\bdx86_instructions.h" />
<ClInclude Include="include\bdx86_mnemonics.h" />
<ClInclude Include="include\bddisasm_crt.h" />
<ClInclude Include="include\bdx86_prefixes.h" />
<ClInclude Include="include\bdx86_tabledefs.h" />
<ClInclude Include="include\bdx86_table_evex.h" />
<ClInclude Include="include\bdx86_table_root.h" />
<ClInclude Include="include\bdx86_table_vex.h" />
<ClInclude Include="include\bdx86_table_xop.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">

@ -19,69 +19,87 @@
<Filter Include="Other">
<UniqueIdentifier>{5e26c505-e8f5-4e6c-9d54-f20e36b637b8}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\x86">
<UniqueIdentifier>{39065bbd-3fd0-42b0-ba8e-d7395674b7ce}</UniqueIdentifier>
</Filter>
<Filter Include="Header Files\public\x86">
<UniqueIdentifier>{032f0e51-6265-4031-b702-5eb620d95964}</UniqueIdentifier>
</Filter>
<Filter Include="Header Files\private">
<UniqueIdentifier>{5eb8f135-5960-4e0e-a5a8-5214a7a9edcb}</UniqueIdentifier>
</Filter>
<Filter Include="Header Files\private\x86">
<UniqueIdentifier>{db15a655-cc99-4e12-a8c3-55a485ee713c}</UniqueIdentifier>
</Filter>
<Filter Include="Header Files\private\x86\tables">
<UniqueIdentifier>{b9961460-d06f-4288-9708-44ca965c4a0d}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="crt.c">
<ClCompile Include="bddisasm_crt.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="bddisasm.c">
<Filter>Source Files</Filter>
<ClCompile Include="bdx86_decoder.c">
<Filter>Source Files\x86</Filter>
</ClCompile>
<ClCompile Include="bdformat.c">
<Filter>Source Files</Filter>
<ClCompile Include="bdx86_formatter.c">
<Filter>Source Files\x86</Filter>
</ClCompile>
<ClCompile Include="bdhelpers.c">
<Filter>Source Files</Filter>
<ClCompile Include="bdx86_helpers.c">
<Filter>Source Files\x86</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="include\instructions.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\mnemonics.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\prefixes.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\table_evex.h">
<Filter>Header Files</Filter>
<ClInclude Include="..\inc\bddisasm_version.h">
<Filter>Header Files\public</Filter>
</ClInclude>
<ClInclude Include="include\table_root.h">
<Filter>Header Files</Filter>
<ClInclude Include="..\inc\bdx86_constants.h">
<Filter>Header Files\public\x86</Filter>
</ClInclude>
<ClInclude Include="include\table_vex.h">
<Filter>Header Files</Filter>
<ClInclude Include="..\inc\bdx86_cpuidflags.h">
<Filter>Header Files\public\x86</Filter>
</ClInclude>
<ClInclude Include="include\table_xop.h">
<Filter>Header Files</Filter>
<ClInclude Include="..\inc\bddisasm_types.h">
<Filter>Header Files\public</Filter>
</ClInclude>
<ClInclude Include="include\tabledefs.h">
<Filter>Header Files</Filter>
<ClInclude Include="..\inc\bdx86_registers.h">
<Filter>Header Files\public\x86</Filter>
</ClInclude>
<ClInclude Include="..\inc\constants.h">
<ClInclude Include="..\inc\bddisasm_status.h">
<Filter>Header Files\public</Filter>
</ClInclude>
<ClInclude Include="..\inc\bddisasm.h">
<Filter>Header Files\public</Filter>
</ClInclude>
<ClInclude Include="..\inc\disasmstatus.h">
<Filter>Header Files\public</Filter>
<ClInclude Include="..\inc\bdx86_core.h">
<Filter>Header Files\public\x86</Filter>
</ClInclude>
<ClInclude Include="..\inc\disasmtypes.h">
<Filter>Header Files\public</Filter>
<ClInclude Include="include\bdx86_instructions.h">
<Filter>Header Files\private\x86</Filter>
</ClInclude>
<ClInclude Include="..\inc\registers.h">
<Filter>Header Files\public</Filter>
<ClInclude Include="include\bdx86_mnemonics.h">
<Filter>Header Files\private\x86</Filter>
</ClInclude>
<ClInclude Include="..\inc\version.h">
<Filter>Header Files\public</Filter>
<ClInclude Include="include\bdx86_prefixes.h">
<Filter>Header Files\private\x86</Filter>
</ClInclude>
<ClInclude Include="..\inc\cpuidflags.h">
<Filter>Header Files\public</Filter>
<ClInclude Include="include\bdx86_tabledefs.h">
<Filter>Header Files\private\x86</Filter>
</ClInclude>
<ClInclude Include="include\bddisasm_crt.h">
<Filter>Header Files\private</Filter>
</ClInclude>
<ClInclude Include="include\bdx86_table_evex.h">
<Filter>Header Files\private\x86\tables</Filter>
</ClInclude>
<ClInclude Include="include\bdx86_table_root.h">
<Filter>Header Files\private\x86\tables</Filter>
</ClInclude>
<ClInclude Include="include\bdx86_table_vex.h">
<Filter>Header Files\private\x86\tables</Filter>
</ClInclude>
<ClInclude Include="include\nd_crt.h">
<Filter>Header Files</Filter>
<ClInclude Include="include\bdx86_table_xop.h">
<Filter>Header Files\private\x86\tables</Filter>
</ClInclude>
</ItemGroup>
</Project>

@ -2,7 +2,7 @@
* Copyright (c) 2020 Bitdefender
* SPDX-License-Identifier: Apache-2.0
*/
#include "include/nd_crt.h"
#include "include/bddisasm_crt.h"
//
// nd_strcat_s

File diff suppressed because it is too large Load Diff

@ -2,7 +2,7 @@
* Copyright (c) 2020 Bitdefender
* SPDX-License-Identifier: Apache-2.0
*/
#include "include/nd_crt.h"
#include "include/bddisasm_crt.h"
#include "../inc/bddisasm.h"
@ -18,24 +18,32 @@ static const char *gReg8Bit64[] =
{
"al", "cl", "dl", "bl", "spl", "bpl", "sil", "dil",
"r8b", "r9b", "r10b", "r11b", "r12b", "r13b", "r14b", "r15b",
"r16b", "r17b", "r18b", "r19b", "r20b", "r21b", "r22b", "r23b",
"r24b", "r25b", "r26b", "r27b", "r28b", "r29b", "r30b", "r31b",
};
static const char *gReg16Bit[] =
{
"ax", "cx", "dx", "bx", "sp", "bp", "si", "di",
"r8w", "r9w", "r10w", "r11w", "r12w", "r13w", "r14w", "r15w",
"r16w", "r17w", "r18w", "r19w", "r20w", "r21w", "r22w", "r23w",
"r24w", "r25w", "r26w", "r27w", "r28w", "r29w", "r30w", "r31w",
};
static const char *gReg32Bit[] =
{
"eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi",
"r8d", "r9d", "r10d", "r11d", "r12d", "r13d", "r14d", "r15d",
"r16d", "r17d", "r18d", "r19d", "r20d", "r21d", "r22d", "r23d",
"r24d", "r25d", "r26d", "r27d", "r28d", "r29d", "r30d", "r31d",
};
static const char *gReg64Bit[] =
{
"rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi",
"r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"
"r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
"r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
"r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
};
static const char *gRegFpu[] =
@ -52,12 +60,16 @@ static const char *gRegControl[] =
{
"cr0", "cr1", "cr2", "cr3", "cr4", "cr5", "cr6", "cr7",
"cr8", "cr9", "cr10", "cr11", "cr12", "cr13", "cr14", "cr15",
"cr16", "cr17", "cr18", "cr19", "cr20", "cr21", "cr22", "cr23",
"cr24", "cr25", "cr26", "cr27", "cr28", "cr29", "cr30", "cr31",
};
static const char *gRegDebug[] =
{
"dr0", "dr1", "dr2", "dr3", "dr4", "dr5", "dr6", "dr7",
"dr8", "dr9", "dr10", "dr11", "dr12", "dr13", "dr14", "dr15",
"dr16", "dr17", "dr18", "dr19", "dr20", "dr21", "dr22", "dr23",
"dr24", "dr25", "dr26", "dr27", "dr28", "dr29", "dr30", "dr31",
};
static const char *gRegTest[] =
@ -110,21 +122,12 @@ static const char *gRegTile[] =
"tmm0", "tmm1", "tmm2", "tmm3", "tmm4", "tmm5", "tmm6", "tmm7",
};
static const char *gConditionCodes[] =
{
"EQ", "LT", "LE", "UNORD", "NEQ", "NLT", "NLE", "ORD",
"EQ_UQ", "NGE", "NGT", "ND_FALSE", "NEQ_OQ", "GE", "GT", "TRUE",
"EQ_OS", "LT_OQ", "LE_OQ", "UNORD_S", "NEQ_US", "NLT_UQ", "NLE_UQ", "ORD_S",
"EQ_US", "NGE_UQ", "NGT_UQ", "FALSE_OS", "NEQ_OS", "GE_OQ", "GT_OQ", "TRUE_US",
};
static const char *gEmbeddedRounding[] =
{
"rn", "rd", "ru", "rz",
};
//
// NdSprintf
//
@ -217,69 +220,61 @@ NdToText(
nd_memzero(temp, sizeof(temp));
// First, store the prefixes.
if (Instrux->Rep != 0)
// Check for REPZ/REPNZ support, and store prefixes.
if (Instrux->IsRepcEnabled)
{
// Check for REPZ/REPNZ support, and store prefixes.
if (ND_REPC_SUPPORT(Instrux))
if (Instrux->Rep == ND_PREFIX_G1_REPE_REPZ)
{
if (Instrux->Rep == ND_PREFIX_G1_REPE_REPZ)
{
res = nd_strcat_s(Buffer, BufferSize, "REPZ ");
RET_EQ(res, ND_NULL, ND_STATUS_BUFFER_OVERFLOW);
}
else if (Instrux->Rep == ND_PREFIX_G1_REPNE_REPNZ)
{
res = nd_strcat_s(Buffer, BufferSize, "REPNZ ");
RET_EQ(res, ND_NULL, ND_STATUS_BUFFER_OVERFLOW);
}
res = nd_strcat_s(Buffer, BufferSize, "REPZ ");
RET_EQ(res, ND_NULL, ND_STATUS_BUFFER_OVERFLOW);
}
// Check for REP support and store prefixes.
if (ND_REP_SUPPORT(Instrux))
else if (Instrux->Rep == ND_PREFIX_G1_REPNE_REPNZ)
{
if (Instrux->Rep == ND_PREFIX_G1_REPE_REPZ)
{
res = nd_strcat_s(Buffer, BufferSize, "REP ");
RET_EQ(res, ND_NULL, ND_STATUS_BUFFER_OVERFLOW);
}
else if (Instrux->Rep == ND_PREFIX_G1_REPNE_REPNZ)
{
res = nd_strcat_s(Buffer, BufferSize, "REPNZ ");
RET_EQ(res, ND_NULL, ND_STATUS_BUFFER_OVERFLOW);
}
res = nd_strcat_s(Buffer, BufferSize, "REPNZ ");
RET_EQ(res, ND_NULL, ND_STATUS_BUFFER_OVERFLOW);
}
}
if (Instrux->IsXreleaseEnabled)
// Check for REP support and store prefixes.
if (Instrux->IsRepEnabled)
{
if (Instrux->Rep == ND_PREFIX_G1_REPE_REPZ)
{
res = nd_strcat_s(Buffer, BufferSize, "XRELEASE ");
res = nd_strcat_s(Buffer, BufferSize, "REP ");
RET_EQ(res, ND_NULL, ND_STATUS_BUFFER_OVERFLOW);
}
else if (Instrux->IsXacquireEnabled)
else if (Instrux->Rep == ND_PREFIX_G1_REPNE_REPNZ)
{
res = nd_strcat_s(Buffer, BufferSize, "XACQUIRE ");
res = nd_strcat_s(Buffer, BufferSize, "REPNZ ");
RET_EQ(res, ND_NULL, ND_STATUS_BUFFER_OVERFLOW);
}
}
if (Instrux->HasLock)
if (Instrux->IsXreleaseEnabled)
{
if (ND_LOCK_SUPPORT(Instrux))
{
res = nd_strcat_s(Buffer, BufferSize, "LOCK ");
RET_EQ(res, ND_NULL, ND_STATUS_BUFFER_OVERFLOW);
}
res = nd_strcat_s(Buffer, BufferSize, "XRELEASE ");
RET_EQ(res, ND_NULL, ND_STATUS_BUFFER_OVERFLOW);
}
else if (Instrux->IsXacquireEnabled)
{
res = nd_strcat_s(Buffer, BufferSize, "XACQUIRE ");
RET_EQ(res, ND_NULL, ND_STATUS_BUFFER_OVERFLOW);
}
if (Instrux->Rep == ND_PREFIX_G1_BND)
if (Instrux->IsLockEnabled)
{
if (ND_BND_SUPPORT(Instrux))
{
res = nd_strcat_s(Buffer, BufferSize, "BND ");
RET_EQ(res, ND_NULL, ND_STATUS_BUFFER_OVERFLOW);
}
res = nd_strcat_s(Buffer, BufferSize, "LOCK ");
RET_EQ(res, ND_NULL, ND_STATUS_BUFFER_OVERFLOW);
}
if (Instrux->IsBndEnabled)
{
res = nd_strcat_s(Buffer, BufferSize, "BND ");
RET_EQ(res, ND_NULL, ND_STATUS_BUFFER_OVERFLOW);
}
if (Instrux->HasSeg && ND_BHINT_SUPPORT(Instrux))
if (Instrux->IsBhintEnabled)
{
switch (Instrux->Seg)
{
@ -303,23 +298,27 @@ NdToText(
}
}
if (Instrux->HasSeg && ND_DNT_SUPPORT(Instrux))
if (Instrux->IsDntEnabled)
{
if (!Instrux->IsCetTracked)
{
res = nd_strcat_s(Buffer, BufferSize, "DNT ");
RET_EQ(res, ND_NULL, ND_STATUS_BUFFER_OVERFLOW);
}
res = nd_strcat_s(Buffer, BufferSize, "DNT ");
RET_EQ(res, ND_NULL, ND_STATUS_BUFFER_OVERFLOW);
}
// Store the mnemonic.
res = nd_strcat_s(Buffer, BufferSize, Instrux->Mnemonic);
RET_EQ(res, ND_NULL, ND_STATUS_BUFFER_OVERFLOW);
// Store condition code, if any.
if (ND_HAS_SSE_CONDITION(Instrux))
// Store NF specifier, if NoFlags presetn.
if (Instrux->HasNf)
{
res = nd_strcat_s(Buffer, BufferSize, gConditionCodes[Instrux->SseCondition]);
res = nd_strcat_s(Buffer, BufferSize, "{NF}");
RET_EQ(res, ND_NULL, ND_STATUS_BUFFER_OVERFLOW);
}
// Store ZU specifier, if ZeroUpper present.
if (Instrux->HasZu)
{
res = nd_strcat_s(Buffer, BufferSize, "{ZU}");
RET_EQ(res, ND_NULL, ND_STATUS_BUFFER_OVERFLOW);
}
@ -406,7 +405,7 @@ NdToText(
{
case ND_SIZE_8BIT:
// 8 bit register.
if ((Instrux->EncMode != ND_ENCM_LEGACY) || Instrux->HasRex)
if ((Instrux->EncMode != ND_ENCM_LEGACY) || Instrux->HasRex || Instrux->HasRex2)
{
res = nd_strcat_s(Buffer, BufferSize, gReg8Bit64[pOp->Info.Register.Reg]);
RET_EQ(res, ND_NULL, ND_STATUS_BUFFER_OVERFLOW);
@ -444,11 +443,6 @@ NdToText(
case ND_REG_SEG:
{
if (pOp->Info.Register.Reg >= ND_MAX_SEG_REGS)
{
return ND_STATUS_INVALID_INSTRUX;
}
res = nd_strcat_s(Buffer, BufferSize, gRegSeg[pOp->Info.Register.Reg]);
RET_EQ(res, ND_NULL, ND_STATUS_BUFFER_OVERFLOW);
}
@ -671,7 +665,7 @@ NdToText(
}
break;
case ND_OP_ADDR:
case ND_OP_ADDR_FAR:
{
switch (Instrux->AddrLength)
{
@ -701,6 +695,36 @@ NdToText(
}
break;
case ND_OP_ADDR_NEAR:
{
status = NdSprintf(temp, sizeof(temp), "0x%016llx", pOp->Info.AddressNear.Target);
if (!ND_SUCCESS(status))
{
return status;
}
res = nd_strcat_s(Buffer, BufferSize, temp);
RET_EQ(res, ND_NULL, ND_STATUS_BUFFER_OVERFLOW);
}
break;
case ND_OP_DFV:
{
status = NdSprintf(temp, sizeof(temp), "%c%c%c%c",
pOp->Info.DefaultFlags.OF ? '1' : '0',
pOp->Info.DefaultFlags.SF ? '1' : '0',
pOp->Info.DefaultFlags.ZF ? '1' : '0',
pOp->Info.DefaultFlags.CF ? '1' : '0');
if (!ND_SUCCESS(status))
{
return status;
}
res = nd_strcat_s(Buffer, BufferSize, temp);
RET_EQ(res, ND_NULL, ND_STATUS_BUFFER_OVERFLOW);
}
break;
case ND_OP_MEM:
{
// Prepend the size. For VSIB addressing, store the VSIB element size, not the total accessed size.
@ -755,11 +779,6 @@ NdToText(
// Perpend the segment, only if it is overridden via a prefix.
if (pOp->Info.Memory.HasSeg && Instrux->HasSeg)
{
if (pOp->Info.Memory.Seg >= ND_MAX_SEG_REGS)
{
return ND_STATUS_INVALID_INSTRUX;
}
if ((ND_CODE_64 != Instrux->DefCode) || (NDR_FS == pOp->Info.Memory.Seg) ||
(NDR_GS == pOp->Info.Memory.Seg))
{
@ -778,16 +797,20 @@ NdToText(
// Base, if any.
if (pOp->Info.Memory.HasBase)
{
if (pOp->Info.Memory.Base >= ND_MAX_GPR_REGS)
{
return ND_STATUS_INVALID_INSTRUX;
}
switch (pOp->Info.Memory.BaseSize)
{
case ND_SIZE_8BIT:
res = nd_strcat_s(Buffer, BufferSize, gReg8Bit[pOp->Info.Memory.Base]);
RET_EQ(res, ND_NULL, ND_STATUS_BUFFER_OVERFLOW);
if ((Instrux->EncMode != ND_ENCM_LEGACY) || Instrux->HasRex || Instrux->HasRex2)
{
res = nd_strcat_s(Buffer, BufferSize, gReg8Bit64[pOp->Info.Memory.Base]);
RET_EQ(res, ND_NULL, ND_STATUS_BUFFER_OVERFLOW);
}
else
{
res = nd_strcat_s(Buffer, BufferSize, gReg8Bit[pOp->Info.Memory.Base]);
RET_EQ(res, ND_NULL, ND_STATUS_BUFFER_OVERFLOW);
}
break;
case ND_SIZE_16BIT:
res = nd_strcat_s(Buffer, BufferSize, gReg16Bit[pOp->Info.Memory.Base]);
@ -823,8 +846,16 @@ NdToText(
switch (pOp->Info.Memory.IndexSize)
{
case ND_SIZE_8BIT:
res = nd_strcat_s(Buffer, BufferSize, gReg8Bit[pOp->Info.Memory.Index]);
RET_EQ(res, ND_NULL, ND_STATUS_BUFFER_OVERFLOW);
if ((Instrux->EncMode != ND_ENCM_LEGACY) || Instrux->HasRex || Instrux->HasRex2)
{
res = nd_strcat_s(Buffer, BufferSize, gReg8Bit64[pOp->Info.Memory.Index]);
RET_EQ(res, ND_NULL, ND_STATUS_BUFFER_OVERFLOW);
}
else
{
res = nd_strcat_s(Buffer, BufferSize, gReg8Bit[pOp->Info.Memory.Index]);
RET_EQ(res, ND_NULL, ND_STATUS_BUFFER_OVERFLOW);
}
break;
case ND_SIZE_16BIT:
res = nd_strcat_s(Buffer, BufferSize, gReg16Bit[pOp->Info.Memory.Index]);
@ -913,7 +944,18 @@ NdToText(
// Now displacement.
if (pOp->Info.Memory.HasBase || pOp->Info.Memory.HasIndex)
{
res = nd_strcat_s(Buffer, BufferSize, Instrux->SignDisp ? "-" : "+");
ND_BOOL sign;
if (ND_GET_SIGN(8, pOp->Info.Memory.Disp))
{
sign = ND_TRUE;
}
else
{
sign = ND_FALSE;
}
res = nd_strcat_s(Buffer, BufferSize, sign ? "-" : "+");
RET_EQ(res, ND_NULL, ND_STATUS_BUFFER_OVERFLOW);
}
@ -951,6 +993,19 @@ NdToText(
// And the ending "]"
res = nd_strcat_s(Buffer, BufferSize, "]");
RET_EQ(res, ND_NULL, ND_STATUS_BUFFER_OVERFLOW);
// Handle memory broadcast.
if (pOp->Info.Memory.HasBroadcast)
{
status = NdSprintf(temp, sizeof(temp), "{1to%d}", pOp->Info.Memory.Broadcast.Count);
if (!ND_SUCCESS(status))
{
return status;
}
res = nd_strcat_s(Buffer, BufferSize, temp);
RET_EQ(res, ND_NULL, ND_STATUS_BUFFER_OVERFLOW);
}
}
break;
@ -958,28 +1013,10 @@ NdToText(
return ND_STATUS_INVALID_INSTRUX;
}
// Handle memory broadcast.
if (pOp->Decorator.HasBroadcast)
{
status = NdSprintf(temp, sizeof(temp), "{1to%d}", pOp->Decorator.Broadcast.Count);
if (!ND_SUCCESS(status))
{
return status;
}
res = nd_strcat_s(Buffer, BufferSize, temp);
RET_EQ(res, ND_NULL, ND_STATUS_BUFFER_OVERFLOW);
}
// Handle masking.
if (pOp->Decorator.HasMask)
{
if (pOp->Decorator.Mask.Msk >= ND_MAX_MSK_REGS)
{
return ND_STATUS_INVALID_INSTRUX;
}
status = NdSprintf(temp, sizeof(temp), "{%s}", gRegMask[pOp->Decorator.Mask.Msk]);
status = NdSprintf(temp, sizeof(temp), "{%s}", gRegMask[pOp->Decorator.Msk]);
if (!ND_SUCCESS(status))
{
return status;
@ -996,30 +1033,30 @@ NdToText(
RET_EQ(res, ND_NULL, ND_STATUS_BUFFER_OVERFLOW);
}
// Append Suppress All Exceptions decorator.
if (pOp->Decorator.HasSae && !pOp->Decorator.HasEr)
// If this is the last reg/mem operand, display {sae} and {er} decorators.
if ((pOp->Type == ND_OP_MEM || pOp->Type == ND_OP_REG) &&
(opIndex + 1 >= Instrux->ExpOperandsCount || Instrux->Operands[opIndex + 1].Type == ND_OP_IMM))
{
// ER implies SAE, so if we have ER, we will list that.
res = nd_strcat_s(Buffer, BufferSize, ", {sae}");
RET_EQ(res, ND_NULL, ND_STATUS_BUFFER_OVERFLOW);
}
// Append Embedded Rounding decorator.
if (pOp->Decorator.HasEr)
{
if (Instrux->RoundingMode >= 4)
// Append Suppress All Exceptions decorator.
if (Instrux->HasSae && !Instrux->HasEr)
{
return ND_STATUS_INVALID_INSTRUX;
// ER implies SAE, so if we have ER, we will list that.
res = nd_strcat_s(Buffer, BufferSize, ", {sae}");
RET_EQ(res, ND_NULL, ND_STATUS_BUFFER_OVERFLOW);
}
status = NdSprintf(temp, sizeof(temp), ", {%s-sae}", gEmbeddedRounding[Instrux->RoundingMode]);
if (!ND_SUCCESS(status))
// Append Embedded Rounding decorator.
if (Instrux->HasEr)
{
return status;
}
status = NdSprintf(temp, sizeof(temp), ", {%s-sae}", gEmbeddedRounding[Instrux->RoundingMode]);
if (!ND_SUCCESS(status))
{
return status;
}
res = nd_strcat_s(Buffer, BufferSize, temp);
RET_EQ(res, ND_NULL, ND_STATUS_BUFFER_OVERFLOW);
res = nd_strcat_s(Buffer, BufferSize, temp);
RET_EQ(res, ND_NULL, ND_STATUS_BUFFER_OVERFLOW);
}
}
}

@ -2,7 +2,7 @@
* Copyright (c) 2020 Bitdefender
* SPDX-License-Identifier: Apache-2.0
*/
#include "include/nd_crt.h"
#include "include/bddisasm_crt.h"
#include "../inc/bddisasm.h"

@ -5,7 +5,7 @@
#ifndef ND_CRT_H
#define ND_CRT_H
#include "../../inc/disasmtypes.h"
#include "../../inc/bddisasm_types.h"
#ifndef UNREFERENCED_PARAMETER
#define UNREFERENCED_PARAMETER(P) ((void)(P))

File diff suppressed because it is too large Load Diff

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020 Bitdefender
* Copyright (c) 2024 Bitdefender
* SPDX-License-Identifier: Apache-2.0
*/
@ -7,39 +7,46 @@
// This file was auto-generated by generate_tables.py. DO NOT MODIFY!
//
#ifndef MNEMONICS_H
#define MNEMONICS_H
#ifndef BDX86_MNEMONICS_H
#define BDX86_MNEMONICS_H
const char *gMnemonics[1751] =
const char *gMnemonics[1786] =
{
"AAA", "AAD", "AADD", "AAM", "AAND", "AAS", "ADC", "ADCX", "ADD",
"ADDPD", "ADDPS", "ADDSD", "ADDSS", "ADDSUBPD", "ADDSUBPS", "ADOX",
"AESDEC", "AESDEC128KL", "AESDEC256KL", "AESDECLAST", "AESDECWIDE128KL",
"AESDECWIDE256KL", "AESENC", "AESENC128KL", "AESENC256KL", "AESENCLAST",
"AESENCWIDE128KL", "AESENCWIDE256KL", "AESIMC", "AESKEYGENASSIST",
"ALTINST", "AND", "ANDN", "ANDNPD", "ANDNPS", "ANDPD", "ANDPS",
"AOR", "ARPL", "AXOR", "BEXTR", "BLCFILL", "BLCI", "BLCIC", "BLCMSK",
"BLCS", "BLENDPD", "BLENDPS", "BLENDVPD", "BLENDVPS", "BLSFILL",
"BLSI", "BLSIC", "BLSMSK", "BLSR", "BNDCL", "BNDCN", "BNDCU",
"BNDLDX", "BNDMK", "BNDMOV", "BNDSTX", "BOUND", "BSF", "BSR",
"BSWAP", "BT", "BTC", "BTR", "BTS", "BZHI", "CALL", "CALLF",
"CBW", "CDQ", "CDQE", "CLAC", "CLC", "CLD", "CLDEMOTE", "CLEVICT0",
"CLEVICT1", "CLFLUSH", "CLFLUSHOPT", "CLGI", "CLI", "CLRSSBSY",
"CLTS", "CLUI", "CLWB", "CLZERO", "CMC", "CMOVBE", "CMOVC", "CMOVL",
"CMOVLE", "CMOVNBE", "CMOVNC", "CMOVNL", "CMOVNLE", "CMOVNO",
"CMOVNP", "CMOVNS", "CMOVNZ", "CMOVO", "CMOVP", "CMOVS", "CMOVZ",
"CMP", "CMPBEXADD", "CMPCXADD", "CMPLEXADD", "CMPLXADD", "CMPNBEXADD",
"AND", "ANDN", "ANDNPD", "ANDNPS", "ANDPD", "ANDPS", "AOR", "ARPL",
"AXOR", "BEXTR", "BLCFILL", "BLCI", "BLCIC", "BLCMSK", "BLCS",
"BLENDPD", "BLENDPS", "BLENDVPD", "BLENDVPS", "BLSFILL", "BLSI",
"BLSIC", "BLSMSK", "BLSR", "BNDCL", "BNDCN", "BNDCU", "BNDLDX",
"BNDMK", "BNDMOV", "BNDSTX", "BOUND", "BSF", "BSR", "BSWAP",
"BT", "BTC", "BTR", "BTS", "BZHI", "CALL", "CALLF", "CBW", "CCMPBE",
"CCMPC", "CCMPF", "CCMPL", "CCMPLE", "CCMPNBE", "CCMPNC", "CCMPNL",
"CCMPNLE", "CCMPNO", "CCMPNS", "CCMPNZ", "CCMPO", "CCMPS", "CCMPT",
"CCMPZ", "CDQ", "CDQE", "CFCMOVBE", "CFCMOVC", "CFCMOVL", "CFCMOVLE",
"CFCMOVNBE", "CFCMOVNC", "CFCMOVNL", "CFCMOVNLE", "CFCMOVNO",
"CFCMOVNP", "CFCMOVNS", "CFCMOVNZ", "CFCMOVO", "CFCMOVP", "CFCMOVS",
"CFCMOVZ", "CLAC", "CLC", "CLD", "CLDEMOTE", "CLEVICT0", "CLEVICT1",
"CLFLUSH", "CLFLUSHOPT", "CLGI", "CLI", "CLRSSBSY", "CLTS", "CLUI",
"CLWB", "CLZERO", "CMC", "CMOVBE", "CMOVC", "CMOVL", "CMOVLE",
"CMOVNBE", "CMOVNC", "CMOVNL", "CMOVNLE", "CMOVNO", "CMOVNP",
"CMOVNS", "CMOVNZ", "CMOVO", "CMOVP", "CMOVS", "CMOVZ", "CMP",
"CMPBEXADD", "CMPCXADD", "CMPLEXADD", "CMPLXADD", "CMPNBEXADD",
"CMPNCXADD", "CMPNLEXADD", "CMPNLXADD", "CMPNOXADD", "CMPNPXADD",
"CMPNSXADD", "CMPNZXADD", "CMPOXADD", "CMPPD", "CMPPS", "CMPPXADD",
"CMPSB", "CMPSD", "CMPSQ", "CMPSS", "CMPSW", "CMPSXADD", "CMPXCHG",
"CMPXCHG16B", "CMPXCHG8B", "CMPZXADD", "COMISD", "COMISS", "CPUID",
"CPU_READ", "CPU_WRITE", "CQO", "CRC32", "CVTDQ2PD", "CVTDQ2PS",
"CVTPD2DQ", "CVTPD2PI", "CVTPD2PS", "CVTPI2PD", "CVTPI2PS", "CVTPS2DQ",
"CVTPS2PD", "CVTPS2PI", "CVTSD2SI", "CVTSD2SS", "CVTSI2SD", "CVTSI2SS",
"CVTSS2SD", "CVTSS2SI", "CVTTPD2DQ", "CVTTPD2PI", "CVTTPS2DQ",
"CVTTPS2PI", "CVTTSD2SI", "CVTTSS2SI", "CWD", "CWDE", "DAA",
"DAS", "DEC", "DELAY", "DIV", "DIVPD", "DIVPS", "DIVSD", "DIVSS",
"DMINT", "DPPD", "DPPS", "EMMS", "ENCLS", "ENCLU", "ENCLV", "ENCODEKEY128",
"CQO", "CRC32", "CTESTBE", "CTESTC", "CTESTF", "CTESTL", "CTESTLE",
"CTESTNBE", "CTESTNC", "CTESTNL", "CTESTNLE", "CTESTNO", "CTESTNS",
"CTESTNZ", "CTESTO", "CTESTS", "CTESTT", "CTESTZ", "CVTDQ2PD",
"CVTDQ2PS", "CVTPD2DQ", "CVTPD2PI", "CVTPD2PS", "CVTPI2PD", "CVTPI2PS",
"CVTPS2DQ", "CVTPS2PD", "CVTPS2PI", "CVTSD2SI", "CVTSD2SS", "CVTSI2SD",
"CVTSI2SS", "CVTSS2SD", "CVTSS2SI", "CVTTPD2DQ", "CVTTPD2PI",
"CVTTPS2DQ", "CVTTPS2PI", "CVTTSD2SI", "CVTTSS2SI", "CWD", "CWDE",
"DAA", "DAS", "DEC", "DELAY", "DIV", "DIVPD", "DIVPS", "DIVSD",
"DIVSS", "DPPD", "DPPS", "EMMS", "ENCLS", "ENCLU", "ENCLV", "ENCODEKEY128",
"ENCODEKEY256", "ENDBR32", "ENDBR64", "ENQCMD", "ENQCMDS", "ENTER",
"ERETS", "ERETU", "EXTRACTPS", "EXTRQ", "F2XM1", "FABS", "FADD",
"FADDP", "FBLD", "FBSTP", "FCHS", "FCMOVB", "FCMOVBE", "FCMOVE",
@ -61,24 +68,24 @@ const char *gMnemonics[1751] =
"INCSSPD", "INCSSPQ", "INSB", "INSD", "INSERTPS", "INSERTQ",
"INSW", "INT", "INT1", "INT3", "INTO", "INVD", "INVEPT", "INVLPG",
"INVLPGA", "INVLPGB", "INVPCID", "INVVPID", "IRETD", "IRETQ",
"IRETW", "JBE", "JC", "JCXZ", "JECXZ", "JL", "JLE", "JMP", "JMPE",
"JMPF", "JNBE", "JNC", "JNL", "JNLE", "JNO", "JNP", "JNS", "JNZ",
"JO", "JP", "JRCXZ", "JS", "JZ", "KADDB", "KADDD", "KADDQ", "KADDW",
"KANDB", "KANDD", "KANDNB", "KANDND", "KANDNQ", "KANDNW", "KANDQ",
"KANDW", "KMERGE2L1H", "KMERGE2L1L", "KMOVB", "KMOVD", "KMOVQ",
"KMOVW", "KNOTB", "KNOTD", "KNOTQ", "KNOTW", "KORB", "KORD",
"KORQ", "KORTESTB", "KORTESTD", "KORTESTQ", "KORTESTW", "KORW",
"KSHIFTLB", "KSHIFTLD", "KSHIFTLQ", "KSHIFTLW", "KSHIFTRB", "KSHIFTRD",
"KSHIFTRQ", "KSHIFTRW", "KTESTB", "KTESTD", "KTESTQ", "KTESTW",
"KUNPCKBW", "KUNPCKDQ", "KUNPCKWD", "KXNORB", "KXNORD", "KXNORQ",
"KXNORW", "KXORB", "KXORD", "KXORQ", "KXORW", "LAHF", "LAR",
"LDDQU", "LDMXCSR", "LDS", "LDTILECFG", "LEA", "LEAVE", "LES",
"LFENCE", "LFS", "LGDT", "LGS", "LIDT", "LKGS", "LLDT", "LLWPCB",
"LMSW", "LOADIWKEY", "LODSB", "LODSD", "LODSQ", "LODSW", "LOOP",
"LOOPNZ", "LOOPZ", "LSL", "LSS", "LTR", "LWPINS", "LWPVAL", "LZCNT",
"MASKMOVDQU", "MASKMOVQ", "MAXPD", "MAXPS", "MAXSD", "MAXSS",
"MCOMMIT", "MFENCE", "MINPD", "MINPS", "MINSD", "MINSS", "MONITOR",
"MONITORX", "MONTMUL", "MOV", "MOVAPD", "MOVAPS", "MOVBE", "MOVD",
"IRETW", "JBE", "JC", "JCXZ", "JECXZ", "JL", "JLE", "JMP", "JMPABS",
"JMPE", "JMPF", "JNBE", "JNC", "JNL", "JNLE", "JNO", "JNP", "JNS",
"JNZ", "JO", "JP", "JRCXZ", "JS", "JZ", "KADDB", "KADDD", "KADDQ",
"KADDW", "KANDB", "KANDD", "KANDNB", "KANDND", "KANDNQ", "KANDNW",
"KANDQ", "KANDW", "KMERGE2L1H", "KMERGE2L1L", "KMOVB", "KMOVD",
"KMOVQ", "KMOVW", "KNOTB", "KNOTD", "KNOTQ", "KNOTW", "KORB",
"KORD", "KORQ", "KORTESTB", "KORTESTD", "KORTESTQ", "KORTESTW",
"KORW", "KSHIFTLB", "KSHIFTLD", "KSHIFTLQ", "KSHIFTLW", "KSHIFTRB",
"KSHIFTRD", "KSHIFTRQ", "KSHIFTRW", "KTESTB", "KTESTD", "KTESTQ",
"KTESTW", "KUNPCKBW", "KUNPCKDQ", "KUNPCKWD", "KXNORB", "KXNORD",
"KXNORQ", "KXNORW", "KXORB", "KXORD", "KXORQ", "KXORW", "LAHF",
"LAR", "LDDQU", "LDMXCSR", "LDS", "LDTILECFG", "LEA", "LEAVE",
"LES", "LFENCE", "LFS", "LGDT", "LGS", "LIDT", "LKGS", "LLDT",
"LLWPCB", "LMSW", "LOADIWKEY", "LODSB", "LODSD", "LODSQ", "LODSW",
"LOOP", "LOOPNZ", "LOOPZ", "LSL", "LSS", "LTR", "LWPINS", "LWPVAL",
"LZCNT", "MASKMOVDQU", "MASKMOVQ", "MAXPD", "MAXPS", "MAXSD",
"MAXSS", "MCOMMIT", "MFENCE", "MINPD", "MINPS", "MINSD", "MINSS",
"MONITOR", "MONITORX", "MOV", "MOVAPD", "MOVAPS", "MOVBE", "MOVD",
"MOVDDUP", "MOVDIR64B", "MOVDIRI", "MOVDQ2Q", "MOVDQA", "MOVDQU",
"MOVHLPS", "MOVHPD", "MOVHPS", "MOVLHPS", "MOVLPD", "MOVLPS",
"MOVMSKPD", "MOVMSKPS", "MOVNTDQ", "MOVNTDQA", "MOVNTI", "MOVNTPD",
@ -104,52 +111,52 @@ const char *gMnemonics[1751] =
"PMINUD", "PMINUW", "PMOVMSKB", "PMOVSXBD", "PMOVSXBQ", "PMOVSXBW",
"PMOVSXDQ", "PMOVSXWD", "PMOVSXWQ", "PMOVZXBD", "PMOVZXBQ", "PMOVZXBW",
"PMOVZXDQ", "PMOVZXWD", "PMOVZXWQ", "PMULDQ", "PMULHRSW", "PMULHRW",
"PMULHUW", "PMULHW", "PMULLD", "PMULLW", "PMULUDQ", "POP", "POPA",
"POPAD", "POPCNT", "POPFD", "POPFQ", "POPFW", "POR", "PREFETCH",
"PREFETCHE", "PREFETCHIT0", "PREFETCHIT1", "PREFETCHM", "PREFETCHNTA",
"PREFETCHT0", "PREFETCHT1", "PREFETCHT2", "PREFETCHW", "PREFETCHWT1",
"PSADBW", "PSHUFB", "PSHUFD", "PSHUFHW", "PSHUFLW", "PSHUFW",
"PSIGNB", "PSIGND", "PSIGNW", "PSLLD", "PSLLDQ", "PSLLQ", "PSLLW",
"PSMASH", "PSRAD", "PSRAW", "PSRLD", "PSRLDQ", "PSRLQ", "PSRLW",
"PSUBB", "PSUBD", "PSUBQ", "PSUBSB", "PSUBSW", "PSUBUSB", "PSUBUSW",
"PSUBW", "PSWAPD", "PTEST", "PTWRITE", "PUNPCKHBW", "PUNPCKHDQ",
"PUNPCKHQDQ", "PUNPCKHWD", "PUNPCKLBW", "PUNPCKLDQ", "PUNPCKLQDQ",
"PUNPCKLWD", "PUSH", "PUSHA", "PUSHAD", "PUSHFD", "PUSHFQ", "PUSHFW",
"PVALIDATE", "PXOR", "RCL", "RCPPS", "RCPSS", "RCR", "RDFSBASE",
"RDGSBASE", "RDMSR", "RDMSRLIST", "RDPID", "RDPKRU", "RDPMC",
"RDPRU", "RDRAND", "RDSEED", "RDSHR", "RDSSPD", "RDSSPQ", "RDTSC",
"RDTSCP", "RETF", "RETN", "RMPADJUST", "RMPQUERY", "RMPUPDATE",
"ROL", "ROR", "RORX", "ROUNDPD", "ROUNDPS", "ROUNDSD", "ROUNDSS",
"RSDC", "RSLDT", "RSM", "RSQRTPS", "RSQRTSS", "RSTORSSP", "RSTS",
"SAHF", "SAL", "SALC", "SAR", "SARX", "SAVEPREVSSP", "SBB", "SCASB",
"SCASD", "SCASQ", "SCASW", "SEAMCALL", "SEAMOPS", "SEAMRET",
"SENDUIPI", "SERIALIZE", "SETBE", "SETC", "SETL", "SETLE", "SETNBE",
"SETNC", "SETNL", "SETNLE", "SETNO", "SETNP", "SETNS", "SETNZ",
"SETO", "SETP", "SETS", "SETSSBSY", "SETZ", "SFENCE", "SGDT",
"SHA1MSG1", "SHA1MSG2", "SHA1NEXTE", "SHA1RNDS4", "SHA256MSG1",
"SHA256MSG2", "SHA256RNDS2", "SHL", "SHLD", "SHLX", "SHR", "SHRD",
"SHRX", "SHUFPD", "SHUFPS", "SIDT", "SKINIT", "SLDT", "SLWPCB",
"SMINT", "SMSW", "SPFLT", "SQRTPD", "SQRTPS", "SQRTSD", "SQRTSS",
"STAC", "STC", "STD", "STGI", "STI", "STMXCSR", "STOSB", "STOSD",
"STOSQ", "STOSW", "STR", "STTILECFG", "STUI", "SUB", "SUBPD",
"SUBPS", "SUBSD", "SUBSS", "SVDC", "SVLDT", "SVTS", "SWAPGS",
"SYSCALL", "SYSENTER", "SYSEXIT", "SYSRET", "T1MSKC", "TCMMIMFP16PS",
"TCMMRLFP16PS", "TDCALL", "TDPBF16PS", "TDPBSSD", "TDPBSUD",
"TDPBUSD", "TDPBUUD", "TDPFP16PS", "TEST", "TESTUI", "TILELOADD",
"TILELOADDT1", "TILERELEASE", "TILESTORED", "TILEZERO", "TLBSYNC",
"TPAUSE", "TZCNT", "TZMSK", "UCOMISD", "UCOMISS", "UD0", "UD1",
"UD2", "UIRET", "UMONITOR", "UMWAIT", "UNPCKHPD", "UNPCKHPS",
"UNPCKLPD", "UNPCKLPS", "V4FMADDPS", "V4FMADDSS", "V4FNMADDPS",
"V4FNMADDSS", "VADDPD", "VADDPH", "VADDPS", "VADDSD", "VADDSH",
"VADDSS", "VADDSUBPD", "VADDSUBPS", "VAESDEC", "VAESDECLAST",
"VAESENC", "VAESENCLAST", "VAESIMC", "VAESKEYGENASSIST", "VALIGND",
"VALIGNQ", "VANDNPD", "VANDNPS", "VANDPD", "VANDPS", "VBCSTNEBF162PS",
"VBCSTNESH2PS", "VBLENDMPD", "VBLENDMPS", "VBLENDPD", "VBLENDPS",
"VBLENDVPD", "VBLENDVPS", "VBROADCASTF128", "VBROADCASTF32X2",
"VBROADCASTF32X4", "VBROADCASTF32X8", "VBROADCASTF64X2", "VBROADCASTF64X4",
"VBROADCASTI128", "VBROADCASTI32X2", "VBROADCASTI32X4", "VBROADCASTI32X8",
"VBROADCASTI64X2", "VBROADCASTI64X4", "VBROADCASTSD", "VBROADCASTSS",
"VCMPPD", "VCMPPH", "VCMPPS", "VCMPSD", "VCMPSH", "VCMPSS", "VCOMISD",
"PMULHUW", "PMULHW", "PMULLD", "PMULLW", "PMULUDQ", "POP", "POP2",
"POP2P", "POPA", "POPAD", "POPCNT", "POPFD", "POPFQ", "POPFW",
"POPP", "POR", "PREFETCH", "PREFETCHE", "PREFETCHIT0", "PREFETCHIT1",
"PREFETCHM", "PREFETCHNTA", "PREFETCHT0", "PREFETCHT1", "PREFETCHT2",
"PREFETCHW", "PREFETCHWT1", "PSADBW", "PSHUFB", "PSHUFD", "PSHUFHW",
"PSHUFLW", "PSHUFW", "PSIGNB", "PSIGND", "PSIGNW", "PSLLD", "PSLLDQ",
"PSLLQ", "PSLLW", "PSMASH", "PSRAD", "PSRAW", "PSRLD", "PSRLDQ",
"PSRLQ", "PSRLW", "PSUBB", "PSUBD", "PSUBQ", "PSUBSB", "PSUBSW",
"PSUBUSB", "PSUBUSW", "PSUBW", "PSWAPD", "PTEST", "PTWRITE",
"PUNPCKHBW", "PUNPCKHDQ", "PUNPCKHQDQ", "PUNPCKHWD", "PUNPCKLBW",
"PUNPCKLDQ", "PUNPCKLQDQ", "PUNPCKLWD", "PUSH", "PUSH2", "PUSH2P",
"PUSHA", "PUSHAD", "PUSHFD", "PUSHFQ", "PUSHFW", "PUSHP", "PVALIDATE",
"PXOR", "RCL", "RCPPS", "RCPSS", "RCR", "RDFSBASE", "RDGSBASE",
"RDMSR", "RDMSRLIST", "RDPID", "RDPKRU", "RDPMC", "RDPRU", "RDRAND",
"RDSEED", "RDSSPD", "RDSSPQ", "RDTSC", "RDTSCP", "RETF", "RETN",
"RMPADJUST", "RMPQUERY", "RMPUPDATE", "ROL", "ROR", "RORX", "ROUNDPD",
"ROUNDPS", "ROUNDSD", "ROUNDSS", "RSM", "RSQRTPS", "RSQRTSS",
"RSTORSSP", "SAHF", "SAL", "SALC", "SAR", "SARX", "SAVEPREVSSP",
"SBB", "SCASB", "SCASD", "SCASQ", "SCASW", "SEAMCALL", "SEAMOPS",
"SEAMRET", "SENDUIPI", "SERIALIZE", "SETBE", "SETC", "SETL",
"SETLE", "SETNBE", "SETNC", "SETNL", "SETNLE", "SETNO", "SETNP",
"SETNS", "SETNZ", "SETO", "SETP", "SETS", "SETSSBSY", "SETZ",
"SFENCE", "SGDT", "SHA1MSG1", "SHA1MSG2", "SHA1NEXTE", "SHA1RNDS4",
"SHA256MSG1", "SHA256MSG2", "SHA256RNDS2", "SHL", "SHLD", "SHLX",
"SHR", "SHRD", "SHRX", "SHUFPD", "SHUFPS", "SIDT", "SKINIT",
"SLDT", "SLWPCB", "SMSW", "SPFLT", "SQRTPD", "SQRTPS", "SQRTSD",
"SQRTSS", "STAC", "STC", "STD", "STGI", "STI", "STMXCSR", "STOSB",
"STOSD", "STOSQ", "STOSW", "STR", "STTILECFG", "STUI", "SUB",
"SUBPD", "SUBPS", "SUBSD", "SUBSS", "SWAPGS", "SYSCALL", "SYSENTER",
"SYSEXIT", "SYSRET", "T1MSKC", "TCMMIMFP16PS", "TCMMRLFP16PS",
"TDCALL", "TDPBF16PS", "TDPBSSD", "TDPBSUD", "TDPBUSD", "TDPBUUD",
"TDPFP16PS", "TEST", "TESTUI", "TILELOADD", "TILELOADDT1", "TILERELEASE",
"TILESTORED", "TILEZERO", "TLBSYNC", "TPAUSE", "TZCNT", "TZMSK",
"UCOMISD", "UCOMISS", "UD0", "UD1", "UD2", "UIRET", "UMONITOR",
"UMWAIT", "UNPCKHPD", "UNPCKHPS", "UNPCKLPD", "UNPCKLPS", "URDMSR",
"UWRMSR", "V4FMADDPS", "V4FMADDSS", "V4FNMADDPS", "V4FNMADDSS",
"VADDPD", "VADDPH", "VADDPS", "VADDSD", "VADDSH", "VADDSS", "VADDSUBPD",
"VADDSUBPS", "VAESDEC", "VAESDECLAST", "VAESENC", "VAESENCLAST",
"VAESIMC", "VAESKEYGENASSIST", "VALIGND", "VALIGNQ", "VANDNPD",
"VANDNPS", "VANDPD", "VANDPS", "VBCSTNEBF162PS", "VBCSTNESH2PS",
"VBLENDMPD", "VBLENDMPS", "VBLENDPD", "VBLENDPS", "VBLENDVPD",
"VBLENDVPS", "VBROADCASTF128", "VBROADCASTF32X2", "VBROADCASTF32X4",
"VBROADCASTF32X8", "VBROADCASTF64X2", "VBROADCASTF64X4", "VBROADCASTI128",
"VBROADCASTI32X2", "VBROADCASTI32X4", "VBROADCASTI32X8", "VBROADCASTI64X2",
"VBROADCASTI64X4", "VBROADCASTSD", "VBROADCASTSS", "VCMPPD",
"VCMPPH", "VCMPPS", "VCMPSD", "VCMPSH", "VCMPSS", "VCOMISD",
"VCOMISH", "VCOMISS", "VCOMPRESSPD", "VCOMPRESSPS", "VCVTDQ2PD",
"VCVTDQ2PH", "VCVTDQ2PS", "VCVTNE2PS2BF16", "VCVTNEEBF162PS",
"VCVTNEEPH2PS", "VCVTNEOBF162PS", "VCVTNEOPH2PS", "VCVTNEPS2BF16",
@ -306,13 +313,11 @@ const char *gMnemonics[1751] =
"VUCOMISH", "VUCOMISS", "VUNPCKHPD", "VUNPCKHPS", "VUNPCKLPD",
"VUNPCKLPS", "VXORPD", "VXORPS", "VZEROALL", "VZEROUPPER", "WAIT",
"WBINVD", "WBNOINVD", "WRFSBASE", "WRGSBASE", "WRMSR", "WRMSRLIST",
"WRMSRNS", "WRPKRU", "WRSHR", "WRSSD", "WRSSQ", "WRUSSD", "WRUSSQ",
"XABORT", "XADD", "XBEGIN", "XCHG", "XCRYPTCBC", "XCRYPTCFB",
"XCRYPTCTR", "XCRYPTECB", "XCRYPTOFB", "XEND", "XGETBV", "XLATB",
"XOR", "XORPD", "XORPS", "XRESLDTRK", "XRSTOR", "XRSTOR64", "XRSTORS",
"XRSTORS64", "XSAVE", "XSAVE64", "XSAVEC", "XSAVEC64", "XSAVEOPT",
"XSAVEOPT64", "XSAVES", "XSAVES64", "XSETBV", "XSHA1", "XSHA256",
"XSTORE", "XSUSLDTRK", "XTEST",
"WRMSRNS", "WRPKRU", "WRSSD", "WRSSQ", "WRUSSD", "WRUSSQ", "XABORT",
"XADD", "XBEGIN", "XCHG", "XEND", "XGETBV", "XLATB", "XOR", "XORPD",
"XORPS", "XRESLDTRK", "XRSTOR", "XRSTOR64", "XRSTORS", "XRSTORS64",
"XSAVE", "XSAVE64", "XSAVEC", "XSAVEC64", "XSAVEOPT", "XSAVEOPT64",
"XSAVES", "XSAVES64", "XSETBV", "XSUSLDTRK", "XTEST",
};

@ -2,8 +2,8 @@
* Copyright (c) 2020 Bitdefender
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef PREFIXES_H
#define PREFIXES_H
#ifndef BDX86_PREFIXES_H
#define BDX86_PREFIXES_H
#define ND_PREF_CODE_NONE 0
#define ND_PREF_CODE_STANDARD 1
@ -26,9 +26,9 @@ static const ND_UINT8 gPrefixesMap[256] =
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // A
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // B
0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // C
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // D
0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // D
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // E
1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // F
};
#endif // PREFIXES_H
#endif // BDX86_PREFIXES_H

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -2,10 +2,10 @@
* Copyright (c) 2020 Bitdefender
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef TABLEDEFS_H
#define TABLEDEFS_H
#ifndef BDX86_TABLEDEFS_H
#define BDX86_TABLEDEFS_H
#include "../inc/disasmtypes.h"
#include "../inc/bddisasm_types.h"
//
// Types of tables.
@ -14,27 +14,29 @@ typedef enum _ND_ILUT_TYPE
{
ND_ILUT_INSTRUCTION = 0,// Table contains one entry that directly points to an instruction.
ND_ILUT_OPCODE, // Table contains 256 entries. Next entry is selected using an opcode.
ND_ILUT_OPCODE_3DNOW, // Table contains 256 entries. Next entry is selected using an opcode, but the
// opcode follows the instruction.
ND_ILUT_MODRM_MOD, // Table contains 2 entries. Next entry is selected using modrm.mod (0 - mem, 1 - reg)
ND_ILUT_OPCODE_LAST, // Table contains 256 entries. Next entry is selected using an opcode, but the
// opcode follows the instruction as the last byte.
ND_ILUT_MODRM_REG, // Table contains 8 entries. Next entry is selected using modrm.reg.
ND_ILUT_MODRM_MOD, // Table contains 2 entries. Next entry is selected using modrm.mod (0 - mem, 1 - reg)
ND_ILUT_MODRM_RM, // Table contains 8 entries. Next entry is selected using modrm.rm.
ND_ILUT_MAN_PREFIX, // Table contains 4 entries. Next entry is 0 (no prefix), 1 (0x66), 2 (0xF3), 3 (0xF2).
ND_ILUT_MODE, // Table contains 4 entries. Next entry is 0 (16 bit mode), 1 (32 bit mode), 2 (64 bit mode).
ND_ILUT_DSIZE, // Table contains 4 entries. Next entry is 0 (16 bit size), 1 (32 bit size), 2 (64 bit size).
// This DOES NOT take into consideration forced/default sizes.
ND_ILUT_ASIZE, // Default addressing mode is used to transition
ND_ILUT_AUXILIARY, // Table contains 8 entries. Next entry is 0 (no prefix), 1 (rex), 2 (rex.w), 3 (64 bit),
// 4 (default op size 16), 5 (default op size 32), 6 (default op size 64),
ND_ILUT_AUXILIARY, // Table contains 10 entries. Next entry is 0 (no prefix), 1 (rex), 2 (rex.w), etc.
ND_ILUT_VENDOR, // Preferred vendor is used to transition. Default is entry 0. Otherwise, preferred
// vendor selects an alternate entry.
ND_ILUT_FEATURE, // Some instructions are mapped onto wide NOP space. They will be decoded only if the
// associated feature is set during decoding.
ND_ILUT_VEX_MMMMM, // Table contains 32 entries. Next entry is vex/xop/evex.mmmmm
ND_ILUT_VEX_PP, // Table contains 4 entries. Next entry is vex/xop/evex.pp
ND_ILUT_VEX_L, // Table contains 4 entries. Next entry is vex/xop.l or evex.l'l
ND_ILUT_VEX_W, // Table contains 2 entries. Next entry is vex/xop/evex.w
ND_ILUT_VEX_WI, // Table contains 2 entries. Next entry is vex/xop/evex.w. If not in 64 bit, next entry is 0.
ND_ILUT_EX_M, // Table contains 32 entries. Next entry is vex/xop/evex.mmmmm
ND_ILUT_EX_PP, // Table contains 4 entries. Next entry is vex/xop/evex.pp
ND_ILUT_EX_L, // Table contains 4 entries. Next entry is vex/xop.l or evex.l'l
ND_ILUT_EX_W, // Table contains 2 entries. Next entry is vex/xop/evex.w
ND_ILUT_EX_WI, // Table contains 2 entries. Next entry is vex/xop/evex.w. If not in 64 bit, next entry is 0.
ND_ILUT_EX_ND, // Table contains 2 entries. Next entry is evex.ND.
ND_ILUT_EX_NF, // Table contains 2 entries. Next entry is evex.NF.
ND_ILUT_EX_SC, // Table contains 16 entries. Next entry is evex.SC.
} ND_ILUT_TYPE;
@ -43,7 +45,7 @@ typedef enum _ND_ILUT_TYPE
#define ND_ILUT_INDEX_MOD_REG 1
// Mandatory prefixes.
#define ND_ILUT_INDEX_MAN_PREF_NONE 0
#define ND_ILUT_INDEX_MAN_PREF_NP 0
#define ND_ILUT_INDEX_MAN_PREF_66 1
#define ND_ILUT_INDEX_MAN_PREF_F3 2
#define ND_ILUT_INDEX_MAN_PREF_F2 3
@ -72,10 +74,12 @@ typedef enum _ND_ILUT_TYPE
#define ND_ILUT_INDEX_AUX_NONE 0
#define ND_ILUT_INDEX_AUX_REXB 1
#define ND_ILUT_INDEX_AUX_REXW 2
#define ND_ILUT_INDEX_AUX_O64 3
#define ND_ILUT_INDEX_AUX_F3 4
#define ND_ILUT_INDEX_AUX_MO64 3
#define ND_ILUT_INDEX_AUX_REPZ 4
#define ND_ILUT_INDEX_AUX_REP 5
#define ND_ILUT_INDEX_AUX_RIPREL 6
#define ND_ILUT_INDEX_AUX_REX2 7
#define ND_ILUT_INDEX_AUX_REX2W 8
// Specific features for instructions that map on the wide NOP space.
#define ND_ILUT_FEATURE_NONE 0
@ -85,9 +89,6 @@ typedef enum _ND_ILUT_TYPE
#define ND_ILUT_FEATURE_PITI 4
typedef struct _ND_TABLE
{
ND_UINT32 Type;
@ -130,11 +131,10 @@ typedef struct _ND_TABLE_MPREFIX
const void *Table[4];
} ND_TABLE_MPREFIX, *PND_TABLE_MPREFIX;
typedef struct _ND_TABLE_AUXILIARY
{
ND_UINT32 Type;
const void *Table[8];
const void *Table[10];
} ND_TABLE_AUXILIARY, *PND_TABLE_AUXILIARY;
typedef struct _ND_TABLE_VENDOR
@ -167,65 +167,66 @@ typedef struct _ND_TABLE_MODE
const void *Table[4];
} ND_TABLE_MODE, *PND_TABLE_MODE;
typedef struct _ND_TABLE_VEX_MMMMM
typedef struct _ND_TABLE_EX_M
{
ND_UINT32 Type;
const void *Table[32];
} ND_TABLE_VEX_MMMMM, *PND_TABLE_VEX_MMMMM;
} ND_TABLE_EX_M, *PND_TABLE_EX_M;
typedef struct _ND_TABLE_VEX_PP
typedef struct _ND_TABLE_EX_PP
{
ND_UINT32 Type;
const void *Table[4];
} ND_TABLE_VEX_PP, *PND_TABLE_VEX_PP;
} ND_TABLE_EX_PP, *PND_TABLE_EX_PP;
typedef struct _ND_TABLE_VEX_L
typedef struct _ND_TABLE_EX_L
{
ND_UINT32 Type;
const void *Table[4];
} ND_TABLE_VEX_L, *PND_TABLE_VEX_L;
} ND_TABLE_EX_L, *PND_TABLE_EX_L;
typedef struct _ND_TABLE_VEX_W
typedef struct _ND_TABLE_EX_W
{
ND_UINT32 Type;
const void *Table[8];
} ND_TABLE_VEX_W, *PND_TABLE_VEX_W;
const void *Table[2];
} ND_TABLE_EX_W, *PND_TABLE_EX_W;
typedef struct _ND_TABLE_EX_ND
{
ND_UINT32 Type;
const void *Table[2];
} ND_TABLE_EX_ND, *PND_TABLE_EX_ND;
typedef struct _ND_TABLE_EX_NF
{
ND_UINT32 Type;
const void *Table[2];
} ND_TABLE_EX_NF, *PND_TABLE_EX_NF;
typedef struct _ND_TABLE_EX_SC
{
ND_UINT32 Type;
const void *Table[16];
} ND_TABLE_EX_SC, *PND_TABLE_EX_SC;
//
// One instruction entry. This structure should be maintained bellow 2 cache lines in size (128 bytes).
// One instruction database entry.
//
#ifdef _MSC_VER
__declspec(align(128))
#pragma warning(push)
#pragma warning(disable: 4214)
#else
__attribute__((aligned(128)))
#endif
typedef struct _ND_INSTRUCTION
typedef struct _ND_IDBE
{
ND_UINT16 Instruction; // Instruction identifier. Check ND_INS_CLASS definitions.
ND_UINT8 Category; // Instruction category. Check ND_INS_TYPE.
ND_UINT8 IsaSet; // Instruction set. Check ND_INS_SET.
ND_UINT16 Mnemonic; // Mnemonic (index inside the global mnemonic table).
ND_UINT16 ValidPrefixes; // Accepted prefixes.
ND_UINT32 ValidModes; // Valid operating modes for the instruction.
ND_UINT8 ValidDecorators;// Accepted decorators (valid for EVEX instructions).
ND_UINT8 OpsCount; // Low 4 bits: explicit operands count; high 4 bits: implicit ops count.
ND_UINT8 TupleType; // EVEX tuple type.
ND_UINT8 ExcType : 5; // SSE/VEX/EVEX/OPMASK/AMX exception type.
ND_UINT8 ExcClass : 3; // Indicates the exception class (SSE/AVX, EVEX, OPMASK or AMX).
ND_UINT8 ExcType; // SSE/VEX/EVEX/OPMASK/AMX/APX exception type.
ND_UINT8 FpuFlags; // FPU status word C0, C1, C2 & C3 access type.
ND_UINT8 Reserved2;
ND_UINT16 Reserved3;
ND_UINT32 Attributes; // Instruction attributes.
ND_UINT64 CpuidFlag; // Required CPUID feature flag.
ND_UINT8 EvexMode; // EVEX prefix extension type.
// Per-flag access. Undefined flags will have their bit set in both the "Set" and "Cleared" mask, since a flag
// cannot be both cleared and set.
@ -234,11 +235,14 @@ typedef struct _ND_INSTRUCTION
ND_UINT32 SetFlags; // Flags that are always set to 1.
ND_UINT32 ClearedFlags; // Flags that are always cleared.
ND_UINT64 Attributes; // Instruction attributes.
ND_UINT64 CpuidFlag; // Required CPUID feature flag.
// List of operands. Up to 10 implicit and explicit operands stored in DB.
ND_UINT64 Operands[10];
} ND_INSTRUCTION, *PND_INSTRUCTION;
#ifdef _MSC_VER
#pragma warning(pop)
#endif
} ND_IDBE, *PND_IDBE;
//
// The following definitions are per-operand specific.
@ -376,7 +380,6 @@ typedef enum _ND_OPERAND_TYPE_SPEC
ND_OPT_I,
ND_OPT_J,
ND_OPT_K,
ND_OPT_L,
ND_OPT_M,
ND_OPT_N,
@ -387,7 +390,6 @@ typedef enum _ND_OPERAND_TYPE_SPEC
ND_OPT_S,
ND_OPT_T,
ND_OPT_U,
ND_OPT_V,
ND_OPT_W,
ND_OPT_X,
@ -404,91 +406,92 @@ typedef enum _ND_OPERAND_TYPE_SPEC
ND_OPT_rT,
ND_OPT_mT,
ND_OPT_vT,
ND_OPT_CONST_1,
ND_OPT_dfv,
ND_OPT_1,
// These are implicit arguments inside instructions.
// Special registers.
ND_OPT_RIP,
ND_OPT_rIP,
ND_OPT_MXCSR,
ND_OPT_PKRU,
ND_OPT_SSP,
ND_OPT_UIF,
// General Purpose REgisters.
ND_OPT_GPR_AH,
ND_OPT_GPR_rAX,
ND_OPT_GPR_rCX,
ND_OPT_GPR_rDX,
ND_OPT_GPR_rBX,
ND_OPT_GPR_rSP,
ND_OPT_GPR_rBP,
ND_OPT_GPR_rSI,
ND_OPT_GPR_rDI,
ND_OPT_GPR_rR8,
ND_OPT_GPR_rR9,
ND_OPT_GPR_rR11,
ND_OPT_AH,
ND_OPT_rAX,
ND_OPT_rCX,
ND_OPT_rDX,
ND_OPT_rBX,
ND_OPT_rSP,
ND_OPT_rBP,
ND_OPT_rSI,
ND_OPT_rDI,
ND_OPT_rR8,
ND_OPT_rR9,
ND_OPT_rR11,
// Segment registers.
ND_OPT_SEG_CS,
ND_OPT_SEG_SS,
ND_OPT_SEG_DS,
ND_OPT_SEG_ES,
ND_OPT_SEG_FS,
ND_OPT_SEG_GS,
ND_OPT_CS,
ND_OPT_SS,
ND_OPT_DS,
ND_OPT_ES,
ND_OPT_FS,
ND_OPT_GS,
// FPU registers.
ND_OPT_FPU_ST0,
ND_OPT_FPU_STX,
ND_OPT_ST0,
ND_OPT_STi,
// SSE registers.
ND_OPT_SSE_XMM0,
ND_OPT_SSE_XMM1,
ND_OPT_SSE_XMM2,
ND_OPT_SSE_XMM3,
ND_OPT_SSE_XMM4,
ND_OPT_SSE_XMM5,
ND_OPT_SSE_XMM6,
ND_OPT_SSE_XMM7,
ND_OPT_XMM0,
ND_OPT_XMM1,
ND_OPT_XMM2,
ND_OPT_XMM3,
ND_OPT_XMM4,
ND_OPT_XMM5,
ND_OPT_XMM6,
ND_OPT_XMM7,
// Implicit memory operands.
ND_OPT_MEM_rAX, // [rAX]
ND_OPT_MEM_rCX, // [rCX]
ND_OPT_MEM_rBX_AL, // [rBX + AL]
ND_OPT_MEM_rDI, // [rDI]
ND_OPT_MEM_SHS, // Shadow stack.
ND_OPT_MEM_SHSP, // Shadow stack pointed by the SSP.
ND_OPT_MEM_SHS0,
ND_OPT_MEM_SMSRT, // Source MSR table, encoded in [RSI].
ND_OPT_MEM_DMSRT, // Destination MSR table, encoded in [RDI].
ND_OPT_pAX, // [rAX]
ND_OPT_pCX, // [rCX]
ND_OPT_pBXAL, // [rBX + AL]
ND_OPT_pDI, // [rDI]
ND_OPT_SHS, // Shadow stack.
ND_OPT_SHSP, // Shadow stack pointed by the SSP.
ND_OPT_SHS0, // Shadow stack pointed by the SSP.
ND_OPT_SMT, // Source MSR table, encoded in [RSI].
ND_OPT_DMT, // Destination MSR table, encoded in [RDI].
// Special immediates.
ND_OPT_Im2z,
ND_OPT_m2zI,
// Misc CR/XCR/MSR/SYS registers.
ND_OPT_CR_0,
ND_OPT_SYS_IDTR,
ND_OPT_SYS_GDTR,
ND_OPT_SYS_LDTR,
ND_OPT_SYS_TR,
ND_OPT_X87_CONTROL,
ND_OPT_X87_TAG,
ND_OPT_X87_STATUS,
ND_OPT_CR0,
ND_OPT_IDTR,
ND_OPT_GDTR,
ND_OPT_LDTR,
ND_OPT_TR,
ND_OPT_X87CONTROL,
ND_OPT_X87TAG,
ND_OPT_X87STATUS,
ND_OPT_MSR,
ND_OPT_XCR,
ND_OPT_MSR_TSC,
ND_OPT_MSR_TSCAUX,
ND_OPT_MSR_SEIP,
ND_OPT_MSR_SESP,
ND_OPT_MSR_SCS,
ND_OPT_MSR_STAR,
ND_OPT_MSR_LSTAR,
ND_OPT_MSR_FMASK,
ND_OPT_MSR_FSBASE,
ND_OPT_MSR_GSBASE,
ND_OPT_MSR_KGSBASE,
ND_OPT_XCR_0,
ND_OPT_REG_BANK,
ND_OPT_TSC,
ND_OPT_TSCAUX,
ND_OPT_SEIP,
ND_OPT_SESP,
ND_OPT_SCS,
ND_OPT_STAR,
ND_OPT_LSTAR,
ND_OPT_FMASK,
ND_OPT_FSBASE,
ND_OPT_GSBASE,
ND_OPT_KGSBASE,
ND_OPT_XCR0,
ND_OPT_BANK,
} ND_OPERAND_TYPE_SPEC;
@ -496,9 +499,9 @@ typedef enum _ND_OPERAND_TYPE_SPEC
//
// Operand flags.
//
#define ND_OPF_DEFAULT 0x01 // The operand is default, no need to show it in disassembly.
#define ND_OPF_SEX_OP1 0x02 // The operand is sign-extended to the first operands' size.
#define ND_OPF_SEX_DWS 0x04 // The operand is sign-extended to the default word size.
#define ND_OPF_OPDEF 0x01 // The operand is default, no need to show it in disassembly.
#define ND_OPF_OPSIGNEXO1 0x02 // The operand is sign-extended to the first operands' size.
#define ND_OPF_OPSIGNEXDW 0x04 // The operand is sign-extended to the default word size.
//
@ -520,7 +523,7 @@ typedef enum _ND_OPERAND_TYPE_SPEC
// Operand decorator flags.
//
#define ND_OPD_MASK 0x01 // Mask accepted.
#define ND_OPD_Z 0x02 // Zeroing accepted.
#define ND_OPD_ZERO 0x02 // Zeroing accepted.
#define ND_OPD_B32 0x04 // 32 bit broadcast supported.
#define ND_OPD_B64 0x08 // 64 bit broadcast supported.
#define ND_OPD_SAE 0x10 // Suppress all exceptions supported.
@ -533,13 +536,13 @@ typedef enum _ND_OPERAND_TYPE_SPEC
//
// Include auto-generated stuff.
//
#include "mnemonics.h"
#include "../../inc/constants.h"
#include "instructions.h"
#include "prefixes.h"
#include "table_root.h"
#include "table_xop.h"
#include "table_vex.h"
#include "table_evex.h"
#endif // TABLEDEFS_H
#include "../../inc/bdx86_constants.h"
#include "bdx86_mnemonics.h"
#include "bdx86_instructions.h"
#include "bdx86_prefixes.h"
#include "bdx86_table_root.h"
#include "bdx86_table_xop.h"
#include "bdx86_table_vex.h"
#include "bdx86_table_evex.h"
#endif // BDX86_TABLEDEFS_H

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -1,7 +1,7 @@
# Disassembler Tests
These tests are used to validate bddisasm. Each test consists of up to three files:
* The binary test file. The name format for this type of file is `name_16|32|64`. No extension must be provided; 16/32/64 indicates disassembly mode
* The binary test file. The name format for this type of file is `name_16|32|64.test`. 16/32/64 indicates disassembly mode
* The output result file. Must be named the same as the binary test file, but with the extension .result
* Optional assembly file, used to generate the binary test file

File diff suppressed because it is too large Load Diff

@ -0,0 +1,224 @@
0000000000000000 626c7808fc1e AADD dword ptr [r22], r27d
DSIZE: 32, ASIZE: 64, VLEN: -
ISA Set: APX_F, Ins cat: RAO-INT, CET tracked: no
CPUID leaf: 0x00000007, sub-leaf: 0x00000001, reg: edx, bit: 21
EVEX Tuple Type: None
Exception class: APX, exception type: APX-EVEX-RAO-INT
Valid modes
R0: yes, R1: yes, R2: yes, R3: yes
Real: no, V8086: no, Prot: yes, Compat: yes, Long: yes
SMM on: yes, SMM off: yes, SGX on: yes, SGX off: yes, TSX on: yes, TSX off: yes
VMXRoot: yes, VMXNonRoot: yes, VMXRoot SEAM: yes, VMXNonRoot SEAM: yes, VMX off: yes
Valid prefixes
REP: no, REPcc: no, LOCK: no
HLE: no, XACQUIRE only: no, XRELEASE only: no
BND: no, BHINT: no, DNT: no
Operand: 0, Acc: RW, Type: Memory, Size: 4, RawSize: 4, Encoding: M,
Segment: 3, Base: 22,
Operand: 1, Acc: R-, Type: Register, Size: 4, RawSize: 4, Encoding: R, RegType: General Purpose, RegSize: 4, RegId: 27, RegCount: 1
0000000000000006 626cf808fc1e AADD qword ptr [r22], r27
DSIZE: 64, ASIZE: 64, VLEN: -
ISA Set: APX_F, Ins cat: RAO-INT, CET tracked: no
CPUID leaf: 0x00000007, sub-leaf: 0x00000001, reg: edx, bit: 21
EVEX Tuple Type: None
Exception class: APX, exception type: APX-EVEX-RAO-INT
Valid modes
R0: yes, R1: yes, R2: yes, R3: yes
Real: no, V8086: no, Prot: yes, Compat: yes, Long: yes
SMM on: yes, SMM off: yes, SGX on: yes, SGX off: yes, TSX on: yes, TSX off: yes
VMXRoot: yes, VMXNonRoot: yes, VMXRoot SEAM: yes, VMXNonRoot SEAM: yes, VMX off: yes
Valid prefixes
REP: no, REPcc: no, LOCK: no
HLE: no, XACQUIRE only: no, XRELEASE only: no
BND: no, BHINT: no, DNT: no
Operand: 0, Acc: RW, Type: Memory, Size: 8, RawSize: 8, Encoding: M,
Segment: 3, Base: 22,
Operand: 1, Acc: R-, Type: Register, Size: 8, RawSize: 8, Encoding: R, RegType: General Purpose, RegSize: 8, RegId: 27, RegCount: 1
000000000000000C 626c7908fc1e AAND dword ptr [r22], r27d
DSIZE: 32, ASIZE: 64, VLEN: -
ISA Set: APX_F, Ins cat: RAO-INT, CET tracked: no
CPUID leaf: 0x00000007, sub-leaf: 0x00000001, reg: edx, bit: 21
EVEX Tuple Type: None
Exception class: APX, exception type: APX-EVEX-RAO-INT
Valid modes
R0: yes, R1: yes, R2: yes, R3: yes
Real: no, V8086: no, Prot: yes, Compat: yes, Long: yes
SMM on: yes, SMM off: yes, SGX on: yes, SGX off: yes, TSX on: yes, TSX off: yes
VMXRoot: yes, VMXNonRoot: yes, VMXRoot SEAM: yes, VMXNonRoot SEAM: yes, VMX off: yes
Valid prefixes
REP: no, REPcc: no, LOCK: no
HLE: no, XACQUIRE only: no, XRELEASE only: no
BND: no, BHINT: no, DNT: no
Operand: 0, Acc: RW, Type: Memory, Size: 4, RawSize: 4, Encoding: M,
Segment: 3, Base: 22,
Operand: 1, Acc: R-, Type: Register, Size: 4, RawSize: 4, Encoding: R, RegType: General Purpose, RegSize: 4, RegId: 27, RegCount: 1
0000000000000012 626cf908fc1e AAND qword ptr [r22], r27
DSIZE: 64, ASIZE: 64, VLEN: -
ISA Set: APX_F, Ins cat: RAO-INT, CET tracked: no
CPUID leaf: 0x00000007, sub-leaf: 0x00000001, reg: edx, bit: 21
EVEX Tuple Type: None
Exception class: APX, exception type: APX-EVEX-RAO-INT
Valid modes
R0: yes, R1: yes, R2: yes, R3: yes
Real: no, V8086: no, Prot: yes, Compat: yes, Long: yes
SMM on: yes, SMM off: yes, SGX on: yes, SGX off: yes, TSX on: yes, TSX off: yes
VMXRoot: yes, VMXNonRoot: yes, VMXRoot SEAM: yes, VMXNonRoot SEAM: yes, VMX off: yes
Valid prefixes
REP: no, REPcc: no, LOCK: no
HLE: no, XACQUIRE only: no, XRELEASE only: no
BND: no, BHINT: no, DNT: no
Operand: 0, Acc: RW, Type: Memory, Size: 8, RawSize: 8, Encoding: M,
Segment: 3, Base: 22,
Operand: 1, Acc: R-, Type: Register, Size: 8, RawSize: 8, Encoding: R, RegType: General Purpose, RegSize: 8, RegId: 27, RegCount: 1
0000000000000018 626c7b08fc1e AOR dword ptr [r22], r27d
DSIZE: 32, ASIZE: 64, VLEN: -
ISA Set: APX_F, Ins cat: RAO-INT, CET tracked: no
CPUID leaf: 0x00000007, sub-leaf: 0x00000001, reg: edx, bit: 21
EVEX Tuple Type: None
Exception class: APX, exception type: APX-EVEX-RAO-INT
Valid modes
R0: yes, R1: yes, R2: yes, R3: yes
Real: no, V8086: no, Prot: yes, Compat: yes, Long: yes
SMM on: yes, SMM off: yes, SGX on: yes, SGX off: yes, TSX on: yes, TSX off: yes
VMXRoot: yes, VMXNonRoot: yes, VMXRoot SEAM: yes, VMXNonRoot SEAM: yes, VMX off: yes
Valid prefixes
REP: no, REPcc: no, LOCK: no
HLE: no, XACQUIRE only: no, XRELEASE only: no
BND: no, BHINT: no, DNT: no
Operand: 0, Acc: RW, Type: Memory, Size: 4, RawSize: 4, Encoding: M,
Segment: 3, Base: 22,
Operand: 1, Acc: R-, Type: Register, Size: 4, RawSize: 4, Encoding: R, RegType: General Purpose, RegSize: 4, RegId: 27, RegCount: 1
000000000000001E 626cfb08fc1e AOR qword ptr [r22], r27
DSIZE: 64, ASIZE: 64, VLEN: -
ISA Set: APX_F, Ins cat: RAO-INT, CET tracked: no
CPUID leaf: 0x00000007, sub-leaf: 0x00000001, reg: edx, bit: 21
EVEX Tuple Type: None
Exception class: APX, exception type: APX-EVEX-RAO-INT
Valid modes
R0: yes, R1: yes, R2: yes, R3: yes
Real: no, V8086: no, Prot: yes, Compat: yes, Long: yes
SMM on: yes, SMM off: yes, SGX on: yes, SGX off: yes, TSX on: yes, TSX off: yes
VMXRoot: yes, VMXNonRoot: yes, VMXRoot SEAM: yes, VMXNonRoot SEAM: yes, VMX off: yes
Valid prefixes
REP: no, REPcc: no, LOCK: no
HLE: no, XACQUIRE only: no, XRELEASE only: no
BND: no, BHINT: no, DNT: no
Operand: 0, Acc: RW, Type: Memory, Size: 8, RawSize: 8, Encoding: M,
Segment: 3, Base: 22,
Operand: 1, Acc: R-, Type: Register, Size: 8, RawSize: 8, Encoding: R, RegType: General Purpose, RegSize: 8, RegId: 27, RegCount: 1
0000000000000024 626c7a08fc1e AXOR dword ptr [r22], r27d
DSIZE: 32, ASIZE: 64, VLEN: -
ISA Set: APX_F, Ins cat: RAO-INT, CET tracked: no
CPUID leaf: 0x00000007, sub-leaf: 0x00000001, reg: edx, bit: 21
EVEX Tuple Type: None
Exception class: APX, exception type: APX-EVEX-RAO-INT
Valid modes
R0: yes, R1: yes, R2: yes, R3: yes
Real: no, V8086: no, Prot: yes, Compat: yes, Long: yes
SMM on: yes, SMM off: yes, SGX on: yes, SGX off: yes, TSX on: yes, TSX off: yes
VMXRoot: yes, VMXNonRoot: yes, VMXRoot SEAM: yes, VMXNonRoot SEAM: yes, VMX off: yes
Valid prefixes
REP: no, REPcc: no, LOCK: no
HLE: no, XACQUIRE only: no, XRELEASE only: no
BND: no, BHINT: no, DNT: no
Operand: 0, Acc: RW, Type: Memory, Size: 4, RawSize: 4, Encoding: M,
Segment: 3, Base: 22,
Operand: 1, Acc: R-, Type: Register, Size: 4, RawSize: 4, Encoding: R, RegType: General Purpose, RegSize: 4, RegId: 27, RegCount: 1
000000000000002A 626cfa08fc1e AXOR qword ptr [r22], r27
DSIZE: 64, ASIZE: 64, VLEN: -
ISA Set: APX_F, Ins cat: RAO-INT, CET tracked: no
CPUID leaf: 0x00000007, sub-leaf: 0x00000001, reg: edx, bit: 21
EVEX Tuple Type: None
Exception class: APX, exception type: APX-EVEX-RAO-INT
Valid modes
R0: yes, R1: yes, R2: yes, R3: yes
Real: no, V8086: no, Prot: yes, Compat: yes, Long: yes
SMM on: yes, SMM off: yes, SGX on: yes, SGX off: yes, TSX on: yes, TSX off: yes
VMXRoot: yes, VMXNonRoot: yes, VMXRoot SEAM: yes, VMXNonRoot SEAM: yes, VMX off: yes
Valid prefixes
REP: no, REPcc: no, LOCK: no
HLE: no, XACQUIRE only: no, XRELEASE only: no
BND: no, BHINT: no, DNT: no
Operand: 0, Acc: RW, Type: Memory, Size: 8, RawSize: 8, Encoding: M,
Segment: 3, Base: 22,
Operand: 1, Acc: R-, Type: Register, Size: 8, RawSize: 8, Encoding: R, RegType: General Purpose, RegSize: 8, RegId: 27, RegCount: 1
0000000000000030 626c7b08f8de URDMSR r22, r27
DSIZE: 32, ASIZE: 64, VLEN: -
ISA Set: APX_F, Ins cat: USER_MSR, CET tracked: no
CPUID leaf: 0x00000007, sub-leaf: 0x00000001, reg: edx, bit: 21
EVEX Tuple Type: None
Exception class: APX, exception type: APX-EVEX-USER-MSR
Valid modes
R0: yes, R1: yes, R2: yes, R3: yes
Real: no, V8086: no, Prot: yes, Compat: yes, Long: yes
SMM on: yes, SMM off: yes, SGX on: yes, SGX off: yes, TSX on: yes, TSX off: yes
VMXRoot: yes, VMXNonRoot: yes, VMXRoot SEAM: yes, VMXNonRoot SEAM: yes, VMX off: yes
Valid prefixes
REP: no, REPcc: no, LOCK: no
HLE: no, XACQUIRE only: no, XRELEASE only: no
BND: no, BHINT: no, DNT: no
Operand: 0, Acc: -W, Type: Register, Size: 8, RawSize: 8, Encoding: M, RegType: General Purpose, RegSize: 8, RegId: 22, RegCount: 1
Operand: 1, Acc: R-, Type: Register, Size: 8, RawSize: 8, Encoding: R, RegType: General Purpose, RegSize: 8, RegId: 27, RegCount: 1
0000000000000036 62ff7b08f8c6bdbdbdbd URDMSR r22, 0xbdbdbdbd
DSIZE: 32, ASIZE: 64, VLEN: -
ISA Set: APX_F, Ins cat: USER_MSR, CET tracked: no
CPUID leaf: 0x00000007, sub-leaf: 0x00000001, reg: edx, bit: 21
EVEX Tuple Type: None
Valid modes
R0: yes, R1: yes, R2: yes, R3: yes
Real: no, V8086: no, Prot: no, Compat: no, Long: yes
SMM on: yes, SMM off: yes, SGX on: yes, SGX off: yes, TSX on: yes, TSX off: yes
VMXRoot: yes, VMXNonRoot: yes, VMXRoot SEAM: yes, VMXNonRoot SEAM: yes, VMX off: yes
Valid prefixes
REP: no, REPcc: no, LOCK: no
HLE: no, XACQUIRE only: no, XRELEASE only: no
BND: no, BHINT: no, DNT: no
Operand: 0, Acc: -W, Type: Register, Size: 8, RawSize: 8, Encoding: M, RegType: General Purpose, RegSize: 8, RegId: 22, RegCount: 1
Operand: 1, Acc: R-, Type: Immediate, Size: 4, RawSize: 4, Encoding: I
Operand: 2, Acc: R-, Type: Register, Size: 8, RawSize: 8, Encoding: E, RegType: Model Specific, RegSize: 8, RegId: 0xffffffff, RegCount: 1
0000000000000040 626c7a08f8de UWRMSR r27, r22
DSIZE: 32, ASIZE: 64, VLEN: -
ISA Set: APX_F, Ins cat: USER_MSR, CET tracked: no
CPUID leaf: 0x00000007, sub-leaf: 0x00000001, reg: edx, bit: 21
EVEX Tuple Type: None
Exception class: APX, exception type: APX-EVEX-USER-MSR
Valid modes
R0: yes, R1: yes, R2: yes, R3: yes
Real: no, V8086: no, Prot: yes, Compat: yes, Long: yes
SMM on: yes, SMM off: yes, SGX on: yes, SGX off: yes, TSX on: yes, TSX off: yes
VMXRoot: yes, VMXNonRoot: yes, VMXRoot SEAM: yes, VMXNonRoot SEAM: yes, VMX off: yes
Valid prefixes
REP: no, REPcc: no, LOCK: no
HLE: no, XACQUIRE only: no, XRELEASE only: no
BND: no, BHINT: no, DNT: no
Operand: 0, Acc: R-, Type: Register, Size: 8, RawSize: 8, Encoding: R, RegType: General Purpose, RegSize: 8, RegId: 27, RegCount: 1
Operand: 1, Acc: R-, Type: Register, Size: 8, RawSize: 8, Encoding: M, RegType: General Purpose, RegSize: 8, RegId: 22, RegCount: 1
0000000000000046 62ff7a08f8c6bdbdbdbd UWRMSR 0xbdbdbdbd, r22
DSIZE: 32, ASIZE: 64, VLEN: -
ISA Set: APX_F, Ins cat: USER_MSR, CET tracked: no
CPUID leaf: 0x00000007, sub-leaf: 0x00000001, reg: edx, bit: 21
EVEX Tuple Type: None
Valid modes
R0: yes, R1: yes, R2: yes, R3: yes
Real: no, V8086: no, Prot: no, Compat: no, Long: yes
SMM on: yes, SMM off: yes, SGX on: yes, SGX off: yes, TSX on: yes, TSX off: yes
VMXRoot: yes, VMXNonRoot: yes, VMXRoot SEAM: yes, VMXNonRoot SEAM: yes, VMX off: yes
Valid prefixes
REP: no, REPcc: no, LOCK: no
HLE: no, XACQUIRE only: no, XRELEASE only: no
BND: no, BHINT: no, DNT: no
Operand: 0, Acc: R-, Type: Immediate, Size: 4, RawSize: 4, Encoding: I
Operand: 1, Acc: R-, Type: Register, Size: 8, RawSize: 8, Encoding: M, RegType: General Purpose, RegSize: 8, RegId: 22, RegCount: 1
Operand: 2, Acc: -W, Type: Register, Size: 8, RawSize: 8, Encoding: E, RegType: Model Specific, RegSize: 8, RegId: 0xffffffff, RegCount: 1

@ -0,0 +1 @@
blxüblřüblyüblůübl{üblűüblzüblúübl{řŢb˙{řĆ˝˝˝˝blzřŢb˙zřĆ˝˝˝˝

@ -0,0 +1,16 @@
bits 64
; NF not supported.
db 0x62, 0x6C, 0x78, 0x0C, 0x10, 0x1E, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
; V' set.
db 0x62, 0x6C, 0x78, 0x00, 0x10, 0x1E, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
; VVVV set.
db 0x62, 0x6C, 0x38, 0x08, 0x10, 0x1E, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
; Reserved bits set.
db 0x62, 0x6C, 0x78, 0x09, 0x10, 0x1E, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
db 0x62, 0x6C, 0x78, 0x88, 0x10, 0x1E, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
; Invalid PUSH2 register (RSP).
db 0x62, 0x6C, 0x58, 0x18, 0xFF, 0xF4, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
; Invalid POP2 registers (same dest register, RAX).
db 0x62, 0x64, 0x78, 0x18, 0x8F, 0xC0, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,

@ -0,0 +1,7 @@
0000000000000000 62 db 0x62 (0x80000002)
0000000000000010 62 db 0x62 (0x80000040)
0000000000000020 62 db 0x62 (0x80000032)
0000000000000030 62 db 0x62 (0x80000045)
0000000000000040 62 db 0x62 (0x80000045)
0000000000000050 62 db 0x62 (0x80000044)
0000000000000060 62 db 0x62 (0x80000044)

@ -0,0 +1,25 @@
bits 64
; REX2 with REX
db 0x48, 0xD5, 0x00, 0x33, 0xC0, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90
; REX with REX2
db 0xD5, 0x00, 0x48, 0x33, 0xC0, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90
; REX2 with EVEX
db 0xD5, 0x00, 0x62, 0x6C, 0x78, 0x08, 0x10, 0x1E, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90
; JMPABS with prefixes
db 0x66, 0xD5, 0x00, 0xA1, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0x90, 0x90, 0x90, 0x90
db 0x67, 0xD5, 0x00, 0xA1, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0x90, 0x90, 0x90, 0x90
db 0xF2, 0xD5, 0x00, 0xA1, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0x90, 0x90, 0x90, 0x90
db 0xF3, 0xD5, 0x00, 0xA1, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0x90, 0x90, 0x90, 0x90
; REX2 with unssuported instruction
db 0xD5, 0x00, 0x70, 0xBD, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90
db 0xD5, 0x80, 0x80, 0xBD, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90
; REX2 inside legacy map 0x38 & 0x3A
db 0xD5, 0x80, 0x38, 0xFC, 0x00, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90
db 0xD5, 0x80, 0x3A, 0xCC, 0x00, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90
; REX2 with extension opcode.
db 0xD5, 0x7F, 0x0F, 0xD1, 0xC0, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90
db 0xD5, 0x7F, 0x0F, 0x38, 0x00, 0xC0, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90
db 0xD5, 0xFF, 0x38, 0x00, 0xC0, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90

@ -0,0 +1,14 @@
0000000000000000 48 db 0x48 (0x80000004)
0000000000000010 d5 db 0xd5 (0x80000009)
0000000000000020 d5 db 0xd5 (0x80000009)
0000000000000030 66 db 0x66 (0x80000002)
0000000000000040 67 db 0x67 (0x80000002)
0000000000000050 f2 db 0xf2 (0x80000002)
0000000000000060 f3 db 0xf3 (0x80000002)
0000000000000070 d5 db 0xd5 (0x80000002)
0000000000000080 d5 db 0xd5 (0x80000002)
0000000000000090 d5 db 0xd5 (0x80000002)
00000000000000A0 d5 db 0xd5 (0x80000002)
00000000000000B0 d5 db 0xd5 (0x80000002)
00000000000000C0 d5 db 0xd5 (0x80000002)
00000000000000D0 d5 db 0xd5 (0x80000002)

@ -0,0 +1,32 @@
bits 64
; REX2 0
db 0xD5, 0x00, 0x33, 0xC0
; REX2.W = 1
db 0xD5, 0x08, 0x33, 0xC0
; REX2.B3 & REX2.B4 set
db 0xD5, 0x19, 0x33, 0xC0
; REX2.R3 & REX2.R4 set
db 0xD5, 0x4C, 0x33, 0xC0
; REX2.X3 & REX2.X4 set, no memory
db 0xD5, 0x2A, 0x33, 0xC0
; REX2.X3 & REX2.X4 set, SIB access
db 0xD5, 0x2A, 0x33, 0x04, 0x33
; JMPABS
db 0xD5, 0x00, 0xA1, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD
; PUSHP/POPP
db 0xD5, 0x08, 0x50
db 0xD5, 0x08, 0x58
db 0xD5, 0x18, 0x50
db 0xD5, 0x18, 0x58
; PUSH/POP
db 0xD5, 0x00, 0x50
db 0xD5, 0x00, 0x58
db 0xD5, 0x10, 0x50
db 0xD5, 0x10, 0x58
; NOP
db 0xD5, 0x00, 0x90
; XCHG r16, rax
db 0xD5, 0x18, 0x90
; RDFSBASE r31
db 0xF3, 0xD5, 0x99, 0xAE, 0xC7

@ -0,0 +1,301 @@
0000000000000000 d50033c0 XOR eax, eax
DSIZE: 32, ASIZE: 64, VLEN: -
ISA Set: I86, Ins cat: LOGIC, CET tracked: no
FLAGS access
CF: 0, PF: m, AF: u, ZF: m, SF: m, OF: 0,
Valid modes
R0: yes, R1: yes, R2: yes, R3: yes
Real: yes, V8086: yes, Prot: yes, Compat: yes, Long: yes
SMM on: yes, SMM off: yes, SGX on: yes, SGX off: yes, TSX on: yes, TSX off: yes
VMXRoot: yes, VMXNonRoot: yes, VMXRoot SEAM: yes, VMXNonRoot SEAM: yes, VMX off: yes
Valid prefixes
REP: no, REPcc: no, LOCK: no
HLE: no, XACQUIRE only: no, XRELEASE only: no
BND: no, BHINT: no, DNT: no
Operand: 0, Acc: RW, Type: Register, Size: 4, RawSize: 4, Encoding: R, RegType: General Purpose, RegSize: 4, RegId: 0, RegCount: 1
Operand: 1, Acc: R-, Type: Register, Size: 4, RawSize: 4, Encoding: M, RegType: General Purpose, RegSize: 4, RegId: 0, RegCount: 1
Operand: 2, Acc: -W, Type: Register, Size: 4, RawSize: 4, Encoding: S, RegType: Flags, RegSize: 4, RegId: 0, RegCount: 1
0000000000000004 d50833c0 XOR rax, rax
DSIZE: 64, ASIZE: 64, VLEN: -
ISA Set: I86, Ins cat: LOGIC, CET tracked: no
FLAGS access
CF: 0, PF: m, AF: u, ZF: m, SF: m, OF: 0,
Valid modes
R0: yes, R1: yes, R2: yes, R3: yes
Real: yes, V8086: yes, Prot: yes, Compat: yes, Long: yes
SMM on: yes, SMM off: yes, SGX on: yes, SGX off: yes, TSX on: yes, TSX off: yes
VMXRoot: yes, VMXNonRoot: yes, VMXRoot SEAM: yes, VMXNonRoot SEAM: yes, VMX off: yes
Valid prefixes
REP: no, REPcc: no, LOCK: no
HLE: no, XACQUIRE only: no, XRELEASE only: no
BND: no, BHINT: no, DNT: no
Operand: 0, Acc: RW, Type: Register, Size: 8, RawSize: 8, Encoding: R, RegType: General Purpose, RegSize: 8, RegId: 0, RegCount: 1
Operand: 1, Acc: R-, Type: Register, Size: 8, RawSize: 8, Encoding: M, RegType: General Purpose, RegSize: 8, RegId: 0, RegCount: 1
Operand: 2, Acc: -W, Type: Register, Size: 8, RawSize: 8, Encoding: S, RegType: Flags, RegSize: 8, RegId: 0, RegCount: 1
0000000000000008 d51933c0 XOR rax, r24
DSIZE: 64, ASIZE: 64, VLEN: -
ISA Set: I86, Ins cat: LOGIC, CET tracked: no
FLAGS access
CF: 0, PF: m, AF: u, ZF: m, SF: m, OF: 0,
Valid modes
R0: yes, R1: yes, R2: yes, R3: yes
Real: yes, V8086: yes, Prot: yes, Compat: yes, Long: yes
SMM on: yes, SMM off: yes, SGX on: yes, SGX off: yes, TSX on: yes, TSX off: yes
VMXRoot: yes, VMXNonRoot: yes, VMXRoot SEAM: yes, VMXNonRoot SEAM: yes, VMX off: yes
Valid prefixes
REP: no, REPcc: no, LOCK: no
HLE: no, XACQUIRE only: no, XRELEASE only: no
BND: no, BHINT: no, DNT: no
Operand: 0, Acc: RW, Type: Register, Size: 8, RawSize: 8, Encoding: R, RegType: General Purpose, RegSize: 8, RegId: 0, RegCount: 1
Operand: 1, Acc: R-, Type: Register, Size: 8, RawSize: 8, Encoding: M, RegType: General Purpose, RegSize: 8, RegId: 24, RegCount: 1
Operand: 2, Acc: -W, Type: Register, Size: 8, RawSize: 8, Encoding: S, RegType: Flags, RegSize: 8, RegId: 0, RegCount: 1
000000000000000C d54c33c0 XOR r24, rax
DSIZE: 64, ASIZE: 64, VLEN: -
ISA Set: I86, Ins cat: LOGIC, CET tracked: no
FLAGS access
CF: 0, PF: m, AF: u, ZF: m, SF: m, OF: 0,
Valid modes
R0: yes, R1: yes, R2: yes, R3: yes
Real: yes, V8086: yes, Prot: yes, Compat: yes, Long: yes
SMM on: yes, SMM off: yes, SGX on: yes, SGX off: yes, TSX on: yes, TSX off: yes
VMXRoot: yes, VMXNonRoot: yes, VMXRoot SEAM: yes, VMXNonRoot SEAM: yes, VMX off: yes
Valid prefixes
REP: no, REPcc: no, LOCK: no
HLE: no, XACQUIRE only: no, XRELEASE only: no
BND: no, BHINT: no, DNT: no
Operand: 0, Acc: RW, Type: Register, Size: 8, RawSize: 8, Encoding: R, RegType: General Purpose, RegSize: 8, RegId: 24, RegCount: 1
Operand: 1, Acc: R-, Type: Register, Size: 8, RawSize: 8, Encoding: M, RegType: General Purpose, RegSize: 8, RegId: 0, RegCount: 1
Operand: 2, Acc: -W, Type: Register, Size: 8, RawSize: 8, Encoding: S, RegType: Flags, RegSize: 8, RegId: 0, RegCount: 1
0000000000000010 d52a33c0 XOR rax, rax
DSIZE: 64, ASIZE: 64, VLEN: -
ISA Set: I86, Ins cat: LOGIC, CET tracked: no
FLAGS access
CF: 0, PF: m, AF: u, ZF: m, SF: m, OF: 0,
Valid modes
R0: yes, R1: yes, R2: yes, R3: yes
Real: yes, V8086: yes, Prot: yes, Compat: yes, Long: yes
SMM on: yes, SMM off: yes, SGX on: yes, SGX off: yes, TSX on: yes, TSX off: yes
VMXRoot: yes, VMXNonRoot: yes, VMXRoot SEAM: yes, VMXNonRoot SEAM: yes, VMX off: yes
Valid prefixes
REP: no, REPcc: no, LOCK: no
HLE: no, XACQUIRE only: no, XRELEASE only: no
BND: no, BHINT: no, DNT: no
Operand: 0, Acc: RW, Type: Register, Size: 8, RawSize: 8, Encoding: R, RegType: General Purpose, RegSize: 8, RegId: 0, RegCount: 1
Operand: 1, Acc: R-, Type: Register, Size: 8, RawSize: 8, Encoding: M, RegType: General Purpose, RegSize: 8, RegId: 0, RegCount: 1
Operand: 2, Acc: -W, Type: Register, Size: 8, RawSize: 8, Encoding: S, RegType: Flags, RegSize: 8, RegId: 0, RegCount: 1
0000000000000014 d52a330433 XOR rax, qword ptr [rbx+r30]
DSIZE: 64, ASIZE: 64, VLEN: -
ISA Set: I86, Ins cat: LOGIC, CET tracked: no
FLAGS access
CF: 0, PF: m, AF: u, ZF: m, SF: m, OF: 0,
Valid modes
R0: yes, R1: yes, R2: yes, R3: yes
Real: yes, V8086: yes, Prot: yes, Compat: yes, Long: yes
SMM on: yes, SMM off: yes, SGX on: yes, SGX off: yes, TSX on: yes, TSX off: yes
VMXRoot: yes, VMXNonRoot: yes, VMXRoot SEAM: yes, VMXNonRoot SEAM: yes, VMX off: yes
Valid prefixes
REP: no, REPcc: no, LOCK: no
HLE: no, XACQUIRE only: no, XRELEASE only: no
BND: no, BHINT: no, DNT: no
Operand: 0, Acc: RW, Type: Register, Size: 8, RawSize: 8, Encoding: R, RegType: General Purpose, RegSize: 8, RegId: 0, RegCount: 1
Operand: 1, Acc: R-, Type: Memory, Size: 8, RawSize: 8, Encoding: M,
Segment: 3, Base: 3, Index: 30 * 1,
Operand: 2, Acc: -W, Type: Register, Size: 8, RawSize: 8, Encoding: S, RegType: Flags, RegSize: 8, RegId: 0, RegCount: 1
0000000000000019 d500a1bdbdbdbdbdbdbdbd JMPABS 0xbdbdbdbdbdbdbdbd
DSIZE: 32, ASIZE: 64, VLEN: -
ISA Set: APX_F, Ins cat: UNCOND_BR, CET tracked: no
CPUID leaf: 0x00000007, sub-leaf: 0x00000001, reg: edx, bit: 21
Valid modes
R0: yes, R1: yes, R2: yes, R3: yes
Real: yes, V8086: yes, Prot: yes, Compat: yes, Long: yes
SMM on: yes, SMM off: yes, SGX on: yes, SGX off: yes, TSX on: yes, TSX off: yes
VMXRoot: yes, VMXNonRoot: yes, VMXRoot SEAM: yes, VMXNonRoot SEAM: yes, VMX off: yes
Valid prefixes
REP: no, REPcc: no, LOCK: no
HLE: no, XACQUIRE only: no, XRELEASE only: no
BND: no, BHINT: no, DNT: no
Operand: 0, Acc: R-, Type: Address, Size: 8, RawSize: 8, Encoding: D
Operand: 1, Acc: -W, Type: Register, Size: 4, RawSize: 4, Encoding: S, RegType: IP, RegSize: 4, RegId: 0, RegCount: 1
0000000000000024 d50850 PUSHP rax
DSIZE: 64, ASIZE: 64, VLEN: -
ISA Set: APX_F, Ins cat: PUSH, CET tracked: no
CPUID leaf: 0x00000007, sub-leaf: 0x00000001, reg: edx, bit: 21
Valid modes
R0: yes, R1: yes, R2: yes, R3: yes
Real: yes, V8086: yes, Prot: yes, Compat: yes, Long: yes
SMM on: yes, SMM off: yes, SGX on: yes, SGX off: yes, TSX on: yes, TSX off: yes
VMXRoot: yes, VMXNonRoot: yes, VMXRoot SEAM: yes, VMXNonRoot SEAM: yes, VMX off: yes
Valid prefixes
REP: no, REPcc: no, LOCK: no
HLE: no, XACQUIRE only: no, XRELEASE only: no
BND: no, BHINT: no, DNT: no
Operand: 0, Acc: R-, Type: Register, Size: 8, RawSize: 8, Encoding: O, RegType: General Purpose, RegSize: 8, RegId: 0, RegCount: 1
Operand: 1, Acc: -W, Type: Memory, Size: 8, RawSize: 8, Encoding: S, Stack: yes,
Segment: 2, Base: 4,
0000000000000027 d50858 POPP rax
DSIZE: 64, ASIZE: 64, VLEN: -
ISA Set: APX_F, Ins cat: POP, CET tracked: no
CPUID leaf: 0x00000007, sub-leaf: 0x00000001, reg: edx, bit: 21
Valid modes
R0: yes, R1: yes, R2: yes, R3: yes
Real: yes, V8086: yes, Prot: yes, Compat: yes, Long: yes
SMM on: yes, SMM off: yes, SGX on: yes, SGX off: yes, TSX on: yes, TSX off: yes
VMXRoot: yes, VMXNonRoot: yes, VMXRoot SEAM: yes, VMXNonRoot SEAM: yes, VMX off: yes
Valid prefixes
REP: no, REPcc: no, LOCK: no
HLE: no, XACQUIRE only: no, XRELEASE only: no
BND: no, BHINT: no, DNT: no
Operand: 0, Acc: -W, Type: Register, Size: 8, RawSize: 8, Encoding: O, RegType: General Purpose, RegSize: 8, RegId: 0, RegCount: 1
Operand: 1, Acc: R-, Type: Memory, Size: 8, RawSize: 8, Encoding: S, Stack: yes,
Segment: 2, Base: 4,
000000000000002A d51850 PUSHP r16
DSIZE: 64, ASIZE: 64, VLEN: -
ISA Set: APX_F, Ins cat: PUSH, CET tracked: no
CPUID leaf: 0x00000007, sub-leaf: 0x00000001, reg: edx, bit: 21
Valid modes
R0: yes, R1: yes, R2: yes, R3: yes
Real: yes, V8086: yes, Prot: yes, Compat: yes, Long: yes
SMM on: yes, SMM off: yes, SGX on: yes, SGX off: yes, TSX on: yes, TSX off: yes
VMXRoot: yes, VMXNonRoot: yes, VMXRoot SEAM: yes, VMXNonRoot SEAM: yes, VMX off: yes
Valid prefixes
REP: no, REPcc: no, LOCK: no
HLE: no, XACQUIRE only: no, XRELEASE only: no
BND: no, BHINT: no, DNT: no
Operand: 0, Acc: R-, Type: Register, Size: 8, RawSize: 8, Encoding: O, RegType: General Purpose, RegSize: 8, RegId: 16, RegCount: 1
Operand: 1, Acc: -W, Type: Memory, Size: 8, RawSize: 8, Encoding: S, Stack: yes,
Segment: 2, Base: 4,
000000000000002D d51858 POPP r16
DSIZE: 64, ASIZE: 64, VLEN: -
ISA Set: APX_F, Ins cat: POP, CET tracked: no
CPUID leaf: 0x00000007, sub-leaf: 0x00000001, reg: edx, bit: 21
Valid modes
R0: yes, R1: yes, R2: yes, R3: yes
Real: yes, V8086: yes, Prot: yes, Compat: yes, Long: yes
SMM on: yes, SMM off: yes, SGX on: yes, SGX off: yes, TSX on: yes, TSX off: yes
VMXRoot: yes, VMXNonRoot: yes, VMXRoot SEAM: yes, VMXNonRoot SEAM: yes, VMX off: yes
Valid prefixes
REP: no, REPcc: no, LOCK: no
HLE: no, XACQUIRE only: no, XRELEASE only: no
BND: no, BHINT: no, DNT: no
Operand: 0, Acc: -W, Type: Register, Size: 8, RawSize: 8, Encoding: O, RegType: General Purpose, RegSize: 8, RegId: 16, RegCount: 1
Operand: 1, Acc: R-, Type: Memory, Size: 8, RawSize: 8, Encoding: S, Stack: yes,
Segment: 2, Base: 4,
0000000000000030 d50050 PUSH rax
DSIZE: 64, ASIZE: 64, VLEN: -
ISA Set: I86, Ins cat: PUSH, CET tracked: no
Valid modes
R0: yes, R1: yes, R2: yes, R3: yes
Real: yes, V8086: yes, Prot: yes, Compat: yes, Long: yes
SMM on: yes, SMM off: yes, SGX on: yes, SGX off: yes, TSX on: yes, TSX off: yes
VMXRoot: yes, VMXNonRoot: yes, VMXRoot SEAM: yes, VMXNonRoot SEAM: yes, VMX off: yes
Valid prefixes
REP: no, REPcc: no, LOCK: no
HLE: no, XACQUIRE only: no, XRELEASE only: no
BND: no, BHINT: no, DNT: no
Operand: 0, Acc: R-, Type: Register, Size: 8, RawSize: 8, Encoding: O, RegType: General Purpose, RegSize: 8, RegId: 0, RegCount: 1
Operand: 1, Acc: -W, Type: Memory, Size: 8, RawSize: 8, Encoding: S, Stack: yes,
Segment: 2, Base: 4,
0000000000000033 d50058 POP rax
DSIZE: 64, ASIZE: 64, VLEN: -
ISA Set: I86, Ins cat: POP, CET tracked: no
Valid modes
R0: yes, R1: yes, R2: yes, R3: yes
Real: yes, V8086: yes, Prot: yes, Compat: yes, Long: yes
SMM on: yes, SMM off: yes, SGX on: yes, SGX off: yes, TSX on: yes, TSX off: yes
VMXRoot: yes, VMXNonRoot: yes, VMXRoot SEAM: yes, VMXNonRoot SEAM: yes, VMX off: yes
Valid prefixes
REP: no, REPcc: no, LOCK: no
HLE: no, XACQUIRE only: no, XRELEASE only: no
BND: no, BHINT: no, DNT: no
Operand: 0, Acc: -W, Type: Register, Size: 8, RawSize: 8, Encoding: O, RegType: General Purpose, RegSize: 8, RegId: 0, RegCount: 1
Operand: 1, Acc: R-, Type: Memory, Size: 8, RawSize: 8, Encoding: S, Stack: yes,
Segment: 2, Base: 4,
0000000000000036 d51050 PUSH r16
DSIZE: 64, ASIZE: 64, VLEN: -
ISA Set: I86, Ins cat: PUSH, CET tracked: no
Valid modes
R0: yes, R1: yes, R2: yes, R3: yes
Real: yes, V8086: yes, Prot: yes, Compat: yes, Long: yes
SMM on: yes, SMM off: yes, SGX on: yes, SGX off: yes, TSX on: yes, TSX off: yes
VMXRoot: yes, VMXNonRoot: yes, VMXRoot SEAM: yes, VMXNonRoot SEAM: yes, VMX off: yes
Valid prefixes
REP: no, REPcc: no, LOCK: no
HLE: no, XACQUIRE only: no, XRELEASE only: no
BND: no, BHINT: no, DNT: no
Operand: 0, Acc: R-, Type: Register, Size: 8, RawSize: 8, Encoding: O, RegType: General Purpose, RegSize: 8, RegId: 16, RegCount: 1
Operand: 1, Acc: -W, Type: Memory, Size: 8, RawSize: 8, Encoding: S, Stack: yes,
Segment: 2, Base: 4,
0000000000000039 d51058 POP r16
DSIZE: 64, ASIZE: 64, VLEN: -
ISA Set: I86, Ins cat: POP, CET tracked: no
Valid modes
R0: yes, R1: yes, R2: yes, R3: yes
Real: yes, V8086: yes, Prot: yes, Compat: yes, Long: yes
SMM on: yes, SMM off: yes, SGX on: yes, SGX off: yes, TSX on: yes, TSX off: yes
VMXRoot: yes, VMXNonRoot: yes, VMXRoot SEAM: yes, VMXNonRoot SEAM: yes, VMX off: yes
Valid prefixes
REP: no, REPcc: no, LOCK: no
HLE: no, XACQUIRE only: no, XRELEASE only: no
BND: no, BHINT: no, DNT: no
Operand: 0, Acc: -W, Type: Register, Size: 8, RawSize: 8, Encoding: O, RegType: General Purpose, RegSize: 8, RegId: 16, RegCount: 1
Operand: 1, Acc: R-, Type: Memory, Size: 8, RawSize: 8, Encoding: S, Stack: yes,
Segment: 2, Base: 4,
000000000000003C d50090 NOP
DSIZE: 32, ASIZE: 64, VLEN: -
ISA Set: I86, Ins cat: NOP, CET tracked: no
Valid modes
R0: yes, R1: yes, R2: yes, R3: yes
Real: yes, V8086: yes, Prot: yes, Compat: yes, Long: yes
SMM on: yes, SMM off: yes, SGX on: yes, SGX off: yes, TSX on: yes, TSX off: yes
VMXRoot: yes, VMXNonRoot: yes, VMXRoot SEAM: yes, VMXNonRoot SEAM: yes, VMX off: yes
Valid prefixes
REP: no, REPcc: no, LOCK: no
HLE: no, XACQUIRE only: no, XRELEASE only: no
BND: no, BHINT: no, DNT: no
000000000000003F d51890 XCHG r16, rax
DSIZE: 64, ASIZE: 64, VLEN: -
ISA Set: I86, Ins cat: DATAXFER, CET tracked: no
Valid modes
R0: yes, R1: yes, R2: yes, R3: yes
Real: yes, V8086: yes, Prot: yes, Compat: yes, Long: yes
SMM on: yes, SMM off: yes, SGX on: yes, SGX off: yes, TSX on: yes, TSX off: yes
VMXRoot: yes, VMXNonRoot: yes, VMXRoot SEAM: yes, VMXNonRoot SEAM: yes, VMX off: yes
Valid prefixes
REP: no, REPcc: no, LOCK: no
HLE: no, XACQUIRE only: no, XRELEASE only: no
BND: no, BHINT: no, DNT: no
Operand: 0, Acc: RW, Type: Register, Size: 8, RawSize: 8, Encoding: O, RegType: General Purpose, RegSize: 8, RegId: 16, RegCount: 1
Operand: 1, Acc: RW, Type: Register, Size: 8, RawSize: 8, Encoding: S, RegType: General Purpose, RegSize: 8, RegId: 0, RegCount: 1
0000000000000042 f3d599aec7 RDFSBASE r31
DSIZE: 64, ASIZE: 64, VLEN: -
ISA Set: RDWRFSGS, Ins cat: RDWRFSGS, CET tracked: no
CPUID leaf: 0x00000007, sub-leaf: 0x00000000, reg: ebx, bit: 0
Valid modes
R0: yes, R1: yes, R2: yes, R3: yes
Real: no, V8086: no, Prot: no, Compat: no, Long: yes
SMM on: yes, SMM off: yes, SGX on: yes, SGX off: yes, TSX on: yes, TSX off: yes
VMXRoot: yes, VMXNonRoot: yes, VMXRoot SEAM: yes, VMXNonRoot SEAM: yes, VMX off: yes
Valid prefixes
REP: no, REPcc: no, LOCK: no
HLE: no, XACQUIRE only: no, XRELEASE only: no
BND: no, BHINT: no, DNT: no
Operand: 0, Acc: -W, Type: Register, Size: 8, RawSize: 8, Encoding: M, RegType: General Purpose, RegSize: 8, RegId: 31, RegCount: 1
Operand: 1, Acc: R-, Type: Register, Size: 8, RawSize: 8, Encoding: S, RegType: Model Specific, RegSize: 8, RegId: 0xc0000100, RegCount: 1

@ -2,7 +2,7 @@
DSIZE: 32, ASIZE: 64, VLEN: -
ISA Set: CMPCCXADD, Ins cat: CMPCCXADD, CET tracked: no
CPUID leaf: 0x00000007, sub-leaf: 0x00000001, reg: eax, bit: 7
Exception class: EVEX, exception type: E6NF
Exception class: SSE/VEX, exception type: 14
FLAGS access
CF: m, PF: m, AF: m, ZF: m, SF: m, OF: m,
Valid modes
@ -24,7 +24,7 @@
DSIZE: 64, ASIZE: 64, VLEN: -
ISA Set: CMPCCXADD, Ins cat: CMPCCXADD, CET tracked: no
CPUID leaf: 0x00000007, sub-leaf: 0x00000001, reg: eax, bit: 7
Exception class: EVEX, exception type: E6NF
Exception class: SSE/VEX, exception type: 14
FLAGS access
CF: m, PF: m, AF: m, ZF: m, SF: m, OF: m,
Valid modes
@ -46,7 +46,7 @@
DSIZE: 32, ASIZE: 64, VLEN: -
ISA Set: CMPCCXADD, Ins cat: CMPCCXADD, CET tracked: no
CPUID leaf: 0x00000007, sub-leaf: 0x00000001, reg: eax, bit: 7
Exception class: EVEX, exception type: E6NF
Exception class: SSE/VEX, exception type: 14
FLAGS access
CF: m, PF: m, AF: m, ZF: m, SF: m, OF: m,
Valid modes
@ -68,7 +68,7 @@
DSIZE: 64, ASIZE: 64, VLEN: -
ISA Set: CMPCCXADD, Ins cat: CMPCCXADD, CET tracked: no
CPUID leaf: 0x00000007, sub-leaf: 0x00000001, reg: eax, bit: 7
Exception class: EVEX, exception type: E6NF
Exception class: SSE/VEX, exception type: 14
FLAGS access
CF: m, PF: m, AF: m, ZF: m, SF: m, OF: m,
Valid modes
@ -90,7 +90,7 @@
DSIZE: 32, ASIZE: 64, VLEN: -
ISA Set: CMPCCXADD, Ins cat: CMPCCXADD, CET tracked: no
CPUID leaf: 0x00000007, sub-leaf: 0x00000001, reg: eax, bit: 7
Exception class: EVEX, exception type: E6NF
Exception class: SSE/VEX, exception type: 14
FLAGS access
CF: m, PF: m, AF: m, ZF: m, SF: m, OF: m,
Valid modes
@ -112,7 +112,7 @@
DSIZE: 64, ASIZE: 64, VLEN: -
ISA Set: CMPCCXADD, Ins cat: CMPCCXADD, CET tracked: no
CPUID leaf: 0x00000007, sub-leaf: 0x00000001, reg: eax, bit: 7
Exception class: EVEX, exception type: E6NF
Exception class: SSE/VEX, exception type: 14
FLAGS access
CF: m, PF: m, AF: m, ZF: m, SF: m, OF: m,
Valid modes
@ -134,7 +134,7 @@
DSIZE: 32, ASIZE: 64, VLEN: -
ISA Set: CMPCCXADD, Ins cat: CMPCCXADD, CET tracked: no
CPUID leaf: 0x00000007, sub-leaf: 0x00000001, reg: eax, bit: 7
Exception class: EVEX, exception type: E6NF
Exception class: SSE/VEX, exception type: 14
FLAGS access
CF: m, PF: m, AF: m, ZF: m, SF: m, OF: m,
Valid modes
@ -156,7 +156,7 @@
DSIZE: 64, ASIZE: 64, VLEN: -
ISA Set: CMPCCXADD, Ins cat: CMPCCXADD, CET tracked: no
CPUID leaf: 0x00000007, sub-leaf: 0x00000001, reg: eax, bit: 7
Exception class: EVEX, exception type: E6NF
Exception class: SSE/VEX, exception type: 14
FLAGS access
CF: m, PF: m, AF: m, ZF: m, SF: m, OF: m,
Valid modes
@ -178,7 +178,7 @@
DSIZE: 32, ASIZE: 64, VLEN: -
ISA Set: CMPCCXADD, Ins cat: CMPCCXADD, CET tracked: no
CPUID leaf: 0x00000007, sub-leaf: 0x00000001, reg: eax, bit: 7
Exception class: EVEX, exception type: E6NF
Exception class: SSE/VEX, exception type: 14
FLAGS access
CF: m, PF: m, AF: m, ZF: m, SF: m, OF: m,
Valid modes
@ -200,7 +200,7 @@
DSIZE: 64, ASIZE: 64, VLEN: -
ISA Set: CMPCCXADD, Ins cat: CMPCCXADD, CET tracked: no
CPUID leaf: 0x00000007, sub-leaf: 0x00000001, reg: eax, bit: 7
Exception class: EVEX, exception type: E6NF
Exception class: SSE/VEX, exception type: 14
FLAGS access
CF: m, PF: m, AF: m, ZF: m, SF: m, OF: m,
Valid modes
@ -222,7 +222,7 @@
DSIZE: 32, ASIZE: 64, VLEN: -
ISA Set: CMPCCXADD, Ins cat: CMPCCXADD, CET tracked: no
CPUID leaf: 0x00000007, sub-leaf: 0x00000001, reg: eax, bit: 7
Exception class: EVEX, exception type: E6NF
Exception class: SSE/VEX, exception type: 14
FLAGS access
CF: m, PF: m, AF: m, ZF: m, SF: m, OF: m,
Valid modes
@ -244,7 +244,7 @@
DSIZE: 64, ASIZE: 64, VLEN: -
ISA Set: CMPCCXADD, Ins cat: CMPCCXADD, CET tracked: no
CPUID leaf: 0x00000007, sub-leaf: 0x00000001, reg: eax, bit: 7
Exception class: EVEX, exception type: E6NF
Exception class: SSE/VEX, exception type: 14
FLAGS access
CF: m, PF: m, AF: m, ZF: m, SF: m, OF: m,
Valid modes
@ -266,7 +266,7 @@
DSIZE: 32, ASIZE: 64, VLEN: -
ISA Set: CMPCCXADD, Ins cat: CMPCCXADD, CET tracked: no
CPUID leaf: 0x00000007, sub-leaf: 0x00000001, reg: eax, bit: 7
Exception class: EVEX, exception type: E6NF
Exception class: SSE/VEX, exception type: 14
FLAGS access
CF: m, PF: m, AF: m, ZF: m, SF: m, OF: m,
Valid modes
@ -288,7 +288,7 @@
DSIZE: 64, ASIZE: 64, VLEN: -
ISA Set: CMPCCXADD, Ins cat: CMPCCXADD, CET tracked: no
CPUID leaf: 0x00000007, sub-leaf: 0x00000001, reg: eax, bit: 7
Exception class: EVEX, exception type: E6NF
Exception class: SSE/VEX, exception type: 14
FLAGS access
CF: m, PF: m, AF: m, ZF: m, SF: m, OF: m,
Valid modes
@ -310,7 +310,7 @@
DSIZE: 32, ASIZE: 64, VLEN: -
ISA Set: CMPCCXADD, Ins cat: CMPCCXADD, CET tracked: no
CPUID leaf: 0x00000007, sub-leaf: 0x00000001, reg: eax, bit: 7
Exception class: EVEX, exception type: E6NF
Exception class: SSE/VEX, exception type: 14
FLAGS access
CF: m, PF: m, AF: m, ZF: m, SF: m, OF: m,
Valid modes
@ -332,7 +332,7 @@
DSIZE: 64, ASIZE: 64, VLEN: -
ISA Set: CMPCCXADD, Ins cat: CMPCCXADD, CET tracked: no
CPUID leaf: 0x00000007, sub-leaf: 0x00000001, reg: eax, bit: 7
Exception class: EVEX, exception type: E6NF
Exception class: SSE/VEX, exception type: 14
FLAGS access
CF: m, PF: m, AF: m, ZF: m, SF: m, OF: m,
Valid modes
@ -354,7 +354,7 @@
DSIZE: 32, ASIZE: 64, VLEN: -
ISA Set: CMPCCXADD, Ins cat: CMPCCXADD, CET tracked: no
CPUID leaf: 0x00000007, sub-leaf: 0x00000001, reg: eax, bit: 7
Exception class: EVEX, exception type: E6NF
Exception class: SSE/VEX, exception type: 14
FLAGS access
CF: m, PF: m, AF: m, ZF: m, SF: m, OF: m,
Valid modes
@ -376,7 +376,7 @@
DSIZE: 64, ASIZE: 64, VLEN: -
ISA Set: CMPCCXADD, Ins cat: CMPCCXADD, CET tracked: no
CPUID leaf: 0x00000007, sub-leaf: 0x00000001, reg: eax, bit: 7
Exception class: EVEX, exception type: E6NF
Exception class: SSE/VEX, exception type: 14
FLAGS access
CF: m, PF: m, AF: m, ZF: m, SF: m, OF: m,
Valid modes
@ -398,7 +398,7 @@
DSIZE: 32, ASIZE: 64, VLEN: -
ISA Set: CMPCCXADD, Ins cat: CMPCCXADD, CET tracked: no
CPUID leaf: 0x00000007, sub-leaf: 0x00000001, reg: eax, bit: 7
Exception class: EVEX, exception type: E6NF
Exception class: SSE/VEX, exception type: 14
FLAGS access
CF: m, PF: m, AF: m, ZF: m, SF: m, OF: m,
Valid modes
@ -420,7 +420,7 @@
DSIZE: 64, ASIZE: 64, VLEN: -
ISA Set: CMPCCXADD, Ins cat: CMPCCXADD, CET tracked: no
CPUID leaf: 0x00000007, sub-leaf: 0x00000001, reg: eax, bit: 7
Exception class: EVEX, exception type: E6NF
Exception class: SSE/VEX, exception type: 14
FLAGS access
CF: m, PF: m, AF: m, ZF: m, SF: m, OF: m,
Valid modes
@ -442,7 +442,7 @@
DSIZE: 32, ASIZE: 64, VLEN: -
ISA Set: CMPCCXADD, Ins cat: CMPCCXADD, CET tracked: no
CPUID leaf: 0x00000007, sub-leaf: 0x00000001, reg: eax, bit: 7
Exception class: EVEX, exception type: E6NF
Exception class: SSE/VEX, exception type: 14
FLAGS access
CF: m, PF: m, AF: m, ZF: m, SF: m, OF: m,
Valid modes
@ -464,7 +464,7 @@
DSIZE: 64, ASIZE: 64, VLEN: -
ISA Set: CMPCCXADD, Ins cat: CMPCCXADD, CET tracked: no
CPUID leaf: 0x00000007, sub-leaf: 0x00000001, reg: eax, bit: 7
Exception class: EVEX, exception type: E6NF
Exception class: SSE/VEX, exception type: 14
FLAGS access
CF: m, PF: m, AF: m, ZF: m, SF: m, OF: m,
Valid modes
@ -486,7 +486,7 @@
DSIZE: 32, ASIZE: 64, VLEN: -
ISA Set: CMPCCXADD, Ins cat: CMPCCXADD, CET tracked: no
CPUID leaf: 0x00000007, sub-leaf: 0x00000001, reg: eax, bit: 7
Exception class: EVEX, exception type: E6NF
Exception class: SSE/VEX, exception type: 14
FLAGS access
CF: m, PF: m, AF: m, ZF: m, SF: m, OF: m,
Valid modes
@ -508,7 +508,7 @@
DSIZE: 64, ASIZE: 64, VLEN: -
ISA Set: CMPCCXADD, Ins cat: CMPCCXADD, CET tracked: no
CPUID leaf: 0x00000007, sub-leaf: 0x00000001, reg: eax, bit: 7
Exception class: EVEX, exception type: E6NF
Exception class: SSE/VEX, exception type: 14
FLAGS access
CF: m, PF: m, AF: m, ZF: m, SF: m, OF: m,
Valid modes
@ -530,7 +530,7 @@
DSIZE: 32, ASIZE: 64, VLEN: -
ISA Set: CMPCCXADD, Ins cat: CMPCCXADD, CET tracked: no
CPUID leaf: 0x00000007, sub-leaf: 0x00000001, reg: eax, bit: 7
Exception class: EVEX, exception type: E6NF
Exception class: SSE/VEX, exception type: 14
FLAGS access
CF: m, PF: m, AF: m, ZF: m, SF: m, OF: m,
Valid modes
@ -552,7 +552,7 @@
DSIZE: 64, ASIZE: 64, VLEN: -
ISA Set: CMPCCXADD, Ins cat: CMPCCXADD, CET tracked: no
CPUID leaf: 0x00000007, sub-leaf: 0x00000001, reg: eax, bit: 7
Exception class: EVEX, exception type: E6NF
Exception class: SSE/VEX, exception type: 14
FLAGS access
CF: m, PF: m, AF: m, ZF: m, SF: m, OF: m,
Valid modes
@ -574,7 +574,7 @@
DSIZE: 32, ASIZE: 64, VLEN: -
ISA Set: CMPCCXADD, Ins cat: CMPCCXADD, CET tracked: no
CPUID leaf: 0x00000007, sub-leaf: 0x00000001, reg: eax, bit: 7
Exception class: EVEX, exception type: E6NF
Exception class: SSE/VEX, exception type: 14
FLAGS access
CF: m, PF: m, AF: m, ZF: m, SF: m, OF: m,
Valid modes
@ -596,7 +596,7 @@
DSIZE: 64, ASIZE: 64, VLEN: -
ISA Set: CMPCCXADD, Ins cat: CMPCCXADD, CET tracked: no
CPUID leaf: 0x00000007, sub-leaf: 0x00000001, reg: eax, bit: 7
Exception class: EVEX, exception type: E6NF
Exception class: SSE/VEX, exception type: 14
FLAGS access
CF: m, PF: m, AF: m, ZF: m, SF: m, OF: m,
Valid modes
@ -618,7 +618,7 @@
DSIZE: 32, ASIZE: 64, VLEN: -
ISA Set: CMPCCXADD, Ins cat: CMPCCXADD, CET tracked: no
CPUID leaf: 0x00000007, sub-leaf: 0x00000001, reg: eax, bit: 7
Exception class: EVEX, exception type: E6NF
Exception class: SSE/VEX, exception type: 14
FLAGS access
CF: m, PF: m, AF: m, ZF: m, SF: m, OF: m,
Valid modes
@ -640,7 +640,7 @@
DSIZE: 64, ASIZE: 64, VLEN: -
ISA Set: CMPCCXADD, Ins cat: CMPCCXADD, CET tracked: no
CPUID leaf: 0x00000007, sub-leaf: 0x00000001, reg: eax, bit: 7
Exception class: EVEX, exception type: E6NF
Exception class: SSE/VEX, exception type: 14
FLAGS access
CF: m, PF: m, AF: m, ZF: m, SF: m, OF: m,
Valid modes
@ -662,7 +662,7 @@
DSIZE: 32, ASIZE: 64, VLEN: -
ISA Set: CMPCCXADD, Ins cat: CMPCCXADD, CET tracked: no
CPUID leaf: 0x00000007, sub-leaf: 0x00000001, reg: eax, bit: 7
Exception class: EVEX, exception type: E6NF
Exception class: SSE/VEX, exception type: 14
FLAGS access
CF: m, PF: m, AF: m, ZF: m, SF: m, OF: m,
Valid modes
@ -684,7 +684,7 @@
DSIZE: 64, ASIZE: 64, VLEN: -
ISA Set: CMPCCXADD, Ins cat: CMPCCXADD, CET tracked: no
CPUID leaf: 0x00000007, sub-leaf: 0x00000001, reg: eax, bit: 7
Exception class: EVEX, exception type: E6NF
Exception class: SSE/VEX, exception type: 14
FLAGS access
CF: m, PF: m, AF: m, ZF: m, SF: m, OF: m,
Valid modes

@ -13,11 +13,11 @@
REP: no, REPcc: no, LOCK: no
HLE: no, XACQUIRE only: no, XRELEASE only: no
BND: no, BHINT: no, DNT: no
Operand: 0, Acc: -W, Type: Register, Size: 8, RawSize: 8, Encoding: S, RegType: IP, RegSize: 8, RegId: 0, RegCount: 1
Operand: 1, Acc: -W, Type: Register, Size: 8, RawSize: 8, Encoding: S, RegType: Flags, RegSize: 8, RegId: 0, RegCount: 1
Operand: 2, Acc: -W, Type: Register, Size: 8, RawSize: 8, Encoding: S, RegType: General Purpose, RegSize: 8, RegId: 4, RegCount: 1
Operand: 3, Acc: -W, Type: Register, Size: 8, RawSize: 8, Encoding: S, RegType: Segment, RegSize: 8, RegId: 1, RegCount: 1
Operand: 4, Acc: -W, Type: Register, Size: 8, RawSize: 8, Encoding: S, RegType: Segment, RegSize: 8, RegId: 2, RegCount: 1
Operand: 0, Acc: -W, Type: Register, Size: 8, RawSize: 8, Encoding: S, RegType: Segment, RegSize: 8, RegId: 1, RegCount: 1
Operand: 1, Acc: -W, Type: Register, Size: 8, RawSize: 8, Encoding: S, RegType: IP, RegSize: 8, RegId: 0, RegCount: 1
Operand: 2, Acc: -W, Type: Register, Size: 8, RawSize: 8, Encoding: S, RegType: Flags, RegSize: 8, RegId: 0, RegCount: 1
Operand: 3, Acc: -W, Type: Register, Size: 8, RawSize: 8, Encoding: S, RegType: Segment, RegSize: 8, RegId: 2, RegCount: 1
Operand: 4, Acc: -W, Type: Register, Size: 8, RawSize: 8, Encoding: S, RegType: General Purpose, RegSize: 8, RegId: 4, RegCount: 1
Operand: 5, Acc: R-, Type: Memory, Size: 40, RawSize: 40, Encoding: S, Stack: yes,
Segment: 2, Base: 4,
Operand: 6, Acc: CRCW, Type: Register, Size: 8, RawSize: 8, Encoding: S, RegType: SSP, RegSize: 8, RegId: 0, RegCount: 1

@ -24,8 +24,8 @@
db 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90
db 0xD4, 0x90 ; AAM
db 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90
db 0xD5, 0x90 ; AAD
db 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90
;db 0xD5, 0x90 ; AAD
;db 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90
db 0x60 ; PUSHA
db 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90
db 0x61 ; POPA

@ -10,8 +10,7 @@
0000000000000090 37 db 0x37 (0x80000009)
00000000000000A0 3f db 0x3f (0x80000009)
00000000000000B0 d4 db 0xd4 (0x80000009)
00000000000000C0 d5 db 0xd5 (0x80000009)
00000000000000D0 60 db 0x60 (0x80000009)
00000000000000E0 61 db 0x61 (0x80000009)
00000000000000F0 9a db 0x9a (0x80000009)
0000000000000100 ea db 0xea (0x80000009)
00000000000000C0 60 db 0x60 (0x80000009)
00000000000000D0 61 db 0x61 (0x80000009)
00000000000000E0 9a db 0x9a (0x80000009)
00000000000000F0 ea db 0xea (0x80000009)

@ -1 +1 @@
<06><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><07><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><0E><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><16><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><17><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><1E><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><1F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>'<27><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>/<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>7<EFBFBD><37><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>?<3F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ô<EFBFBD><C394><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Õ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>`<60><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>a<EFBFBD><61><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>š<EFBFBD><C5A1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ê<EFBFBD><C3AA><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<06><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><07><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><0E><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><16><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><17><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><1E><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><1F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>'<27><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>/<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>7<EFBFBD><37><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>?<3F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ô<EFBFBD><C394><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>`<60><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>a<EFBFBD><61><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>š<EFBFBD><C5A1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ê<EFBFBD><C3AA><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>

@ -0,0 +1,11 @@
bits 64
; UWRMSR 0x44332211, rax
db 0xC4, 0xE7, 0x7A, 0xF8, 0xC0, 0x11, 0x22, 0x33, 0x44
; URDMSR rax, 0x44332211
db 0xC4, 0xE7, 0x7B, 0xF8, 0xC0, 0x11, 0x22, 0x33, 0x44
; UWRMSR rcx, rax
db 0xF3, 0x0F, 0x38, 0xF8, 0xC1
; URDMSR rax, rcx
db 0xF2, 0x0F, 0x38, 0xF8, 0xC1

@ -0,0 +1,68 @@
0000000000000000 c4e77af8c011223344 UWRMSR 0x44332211, rax
DSIZE: 32, ASIZE: 64, VLEN: -
ISA Set: USER_MSR, Ins cat: USER_MSR, CET tracked: no
CPUID leaf: 0x00000007, sub-leaf: 0x00000001, reg: edx, bit: 15
Valid modes
R0: yes, R1: yes, R2: yes, R3: yes
Real: no, V8086: no, Prot: no, Compat: no, Long: yes
SMM on: yes, SMM off: yes, SGX on: yes, SGX off: yes, TSX on: yes, TSX off: yes
VMXRoot: yes, VMXNonRoot: yes, VMXRoot SEAM: yes, VMXNonRoot SEAM: yes, VMX off: yes
Valid prefixes
REP: no, REPcc: no, LOCK: no
HLE: no, XACQUIRE only: no, XRELEASE only: no
BND: no, BHINT: no, DNT: no
Operand: 0, Acc: R-, Type: Immediate, Size: 4, RawSize: 4, Encoding: I
Operand: 1, Acc: R-, Type: Register, Size: 8, RawSize: 8, Encoding: M, RegType: General Purpose, RegSize: 8, RegId: 0, RegCount: 1
Operand: 2, Acc: -W, Type: Register, Size: 8, RawSize: 8, Encoding: E, RegType: Model Specific, RegSize: 8, RegId: 0xffffffff, RegCount: 1
0000000000000009 c4e77bf8c011223344 URDMSR rax, 0x44332211
DSIZE: 32, ASIZE: 64, VLEN: -
ISA Set: USER_MSR, Ins cat: USER_MSR, CET tracked: no
CPUID leaf: 0x00000007, sub-leaf: 0x00000001, reg: edx, bit: 15
Valid modes
R0: yes, R1: yes, R2: yes, R3: yes
Real: no, V8086: no, Prot: no, Compat: no, Long: yes
SMM on: yes, SMM off: yes, SGX on: yes, SGX off: yes, TSX on: yes, TSX off: yes
VMXRoot: yes, VMXNonRoot: yes, VMXRoot SEAM: yes, VMXNonRoot SEAM: yes, VMX off: yes
Valid prefixes
REP: no, REPcc: no, LOCK: no
HLE: no, XACQUIRE only: no, XRELEASE only: no
BND: no, BHINT: no, DNT: no
Operand: 0, Acc: -W, Type: Register, Size: 8, RawSize: 8, Encoding: M, RegType: General Purpose, RegSize: 8, RegId: 0, RegCount: 1
Operand: 1, Acc: R-, Type: Immediate, Size: 4, RawSize: 4, Encoding: I
Operand: 2, Acc: R-, Type: Register, Size: 8, RawSize: 8, Encoding: E, RegType: Model Specific, RegSize: 8, RegId: 0xffffffff, RegCount: 1
0000000000000012 f30f38f8c1 UWRMSR rax, rcx
DSIZE: 32, ASIZE: 64, VLEN: -
ISA Set: USER_MSR, Ins cat: USER_MSR, CET tracked: no
CPUID leaf: 0x00000007, sub-leaf: 0x00000001, reg: edx, bit: 15
Valid modes
R0: yes, R1: yes, R2: yes, R3: yes
Real: no, V8086: no, Prot: no, Compat: no, Long: yes
SMM on: yes, SMM off: yes, SGX on: yes, SGX off: yes, TSX on: yes, TSX off: yes
VMXRoot: yes, VMXNonRoot: yes, VMXRoot SEAM: yes, VMXNonRoot SEAM: yes, VMX off: yes
Valid prefixes
REP: no, REPcc: no, LOCK: no
HLE: no, XACQUIRE only: no, XRELEASE only: no
BND: no, BHINT: no, DNT: no
Operand: 0, Acc: R-, Type: Register, Size: 8, RawSize: 8, Encoding: R, RegType: General Purpose, RegSize: 8, RegId: 0, RegCount: 1
Operand: 1, Acc: R-, Type: Register, Size: 8, RawSize: 8, Encoding: M, RegType: General Purpose, RegSize: 8, RegId: 1, RegCount: 1
Operand: 2, Acc: -W, Type: Register, Size: 8, RawSize: 8, Encoding: E, RegType: Model Specific, RegSize: 8, RegId: 0xffffffff, RegCount: 1
0000000000000017 f20f38f8c1 URDMSR rcx, rax
DSIZE: 32, ASIZE: 64, VLEN: -
ISA Set: USER_MSR, Ins cat: USER_MSR, CET tracked: no
CPUID leaf: 0x00000007, sub-leaf: 0x00000001, reg: edx, bit: 15
Valid modes
R0: yes, R1: yes, R2: yes, R3: yes
Real: no, V8086: no, Prot: no, Compat: no, Long: yes
SMM on: yes, SMM off: yes, SGX on: yes, SGX off: yes, TSX on: yes, TSX off: yes
VMXRoot: yes, VMXNonRoot: yes, VMXRoot SEAM: yes, VMXNonRoot SEAM: yes, VMX off: yes
Valid prefixes
REP: no, REPcc: no, LOCK: no
HLE: no, XACQUIRE only: no, XRELEASE only: no
BND: no, BHINT: no, DNT: no
Operand: 0, Acc: -W, Type: Register, Size: 8, RawSize: 8, Encoding: M, RegType: General Purpose, RegSize: 8, RegId: 1, RegCount: 1
Operand: 1, Acc: R-, Type: Register, Size: 8, RawSize: 8, Encoding: R, RegType: General Purpose, RegSize: 8, RegId: 0, RegCount: 1
Operand: 2, Acc: R-, Type: Register, Size: 8, RawSize: 8, Encoding: E, RegType: Model Specific, RegSize: 8, RegId: 0xffffffff, RegCount: 1

@ -0,0 +1 @@
Δηzψΐ"3DΔη{ψΐ"3DσΑςΑ

@ -1,6 +1,6 @@
.PHONY: clean
SRC_FILES := bdshemu.c
SRC_FILES := bdshemu.c bdshemu_x86.c
OBJECTS := $(SRC_FILES:.c=.o)
@ -120,4 +120,5 @@ install: all
install -d $(DESTDIR)$(PREFIX)/lib/
install -m 644 $(OUT_DIR)/$(LIB_NAME) $(DESTDIR)$(PREFIX)/lib/
install -d $(DESTDIR)$(PREFIX)/include/bddisasm/
cp -r ../inc/bdshemu.h $(DESTDIR)$(PREFIX)/include/bddisasm/
cp -r ../inc/bdshemu.h $(DESTDIR)$(PREFIX)/include/bddisasm/
cp -r ../inc/bdshemu_x86.h $(DESTDIR)$(PREFIX)/include/bddisasm/

File diff suppressed because it is too large Load Diff

@ -643,10 +643,13 @@
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="bdshemu.c" />
<ClCompile Include="bdshemu_x86.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\inc\bddisasm_version.h" />
<ClInclude Include="..\inc\bdshemu.h" />
<ClInclude Include="..\inc\version.h" />
<ClInclude Include="..\inc\bdshemu_x86.h" />
<ClInclude Include="include\bdshemu_common.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">

@ -16,18 +16,36 @@
<Filter Include="Header Files\public">
<UniqueIdentifier>{e9031566-ae16-49a2-807a-b33729f7b1d4}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="bdshemu.c">
<Filter>Source Files</Filter>
</ClCompile>
<Filter Include="Header Files\public\x86">
<UniqueIdentifier>{d95202e3-5db7-4437-aaee-b42dd317eb1b}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\x86">
<UniqueIdentifier>{b37ad850-b053-4c49-a61c-81abc50c144e}</UniqueIdentifier>
</Filter>
<Filter Include="Header Files\private">
<UniqueIdentifier>{ca0d8798-3c56-489f-8cc5-fe315397c76a}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\inc\bdshemu.h">
<Filter>Header Files\public</Filter>
</ClInclude>
<ClInclude Include="..\inc\version.h">
<ClInclude Include="..\inc\bdshemu_x86.h">
<Filter>Header Files\public\x86</Filter>
</ClInclude>
<ClInclude Include="include\bdshemu_common.h">
<Filter>Header Files\private</Filter>
</ClInclude>
<ClInclude Include="..\inc\bddisasm_version.h">
<Filter>Header Files\public</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="bdshemu.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="bdshemu_x86.c">
<Filter>Source Files\x86</Filter>
</ClCompile>
</ItemGroup>
</Project>

File diff suppressed because it is too large Load Diff

@ -0,0 +1,172 @@
/*
* Copyright (c) 2020 Bitdefender
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef BDSHEMU_COMMON_H_
#define BDSHEMU_COMMON_H_
#if defined(_MSC_VER)
#include <sal.h>
#else
#define _Analysis_assume_(x)
#endif
// The SHELLBMP and STACKBMP are two bitmaps which hold the state of each shellcode byte and each stack byte.
// Inside SHELLBMP, we store whether a shellcode byte has been fetched for execution or not, and whether it was
// modified or not.
// Inside STACKBMP, we store whether a stack byte is part of a previously saved RIP value or not.
#define STACKBMP(ctx) ((ctx)->Intbuf)
#define STACKBMP_SIZE(ctx) ((ctx)->StackSize)
#define SHELLBMP(ctx) (!((ctx)->Options & SHEMU_OPT_DIRECT_MAPPED_SHELL) ? (ctx)->Intbuf + (ctx)->StackSize : ND_NULL)
#define SHELLBMP_SIZE(ctx) (!((ctx)->Options & SHEMU_OPT_DIRECT_MAPPED_SHELL) ? (ctx)->ShellcodeSize : 0)
#define MAX(a, b) ((a) < (b) ? (b) : (a))
#define MIN(a, b) ((a) > (b) ? (b) : (a))
// Flags used for the shellcode. These are set inside SHELLBMP. Each byte at index X inside SHELLBMP indicates the state
// of the shellcode byte at index X.
#define SHELL_BYTE_DIRTY (0x01) // The location inside the shellcode has been written.
#define SHELL_BYTE_FETCHED (0x02) // The location inside the shellcode has been fetched for execution.
#define SHELL_BYTE_IBYTES (0x04) // The location inside the shellcode represents executed instruction
// bytes. Does not include the first instruction byte, which is marked
// using the SHELL_BYTE_FETCHED flag.
// Flags used for the stack. These are set inside STACKBMP. Each byte at index X inside STACKBMP indicates the state
// of the stack byte at index X.
#define STACK_BYTE_RIP (0x01) // The location inside the stack contains a RIP portion.
// Flags used for the GPR tracking mechanism. Each byte X inside the GPR tracker array indicates the state of said GPR.
#define GPR_TRACK_READ (0x01) // The GPR has been read, by any instruction (including RMW).
#define GPR_TRACK_DIRTY (0x02) // The GPR has been modified.
#define GET_BITS(val, start, stop) (((val) >> (start)) & ((1ULL << ((stop) - (start) + 1)) - 1))
#define ShemuShellBmpStateSet(Context, Start, Count, Flags) \
ShemuBmpStateUpdate(SHELLBMP(Context), SHELLBMP_SIZE(Context), Start, Count, Flags, ND_FALSE)
#define ShemuShellBmpStateClear(Context, Start, Count, Flags) \
ShemuBmpStateUpdate(SHELLBMP(Context), SHELLBMP_SIZE(Context), Start, Count, Flags, ND_TRUE)
#define ShemuShellBmpStateCheck(Context, Start, Count, Flags) \
ShemuBmpStateCheck(SHELLBMP(Context), SHELLBMP_SIZE(Context), Start, Count, Flags)
#define ShemuStackBmpStateSet(Contxt, Start, Count, Flags) \
ShemuBmpStateUpdate(STACKBMP(Context), STACKBMP_SIZE(Context), Start, Count, Flags, ND_FALSE)
#define ShemuStackBmpStateClear(Context, Start, Count, Flags) \
ShemuBmpStateUpdate(STACKBMP(Context), STACKBMP_SIZE(Context), Start, Count, Flags, ND_TRUE)
#define ShemuStackBmpStateCheck(Context, Start, Count, Flags) \
ShemuBmpStateCheck(STACKBMP(Context), STACKBMP_SIZE(Context), Start, Count, Flags)
void
shemu_printf(
SHEMU_CONTEXT *Context,
char *formatstring,
...
);
void *
shemu_memcpy(
void *Dest,
const void *Source,
ND_SIZET Size
);
void
ShemuHexlify(
ND_UINT8 *Value,
ND_UINT64 ValueSize,
char *Hex,
ND_UINT64 HexSize
);
void
ShemuBmpStateUpdate(
ND_UINT8 *Bitmap,
ND_UINT64 Size,
ND_UINT64 Start,
ND_UINT64 Count,
ND_UINT8 Flags,
ND_BOOL Clear
);
ND_BOOL
ShemuBmpStateCheck(
ND_UINT8 *Bitmap,
ND_UINT64 Size,
ND_UINT64 Start,
ND_UINT64 Count,
ND_UINT8 Flags
);
ND_BOOL
ShemuIsShellcodePtr(
SHEMU_CONTEXT *Context,
ND_UINT64 Gla,
ND_UINT64 Size
);
ND_BOOL
ShemuIsStackPtr(
SHEMU_CONTEXT *Context,
ND_UINT64 Gla,
ND_UINT64 Size
);
ND_BOOL
ShemuIsIcachePtr(
SHEMU_CONTEXT *Context,
ND_UINT64 Gla,
ND_UINT64 Size
);
SHEMU_STATUS
ShemuMemLoad(
SHEMU_CONTEXT *Context,
ND_UINT64 Gla,
ND_UINT64 Size,
ND_UINT8 *Value
);
SHEMU_STATUS
ShemuMemStore(
SHEMU_CONTEXT *Context,
ND_UINT64 Gla,
ND_UINT64 Size,
ND_UINT8 *Value
);
SHEMU_STATUS
ShemuMemFetch(
SHEMU_CONTEXT *Context,
ND_UINT64 Gla,
ND_UINT64 Size,
ND_UINT8 *Bytes
);
void
ShemuFlushIcache(
SHEMU_CONTEXT *Context
);
void
ShemuDisplayMemValue(
SHEMU_CONTEXT *Context,
ND_UINT64 Gla,
ND_UINT64 Size,
ND_UINT8 *Value,
ND_BOOL Load
);
ND_BOOL
ShemuIsImmMetasploitHash(
ND_UINT64 Value
);
#endif // BDSHEMU_COMMON_H_

@ -1,6 +1,7 @@
cmake_minimum_required(VERSION 3.16)
option(BDD_FUZZ_WITH_LOGS "Enable logging for the fuzzer" OFF)
option(BDD_FUZZ_DIRECT_MAP "Enable direct SHEMU_OPT_DIRECT_MAPPED_SHELL" OFF)
project(bdshemu_fuzzer LANGUAGES C)
@ -17,4 +18,23 @@ if (BDD_FUZZ_WITH_LOGS)
target_compile_definitions(shfuzzx64 PRIVATE ENABLE_LOGGING)
endif (BDD_FUZZ_WITH_LOGS)
if (BDD_FUZZ_DIRECT_MAP)
target_compile_definitions(shfuzzx86 PRIVATE DIRECT_MAP)
target_compile_definitions(shfuzzx64 PRIVATE DIRECT_MAP)
endif (BDD_FUZZ_DIRECT_MAP)
# Using CMAKE_C_COMPILER_ID to check for this will not work because afl-gcc is reported as gcc, while afl-clang and
# afl-clang-fast are reported as clang.
# We also don't want to use libfuzzer with AFL because it seems to have some build issues.
# TODO: but it should work, see https://chromium.googlesource.com/chromium/src/+/master/testing/libfuzzer/AFL_integration.md#how
if ("${CMAKE_C_COMPILER_ID}" STREQUAL "Clang" AND NOT "${CMAKE_C_COMPILER}" MATCHES "afl-.*")
message(STATUS "Will use libfuzzer")
target_compile_options(shfuzzx86 PRIVATE -fsanitize=fuzzer)
target_link_libraries(shfuzzx86 PRIVATE -fsanitize=fuzzer)
target_compile_options(shfuzzx64 PRIVATE -fsanitize=fuzzer)
target_link_libraries(shfuzzx64 PRIVATE -fsanitize=fuzzer)
endif ()
add_custom_target(shfuzz DEPENDS shfuzzx86 shfuzzx64)

@ -1,49 +0,0 @@
# Bitdefender Shellocde Emulator Fuzzer
This assumes that you have [AFL](https://github.com/google/AFL) in your path.
It collects the `bddisasm` and `bdshemu` sources into a single executable, built with AFL instrumentation.
## Getting started
Build it with `make shfuzz`.
Start fuzzing with `make fuzz32` (for 32-bit mode samples) or `make fuzz64` (for 64-bit mode samples).
If you're in a hurry you can fuzz in the quick and dirty mode with `DIRTY=y`: `make fuzz32 DIRTY=y` or `make fuzz64 DIRTY=y`.
Activate support for [address sanitizer](https://github.com/google/sanitizers/wiki/AddressSanitizer) with `AFL_USE_ASAN=1 make shfuzz`. This can uncover more bugs, but it is a lot slower and requires more memory.
Input files are in the `in-32` and `in-64` directories, crashes will be in `out-32/crashes` or `out-64/crashes`, hangs will be in `out-32/hangs` or `out-64/hangs`.
## Details
If the `AFL_COMPILER` variable is not set, the build process looks for `afl-clang-fast` and if it is available, the tool is compiled with that. If not, it tries to choose between `afl-clang` and `afl-gcc`.
If you want to use a certain compiler simply set `AFL_COMPILER` before invoking make: `AFL_COMPILER=afl-gcc make`.
Note that `afl-clang-fast` is not compiled by default when compiling AFL. See [llvm mode](https://github.com/google/AFL/tree/master/llvm_mode) in the AFL repository.
Run the fuzzer in 32-bit mode with `make fuzz32`, or in 64-bit mode with `make fuzz64`.
If you want to take advantage of multiple cores see [parallel fuzzing](https://github.com/google/AFL/blob/master/docs/parallel_fuzzing.txt).
If `afl-clang-fast` is used, we try to use AFL in persistent mode, which should provide better performance.
Note that both `fuzz32` and `fuzz64` assume that the tool was compiled with `afl-clang-fast`, `afl-clang`, or `afl-gcc`.
ASAN builds will have increased memory requirements. You may need to tweak the `-m` parameter (or set `AFL_MEMORY`) for `afl-fuzz` (see [notes for ASAN](https://github.com/google/AFL/blob/master/docs/notes_for_asan.txt)).
By default, all logging is disabled, as it is already not visible while AFL is running. Compile with `LOG=y` in order to enable some minimal logging.
## Using the tool
The `shfuzz` tool is a simplified version of `disasmtool`. It takes 3 positional arguments:
```bash
shfuzz file mode use_logging
```
- file - the path to a input file that contains instructions to be disassembled and emulated;
- mode - the mode in which to run: `32` for 32-bit instructions, `64` for 64-bit instruction;
- use_logging - if present, will actually log everything that `bdshemu` wants to log; even if absent, the `ShemuLog` implementation will still try to access every character in the string it should normally print, so if you want to find bugs related to logging you can still do, but it is a lot faster when the strings don't get printed. This is ignored if you compile `shfuzz` without `LOG=y`.
Any errors encountered while parsing the arguments, trying to open the input file, or allocate memory are handled by calling `abort()`. This makes it easier to detect these problems.

@ -25,11 +25,37 @@
#define LOG(fmt, ...)
#endif // ENABLE_LOGGING
void ShemuLog(char *data)
#define DEFAULT_OPTIONS (SHEMU_OPT_TRACE_EMULATION |\
SHEMU_OPT_SUPPORT_AES |\
SHEMU_OPT_SUPPORT_APX)
void ShemuLog(char *data, void *ctx)
{
(void)(ctx);
LOG("%s", data);
}
ND_BOOL
access_shellcode(void *Ctx, ND_UINT64 Gla, ND_SIZET Size, ND_UINT8 *Buffer, ND_BOOL Store)
{
SHEMU_CONTEXT *ctx = Ctx;
ND_UINT32 offset;
offset = (ND_UINT32)(Gla - ctx->ShellcodeBase);
if (Store)
{
memcpy(ctx->Shellcode + offset, Buffer, Size);
}
else
{
memcpy(Buffer, ctx->Shellcode + offset, Size);
}
return true;
}
#if defined(FUZZ_X86) || defined(FUZZ_X64)
#ifdef FUZZ_X86
#define DEF_CODE ND_CODE_32
#define FUZZER_TYPE "x86"
@ -45,6 +71,13 @@ void run_shemu(uint8_t *Data, size_t Size)
SHEMU_CONTEXT ctx = { 0 };
SHEMU_STATUS shs;
#if defined(DIRECT_MAP)
ctx.AccessShellcode = access_shellcode;
ctx.Options |= SHEMU_OPT_DIRECT_MAPPED_SHELL;
#endif
ctx.ArchType = SHEMU_ARCH_TYPE_X86;
ctx.Shellcode = Data;
ctx.Stack = calloc(1, 0x2000);
@ -65,28 +98,28 @@ void run_shemu(uint8_t *Data, size_t Size)
ctx.ShellcodeSize = (uint32_t)Size;
ctx.StackBase = 0x100000;
ctx.StackSize = 0x2000;
ctx.Registers.RegRsp = 0x101000;
ctx.Arch.X86.Registers.RegRsp = 0x101000;
ctx.IntbufSize = (uint32_t)Size + 0x2000;
ctx.Registers.RegFlags = NDR_RFLAG_IF | 2;
ctx.Registers.RegRip = ctx.ShellcodeBase;
ctx.Segments.Cs.Selector = 0x10;
ctx.Segments.Ds.Selector = 0x28;
ctx.Segments.Es.Selector = 0x28;
ctx.Segments.Ss.Selector = 0x28;
ctx.Segments.Fs.Selector = 0x30;
ctx.Segments.Fs.Base = 0x7FFF0000;
ctx.Segments.Gs.Selector = 0x30;
ctx.Segments.Gs.Base = 0x7FFF0000;
ctx.Mode = DEF_CODE;
ctx.Ring = 3;
ctx.TibBase = ctx.Mode == ND_CODE_32 ? ctx.Segments.Fs.Base : ctx.Segments.Gs.Base;
ctx.Arch.X86.Registers.RegFlags = NDR_RFLAG_IF | 2;
ctx.Arch.X86.Registers.RegRip = ctx.ShellcodeBase;
ctx.Arch.X86.Segments.Cs.Selector = 0x10;
ctx.Arch.X86.Segments.Ds.Selector = 0x28;
ctx.Arch.X86.Segments.Es.Selector = 0x28;
ctx.Arch.X86.Segments.Ss.Selector = 0x28;
ctx.Arch.X86.Segments.Fs.Selector = 0x30;
ctx.Arch.X86.Segments.Fs.Base = 0x7FFF0000;
ctx.Arch.X86.Segments.Gs.Selector = 0x30;
ctx.Arch.X86.Segments.Gs.Base = 0x7FFF0000;
ctx.Arch.X86.Mode = DEF_CODE;
ctx.Arch.X86.Ring = 3;
ctx.TibBase = ctx.Arch.X86.Mode == ND_CODE_32 ? ctx.Arch.X86.Segments.Fs.Base : ctx.Arch.X86.Segments.Gs.Base;
ctx.MaxInstructionsCount = 4096;
ctx.Log = &ShemuLog;
ctx.Flags = 0;
ctx.Options = SHEMU_OPT_TRACE_EMULATION;
ctx.Options |= DEFAULT_OPTIONS;
shs = ShemuEmulate(&ctx);
LOG("[+] Shemu returned: 0x%08x\n", shs);
@ -94,10 +127,11 @@ void run_shemu(uint8_t *Data, size_t Size)
free(ctx.Intbuf);
free(ctx.Stack);
}
#else
#error "Do not know what to fuzz, define one of FUZZ_X86, FUZZ_X64"
#endif
#if defined(__AFL_FUZZ_TESTCASE_LEN)
#include <unistd.h>
// See https://github.com/AFLplusplus/AFLplusplus/blob/stable/instrumentation/README.persistent_mode.md
__AFL_FUZZ_INIT();

@ -0,0 +1,21 @@
#!/bin/bash
set -e
# Check if the -it flag is provided
if [ -t 0 ] && [ -t 1 ]; then
echo "Running in interactive mode"
else
echo "Error: This container requires an interactive shell (-it flag)."
exit 1
fi
# Check if the volume directory is present
if [ ! -d "${SHARE_DIR}" ]; then
echo "Warning: Volume directory '${SHARE_DIR}' is missing."
echo "Please use the -v flag to specify a host directory."
echo "For example 'podman run -v /host/path:${SHARE_DIR}'"
echo "You will need to manually copy fuzzing inputs/outputs from/to the host"
fi
# Continue with the original command
exec "$@"

@ -1,7 +1,7 @@
# Shellcode Emulator Tests
These tests are used to validate basic bdshemu functionality. Each test consists of up to three files:
* The binary test file. The name format for this type of file is `name_32|64[_r0]`. No extension must be provided; 32 indicates 32 bit test file, 64 indicates 64 bit test file, and r0 indicates kernel payload
* The binary test file. The name format for this type of file is `name_32|64[_r0].test`. 32 indicates 32 bit test file, 64 indicates 64 bit test file, and r0 indicates kernel payload
* The output result file. Must be named the same as the binary test file, but with the extension .result
* Optional assembly file, used to generate the binary test file

Binary file not shown.

@ -5,87 +5,175 @@
import os
import sys
import glob
import shutil
from zipfile import ZipFile
from pathlib import Path
total_tests = 0
failed_tests = 0
TEMP_PATH = "!temp"
def test_dir(dir):
global total_tests
global failed_tests
# A test file-name contains some indicators as to how the emulation should be done:
# - If '_16' is present in the name, emulation will be done on 16 bit
# - If '_32' is present in the name, emulation will be done on 32 bit
# - If '_64' is present in the name, emulation will be done on 64 bit
# - If '_r0' is present in the name, emulation will be done as kernel code
# A test case consists of minimum two files:
# - An '.test' file, containing the binary code to be emulated
# - An '.result' file, containing the emulation output
# A test is considered passed if the output produced during emulation is identical to the
# output containted in the '.result' file.
#
# test_dir
#
# Runs the tests inside the provided directory.
# Returns a tuplecontaining the total number of tests run and the number of failed tests.
#
def test_dir(dir, arch='x86'):
total_tests = 0
failed_tests = 0
for f in glob.glob('%s\\*' % dir):
if -1 == f.find('.'):
if 0 < f.find('_16'):
mod = '-b16'
elif 0 < f.find('_32'):
mod = '-b32'
else:
mod = '-b64'
if 0 < f.find('_r0'):
mod += ' -k'
print(' * Running test case %s...' % f)
os.system('disasm shemu %s -f %s >%s.temp' % (mod, f, f))
try:
res = open('%s.result' % f).read()
except:
print(' ! No result file provided for test %s!' % f)
try:
tmp = open('%s.temp' % f).read()
except:
print(' ! No result produced by test %s!' % f)
for f in glob.glob('%s\\*.test' % dir):
base, _ = os.path.splitext(f)
tst_file = f
res_file = base + '.result'
tmp_file = base + '.temp'
if 0 < tst_file.find('_16'):
mod = '-b16'
elif 0 < tst_file.find('_32'):
mod = '-b32'
else:
mod = '-b64'
total_tests += 1
if res != tmp:
print(' **** FAILED! ****')
failed_tests += 1
else:
print(' * Passed.')
for f in glob.glob('%s\\*_decoded.bin' % dir):
os.remove(f)
for f in glob.glob('%s\\*.temp' % dir):
os.remove(f)
if 0 < tst_file.find('_r0'):
mod += ' -k'
print(' * Running test case %s...' % tst_file)
os.system('disasm shemu %s -f %s >%s' % (mod, tst_file, tmp_file))
try:
res = open(res_file).read()
except:
print(' ! No result file provided for test %s!' % tst_file)
try:
tmp = open(tmp_file).read()
except:
print(' ! No result produced by test %s!' % tst_file)
total_tests += 1
if res != tmp:
print(' **** FAILED! ****')
failed_tests += 1
else:
print(' * Passed.')
# Cleanup.
os.remove(tmp_file)
os.remove(tst_file + "_decoded.bin")
return (total_tests, failed_tests)
#
# regenerate
#
def regenerate(dir, arch='x86'):
for f in glob.glob('%s\\*.test' % dir):
base, _ = os.path.splitext(f)
tst_file = f
res_file = base + '.result'
def regenerate(dir):
for f in glob.glob('%s\\*' % dir):
if -1 == f.find('.'):
if 0 < f.find('_16'):
mod = '-b16'
elif 0 < f.find('_32'):
mod = '-b32'
else:
mod = '-b64'
if 0 < f.find('_r0'):
mod += ' -k'
if 0 < f.find('_16'):
mod = '-b16'
elif 0 < f.find('_32'):
mod = '-b32'
else:
mod = '-b64'
if 0 < f.find('_r0'):
mod += ' -k'
print(' * Regenerating test case %s...' % f)
os.system('disasm -exi shemu %s -f %s >%s.result' % (mod, f, f))
for f in glob.glob('%s\\*_decoded.bin' % dir):
os.remove(f)
print(' * Regenerating test case %s...' % tst_file)
os.system('disasm -exi shemu %s -f %s >%s' % (mod, tst_file, res_file))
# Cleanup.
os.remove(tst_file + "_decoded.bin")
#
# parse_dir_rec
#
def parse_dir_rec(dir, arch, handler):
for f in glob.glob(dir + "\\*"):
path, name = os.path.split(f)
if name in ['.', '..']:
continue
if os.path.isdir(f):
parse_dir_rec(f, arch, handler)
handler(f, arch)
cleanup_files = []
print("Extracting test archive...\n")
with ZipFile('bdshemu_test.zip') as zf:
cleanup_files = zf.namelist()
zf.extractall()
print("Done!\n")
#
# test_archive
#
def test_archive(filename, arch='x86'):
cleanup_files = []
# Run the x86 test.
print("Extracting test archive...")
with ZipFile(filename) as zf:
cleanup_files = zf.namelist()
zf.extractall(path=TEMP_PATH)
zf.close()
for dn in glob.glob("*"):
if not os.path.isdir(dn):
continue
print('Testing %s...' % dn)
test_dir(dn)
print("Ran %d tests, %d failed" % (total_tests, failed_tests))
print("Running tests...")
total_tests, failed_tests = 0, 0
for dn in glob.glob(os.path.join(TEMP_PATH, "*")):
if not os.path.isdir(dn):
continue
print('Testing %s...' % dn)
cnt_tests, cnt_failed = test_dir(dn, arch)
total_tests += cnt_tests
failed_tests += cnt_failed
print("========================================================================")
print("Summary:")
print("Ran %d tests, %d failed" % (total_tests, failed_tests))
print("========================================================================")
print()
shutil.rmtree(TEMP_PATH)
if __name__ == "__main__":
# No arguments provided, auto-run all tests.
if len(sys.argv) == 1:
print("Running x86 tests...")
test_archive("x86\\bdshemu_test_x86.zip")
sys.exit(0)
opt_dir = ""
opt_regen = False
opt_arch = 'x86'
for arg in sys.argv[1:]:
if os.path.isdir(arg):
print("Will test directory", arg)
opt_dir = arg
if arg == "regenerate":
print("Will regenerate tests...")
opt_regen = True
print("Identified architecture: ", opt_arch)
# Single directory test.
if not opt_dir:
print("A directory containing tests must be supplied!")
sys.exit(-1)
print("Cleaning up test files...\n")
for f in cleanup_files:
p = Path(os.getcwd()) / f
if p.is_file():
p.unlink()
print("Done!\n")
if opt_regen:
parse_dir_rec(opt_dir, opt_arch, regenerate)
else:
parse_dir_rec(opt_dir, opt_arch, test_dir)

@ -15,7 +15,7 @@
#define ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x)))
#if _MSC_VER
#ifdef _MSC_VER
int nd_vsnprintf_s(char *buffer, size_t size, size_t count, const char *format, va_list argptr)
{
return vsnprintf(buffer, size, format, argptr);
@ -27,7 +27,7 @@ void * nd_memset(void *s, int c, size_t n)
}
#endif
void nd_get_version(ND_UINT32 *major, ND_UINT32 *minor, ND_UINT32 *revision, char **build_date, char **build_time)
void nd_get_version(ND_UINT32 *major, ND_UINT32 *minor, ND_UINT32 *revision, const char **build_date, const char **build_time)
{
NdGetVersion(major, minor, revision, build_date, build_time);
}

@ -7,7 +7,7 @@
#include "bddisasm.h"
void nd_get_version(ND_UINT32 *major, ND_UINT32 *minor, ND_UINT32 *revision, char **build_date, char **build_time);
void nd_get_version(ND_UINT32 *major, ND_UINT32 *minor, ND_UINT32 *revision, const char **build_date, const char **build_time);
NDSTATUS nd_decode(INSTRUX *__output_instr, const ND_UINT8 *code, ND_UINT8 def_code, ND_UINT8 def_data);
NDSTATUS nd_decode_ex(INSTRUX *__output_instr, const ND_UINT8 *code, ND_SIZET size, ND_UINT8 def_code, ND_UINT8 def_data);
NDSTATUS nd_decode_ex2(INSTRUX *__output_instr, const ND_UINT8 *code, ND_SIZET size, ND_UINT8 def_code, ND_UINT8 def_data,

@ -9,13 +9,6 @@
#include "pybddisasm.h"
#include "bddisasm.h"
#include "constants.h"
#include "cpuidflags.h"
#include "disasmstatus.h"
#include "disasmtypes.h"
#include "registers.h"
#include "version.h"
%}
%include "typemaps.i"
@ -165,13 +158,10 @@
%define __x86_64__
%enddef
%include "bddisasm.h"
%include "constants.h"
%include "cpuidflags.h"
%include "disasmstatus.h"
%include "disasmtypes.h"
%include "registers.h"
%include "version.h"
%include "pybddisasm.h"
%include "bdx86_constants.h"
%include "bdx86_cpuidflags.h"
%include "bddisasm_status.h"
%include "bddisasm_types.h"
%include "bdx86_registers.h"
%include "bdx86_core.h"

@ -12,7 +12,7 @@ from setuptools import find_packages, setup, Command, Extension, Distribution
from codecs import open
VERSION = (0, 3, 0)
LIBRARY_VERSION = (1, 38, 0)
LIBRARY_VERSION = (2, 1, 0)
DIR_INCLUDE = '../../inc'
here = os.path.abspath(os.path.dirname(__file__))
@ -25,7 +25,6 @@ __library_dirs = ['../../build', '../../bin/x64/Release']
__packages = ['pybddisasm']
__requires = ['setuptools']
class BinaryDistribution(Distribution):
def has_ext_modules(arg):
return True
@ -33,10 +32,8 @@ class BinaryDistribution(Distribution):
def is_pure(self):
return False
def __fn_validate_compatibility():
print(os.getcwd())
version_header = '%s/version.h' % (DIR_INCLUDE)
version_header = '%s/bddisasm_version.h' % (DIR_INCLUDE)
with open(version_header, 'r') as file:
data = file.read()
@ -62,10 +59,9 @@ def __fn_validate_compatibility():
if int(major) != LIBRARY_VERSION[0] or int(minor) != LIBRARY_VERSION[1] or int(revision) != LIBRARY_VERSION[2]:
print('error: The version of the library is not compatible with the pybddisasm!')
print('error: Library : %s.%s.%s - pybddisasm : %d.%d.%d' % (major, minor, revision, LIBRARY_VERSION[0],
LIBRARY_VERSION[1], LIBRARY_VERSION[2]))
LIBRARY_VERSION[1], LIBRARY_VERSION[2]))
sys.exit(1)
__fn_validate_compatibility()
with open('README.md', 'r', 'utf-8') as f:
@ -91,11 +87,12 @@ setup(
install_requires=__requires,
zip_safe=False,
classifiers=[
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
'Programming Language :: Python :: 3.9',
'Programming Language :: Python :: 3.10',
'Programming Language :: Python :: 3.11',
'License :: OSI Approved :: Apache Software License',
'Operating System :: Microsoft :: Windows',
'Operating System :: POSIX :: Linux'

@ -4,3 +4,6 @@ members = [
"bddisasm-sys",
"bddisasm",
]
[workspace.package]
version = "0.2.3"

@ -1,6 +1,6 @@
[package]
name = "bddisasm-sys"
version = "0.4.0"
version.workspace = true
authors = ["Cristi Anichitei <ianichitei@bitdefender.com>"]
edition = "2018"
links = "bddisasm"
@ -23,5 +23,5 @@ path = "src/lib.rs"
cty = "0.2.2"
[build-dependencies]
bindgen = "0.59.1"
bindgen = "0.62.0"
cc = "1.0.70"

@ -9,10 +9,10 @@ fn main() {
println!("cargo:rerun-if-changed=csrc");
cc::Build::new()
.file("csrc/bddisasm/bddisasm.c")
.file("csrc/bddisasm/bdformat.c")
.file("csrc/bddisasm/bdhelpers.c")
.file("csrc/bddisasm/crt.c")
.file("csrc/bddisasm/bddisasm_crt.c")
.file("csrc/bddisasm/bdx86_decoder.c")
.file("csrc/bddisasm/bdx86_formatter.c")
.file("csrc/bddisasm/bdx86_helpers.c")
.include("csrc/bddisasm/include")
.include("csrc/inc")
.define("BDDISASM_HAS_VSNPRINTF", Some("1"))

@ -30,8 +30,8 @@ mod tests {
let mut major: u32 = 0;
let mut minor: u32 = 0;
let mut revision: u32 = 0;
let mut build_date: *mut c_char = std::ptr::null_mut();
let mut build_time: *mut c_char = std::ptr::null_mut();
let mut build_date: *const c_char = std::ptr::null();
let mut build_time: *const c_char = std::ptr::null();
unsafe {
NdGetVersion(
@ -53,7 +53,7 @@ mod tests {
// There are no other asserts in this test. Enforcing a known minor version is not worth it, we mainly want to
// see that `NdGetVersion` works.
assert_eq!(major, 1);
assert_eq!(major, 2);
}
fn do_decode(code: &[u8]) -> (INSTRUX, NDSTATUS) {
@ -79,10 +79,7 @@ mod tests {
let (instrux, status) = do_decode(&code);
assert_eq!(status, 0, "Failed to decode instruction {:#x?}", code);
assert_eq!(
unsafe { instrux.__bindgen_anon_2.Instruction },
_ND_INS_CLASS::ND_INS_NOP
);
assert_eq!(instrux.Instruction, _ND_INS_CLASS::ND_INS_NOP);
}
#[test]

@ -2,19 +2,13 @@
## 0.3.1
### Added
- support for new Intel ISA, per Intel Architecture Instruction Set Extensions and Future Features document #319433-049 (June 2023): AVX-NNI-INT16, SHA512, SM3, SM4, TSE.
### Changed
- `Mnemonic`, `IsaSet`, and `Category` use all caps for the enum variants
## 0.3.0
### Fixed
### Removed
- #84: handle 0 sizes in `OpSize::from_raw`
- the `ExceptionClass` enum
- `sse_cond`, `has_mvex`, `has_drex`, `has_imm3`, `immediate3`, `sign_disp`, `imm3_length`, `imm3_offset`, `bhint` from `DecodedInstruction`
- multiple variants from `Category`, `IsaSet`, `Mnemonic` in accordance with the changes in `bddisasm`
- `raw_size`, `decorator` from `Operand`
- the `Operand` struct
## 0.2.1

@ -1,6 +1,6 @@
[package]
name = "bddisasm"
version = "0.3.0"
version.workspace = true
authors = ["Cristi Anichitei <ianichitei@bitdefender.com>"]
edition = "2018"
license = "Apache-2.0"
@ -14,7 +14,7 @@ categories = ["api-bindings", "hardware-support"]
keywords = ["disassembler", "decoder", "x86", "amd64", "x86_64"]
[dependencies]
bddisasm-sys = { version = "0.4.0", path = "../bddisasm-sys" }
bddisasm-sys = { version = "0.2.3", path = "../bddisasm-sys" }
[features]
std = []
@ -23,5 +23,5 @@ std = []
all-features = true
[dev-dependencies]
anyhow = "1.0"
anyhow = "1.0.0"
clap = "2.34.0"

@ -29,6 +29,7 @@
// TODO: maybe use something like the `bitflags` crate and have all these as flags?
/// Privilege levels (rings) in which an instruction is supported.
#[allow(clippy::struct_excessive_bools)]
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
pub struct PrivilegeLevel {
/// Instruction is valid in ring 0.
@ -45,6 +46,7 @@ pub struct PrivilegeLevel {
}
/// Operating modes in which an instruction is supported.
#[allow(clippy::struct_excessive_bools)]
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
pub struct OperatingMode {
/// The instruction is valid in real mode.
@ -64,6 +66,7 @@ pub struct OperatingMode {
}
/// Special modes - these may be active inside other modes (example: `TSX` in `Long mode`).
#[allow(clippy::struct_excessive_bools)]
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
pub struct SpecialModes {
/// The instruction is valid in System Management Mode.
@ -86,6 +89,7 @@ pub struct SpecialModes {
}
/// VMX mode - they engulf all the other modes.
#[allow(clippy::struct_excessive_bools)]
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
pub struct VmxMode {
/// The instruction is valid in VMX root mode.

@ -7,7 +7,7 @@
//!
//! # Notes
//!
//! All error codes that can be returned by `bddisasm-sys` are encapsulated in the [`DecodeError`](DecodeError) enum.
//! All error codes that can be returned by `bddisasm-sys` are encapsulated in the [`DecodeError`] enum.
//! However, some of these are unlikely to be encountered when using this crate (for example,
//! [`BufferOverflow`](DecodeError::BufferOverflow)) which indicates that a buffer passed to the `bddisasm` C library is
//! not large enough.
@ -117,6 +117,9 @@ pub enum DecodeError {
/// Not enough space is available.
BufferOverflow,
/// EVEX payload byte 3 is invalid.
InvalidEvexByte3,
/// Internal library error.
InternalError(u64),
}
@ -181,6 +184,9 @@ impl fmt::Display for DecodeError {
DecodeError::BufferOverflow => {
write!(f, "not enough space is available to format instruction")
}
DecodeError::InvalidEvexByte3 => {
write!(f, "EVEX payload byte 3 is invalid.")
}
DecodeError::InternalError(e) => write!(f, "internal error: {}", e),
}
}
@ -232,6 +238,7 @@ pub(crate) fn status_to_error(status: ffi::NDSTATUS) -> Result<(), DecodeError>
ffi::ND_STATUS_INVALID_PARAMETER => Err(DecodeError::InvalidParameter),
ffi::ND_STATUS_INVALID_INSTRUX => Err(DecodeError::InvalidInstrux),
ffi::ND_STATUS_BUFFER_OVERFLOW => Err(DecodeError::BufferOverflow),
ffi::ND_STATUS_INVALID_EVEX_BYTE3 => Err(DecodeError::InvalidEvexByte3),
ffi::ND_STATUS_INTERNAL_ERROR => Err(DecodeError::InternalError(0)),
_ => panic!("Unexpected status: {:#x}", status),
}

File diff suppressed because it is too large Load Diff

@ -20,10 +20,11 @@ impl<'a> Decoder<'a> {
///
/// # Arguments
///
/// * `code` - An [u8](u8) slice that holds the code to be decoded.
/// * `code` - An [`u8`] slice that holds the code to be decoded.
/// * `mode` - The mode in which to decode the instruction.
/// * `ip` - The instruction pointer value to use when formatting the decoded instruction. Does not affect the
/// decoding process in any way.
#[must_use]
pub fn new(code: &'a [u8], mode: DecodeMode, ip: u64) -> Self {
Self {
code,
@ -82,15 +83,12 @@ impl<'a> Decoder<'a> {
} else {
let result =
DecodedInstruction::decode_with_ip(&self.code[self.offset..], self.mode, self.ip);
match result {
Ok(ins) => {
self.offset += ins.length() as usize;
self.ip += ins.length() as u64;
}
Err(_) => {
self.offset += 1;
self.ip += 1;
}
if let Ok(ins) = result {
self.offset += ins.length();
self.ip += ins.length() as u64;
} else {
self.offset += 1;
self.ip += 1;
};
Some(result)
@ -99,7 +97,7 @@ impl<'a> Decoder<'a> {
/// Attempts to decode the next instruction from the given code chunk.
///
/// Behaves like [`decode_next`](Decoder::decode_next), but in addition to the [`DecodeResult`](DecodeResult) it
/// Behaves like [`decode_next`](Decoder::decode_next), but in addition to the [`DecodeResult`] it
/// will also return the offset from which decoding was attempted, as well as the corresponding instruction pointer.
///
/// # Examples
@ -134,7 +132,7 @@ impl<'a> Decoder<'a> {
/// Attempts to decode the next instruction from the given code chunk.
///
/// Behaves like [`decode_next`](Decoder::decode_next), but in addition to the [`DecodeResult`](DecodeResult) it
/// Behaves like [`decode_next`](Decoder::decode_next), but in addition to the [`DecodeResult`] it
/// will also return the offset from which decoding was attempted.
///
/// # Examples
@ -168,7 +166,7 @@ impl<'a> Decoder<'a> {
/// Attempts to decode the next instruction from the given code chunk.
///
/// Behaves like [`decode_next`](Decoder::decode_next), but in addition to the [`DecodeResult`](DecodeResult) it
/// Behaves like [`decode_next`](Decoder::decode_next), but in addition to the [`DecodeResult`] it
/// will also return the corresponding instruction pointer.
///
/// # Examples

@ -4,6 +4,8 @@
*/
//! Offers information about how an instructions accesses the FPU status registers.
#![allow(clippy::module_name_repetitions)]
use super::decode_error::DecodeError;
/// The mode in which a FPU status flag is accessed.

@ -15,6 +15,7 @@ pub enum Category {
AES,
AESKL,
AMX,
APX,
ARITH,
AVX,
AVX2,
@ -72,7 +73,6 @@ pub enum Category {
MOVDIRI,
MPX,
NOP,
PADLOCK,
PCLMULQDQ,
PCONFIG,
POP,
@ -108,6 +108,7 @@ pub enum Category {
UINTR,
UNCOND_BR,
UNKNOWN,
USER_MSR,
VAES,
VFMA,
VFMAPS,
@ -129,6 +130,7 @@ pub enum Category {
impl TryFrom<ffi::ND_INS_CATEGORY> for Category {
type Error = DecodeError;
#[allow(clippy::too_many_lines)]
fn try_from(value: ffi::ND_INS_CATEGORY) -> Result<Self, Self::Error> {
match value {
ffi::_ND_INS_TYPE::ND_CAT_INVALID => Err(DecodeError::InternalError(value as u64)),
@ -136,6 +138,7 @@ impl TryFrom<ffi::ND_INS_CATEGORY> for Category {
ffi::_ND_INS_TYPE::ND_CAT_AES => Ok(Category::AES),
ffi::_ND_INS_TYPE::ND_CAT_AESKL => Ok(Category::AESKL),
ffi::_ND_INS_TYPE::ND_CAT_AMX => Ok(Category::AMX),
ffi::_ND_INS_TYPE::ND_CAT_APX => Ok(Category::APX),
ffi::_ND_INS_TYPE::ND_CAT_ARITH => Ok(Category::ARITH),
ffi::_ND_INS_TYPE::ND_CAT_AVX => Ok(Category::AVX),
ffi::_ND_INS_TYPE::ND_CAT_AVX2 => Ok(Category::AVX2),
@ -193,7 +196,6 @@ impl TryFrom<ffi::ND_INS_CATEGORY> for Category {
ffi::_ND_INS_TYPE::ND_CAT_MOVDIRI => Ok(Category::MOVDIRI),
ffi::_ND_INS_TYPE::ND_CAT_MPX => Ok(Category::MPX),
ffi::_ND_INS_TYPE::ND_CAT_NOP => Ok(Category::NOP),
ffi::_ND_INS_TYPE::ND_CAT_PADLOCK => Ok(Category::PADLOCK),
ffi::_ND_INS_TYPE::ND_CAT_PCLMULQDQ => Ok(Category::PCLMULQDQ),
ffi::_ND_INS_TYPE::ND_CAT_PCONFIG => Ok(Category::PCONFIG),
ffi::_ND_INS_TYPE::ND_CAT_POP => Ok(Category::POP),
@ -229,6 +231,7 @@ impl TryFrom<ffi::ND_INS_CATEGORY> for Category {
ffi::_ND_INS_TYPE::ND_CAT_UINTR => Ok(Category::UINTR),
ffi::_ND_INS_TYPE::ND_CAT_UNCOND_BR => Ok(Category::UNCOND_BR),
ffi::_ND_INS_TYPE::ND_CAT_UNKNOWN => Ok(Category::UNKNOWN),
ffi::_ND_INS_TYPE::ND_CAT_USER_MSR => Ok(Category::USER_MSR),
ffi::_ND_INS_TYPE::ND_CAT_VAES => Ok(Category::VAES),
ffi::_ND_INS_TYPE::ND_CAT_VFMA => Ok(Category::VFMA),
ffi::_ND_INS_TYPE::ND_CAT_VFMAPS => Ok(Category::VFMAPS),

@ -20,6 +20,7 @@ pub enum IsaSet {
AMXFP16,
AMXINT8,
AMXTILE,
APX_F,
AVX,
AVX2,
AVX2GATHER,
@ -56,8 +57,6 @@ pub enum IsaSet {
CLZERO,
CMPCCXADD,
CMPXCHG16B,
CYRIX,
CYRIX_SMM,
ENQCMD,
F16C,
FMA,
@ -132,6 +131,7 @@ pub enum IsaSet {
UD,
UINTR,
UNKNOWN,
USER_MSR,
VAES,
VPCLMULQDQ,
VTX,
@ -149,6 +149,7 @@ pub enum IsaSet {
impl TryFrom<ffi::ND_INS_SET> for IsaSet {
type Error = DecodeError;
#[allow(clippy::too_many_lines)]
fn try_from(value: ffi::ND_INS_SET) -> Result<Self, Self::Error> {
match value {
ffi::_ND_INS_SET::ND_SET_INVALID => Err(DecodeError::InternalError(value as u64)),
@ -161,6 +162,7 @@ impl TryFrom<ffi::ND_INS_SET> for IsaSet {
ffi::_ND_INS_SET::ND_SET_AMXFP16 => Ok(IsaSet::AMXFP16),
ffi::_ND_INS_SET::ND_SET_AMXINT8 => Ok(IsaSet::AMXINT8),
ffi::_ND_INS_SET::ND_SET_AMXTILE => Ok(IsaSet::AMXTILE),
ffi::_ND_INS_SET::ND_SET_APX_F => Ok(IsaSet::APX_F),
ffi::_ND_INS_SET::ND_SET_AVX => Ok(IsaSet::AVX),
ffi::_ND_INS_SET::ND_SET_AVX2 => Ok(IsaSet::AVX2),
ffi::_ND_INS_SET::ND_SET_AVX2GATHER => Ok(IsaSet::AVX2GATHER),
@ -197,8 +199,6 @@ impl TryFrom<ffi::ND_INS_SET> for IsaSet {
ffi::_ND_INS_SET::ND_SET_CLZERO => Ok(IsaSet::CLZERO),
ffi::_ND_INS_SET::ND_SET_CMPCCXADD => Ok(IsaSet::CMPCCXADD),
ffi::_ND_INS_SET::ND_SET_CMPXCHG16B => Ok(IsaSet::CMPXCHG16B),
ffi::_ND_INS_SET::ND_SET_CYRIX => Ok(IsaSet::CYRIX),
ffi::_ND_INS_SET::ND_SET_CYRIX_SMM => Ok(IsaSet::CYRIX_SMM),
ffi::_ND_INS_SET::ND_SET_ENQCMD => Ok(IsaSet::ENQCMD),
ffi::_ND_INS_SET::ND_SET_F16C => Ok(IsaSet::F16C),
ffi::_ND_INS_SET::ND_SET_FMA => Ok(IsaSet::FMA),
@ -273,6 +273,7 @@ impl TryFrom<ffi::ND_INS_SET> for IsaSet {
ffi::_ND_INS_SET::ND_SET_UD => Ok(IsaSet::UD),
ffi::_ND_INS_SET::ND_SET_UINTR => Ok(IsaSet::UINTR),
ffi::_ND_INS_SET::ND_SET_UNKNOWN => Ok(IsaSet::UNKNOWN),
ffi::_ND_INS_SET::ND_SET_USER_MSR => Ok(IsaSet::USER_MSR),
ffi::_ND_INS_SET::ND_SET_VAES => Ok(IsaSet::VAES),
ffi::_ND_INS_SET::ND_SET_VPCLMULQDQ => Ok(IsaSet::VPCLMULQDQ),
ffi::_ND_INS_SET::ND_SET_VTX => Ok(IsaSet::VTX),

@ -22,7 +22,7 @@
//!
//! ```toml
//! [dependencies]
//! bddisasm = "0.1.0"
//! bddisasm = "0.2"
//! ```
//!
//! # Examples
@ -47,7 +47,7 @@
//!
//! ## Decoding multiple instructions
//!
//! Use [`Decoder`](crate::decoder::Decoder) to decode multiple instructions from a chunk of code.
//! Use [`Decoder`] to decode multiple instructions from a chunk of code.
//!
//! ```
//! use bddisasm::{Decoder, DecodeMode};
@ -120,7 +120,7 @@
//!
//! ## Working with instruction operands
//!
//! Instruction operands can be analyzed using the [operand](crate::operand) module. Rich informaion is offered for
//! Instruction operands can be analyzed using the [`operand`] module. Rich informaion is offered for
//! each type of operand. Bellow is a minimal example that looks at a memory operand.
//!
//! ```
@ -190,6 +190,7 @@
//!
#![cfg_attr(all(not(test), not(feature = "std")), no_std)]
#![allow(clippy::if_not_else)]
pub extern crate bddisasm_sys as ffi;

@ -41,7 +41,6 @@ pub enum Mnemonic {
AESENCWIDE256KL,
AESIMC,
AESKEYGENASSIST,
ALTINST,
AND,
ANDN,
ANDNPD,
@ -87,8 +86,10 @@ pub enum Mnemonic {
CALLNI,
CALLNR,
CBW,
CCMP,
CDQ,
CDQE,
CFCMOV,
CLAC,
CLC,
CLD,
@ -134,10 +135,9 @@ pub enum Mnemonic {
COMISD,
COMISS,
CPUID,
CPU_READ,
CPU_WRITE,
CQO,
CRC32,
CTEST,
CVTDQ2PD,
CVTDQ2PS,
CVTPD2DQ,
@ -171,7 +171,6 @@ pub enum Mnemonic {
DIVPS,
DIVSD,
DIVSS,
DMINT,
DPPD,
DPPS,
EMMS,
@ -315,6 +314,7 @@ pub enum Mnemonic {
INVPCID,
INVVPID,
IRET,
JMPABS,
JMPE,
JMPFD,
JMPFI,
@ -382,7 +382,6 @@ pub enum Mnemonic {
MINSS,
MONITOR,
MONITORX,
MONTMUL,
MOV,
MOVAPD,
MOVAPS,
@ -557,10 +556,13 @@ pub enum Mnemonic {
PMULLW,
PMULUDQ,
POP,
POP2,
POP2P,
POPA,
POPAD,
POPCNT,
POPF,
POPP,
POR,
PREFETCH,
PREFETCHE,
@ -613,9 +615,12 @@ pub enum Mnemonic {
PUNPCKLQDQ,
PUNPCKLWD,
PUSH,
PUSH2,
PUSH2P,
PUSHA,
PUSHAD,
PUSHF,
PUSHP,
PVALIDATE,
PXOR,
RCL,
@ -632,7 +637,6 @@ pub enum Mnemonic {
RDPRU,
RDRAND,
RDSEED,
RDSHR,
RDTSC,
RDTSCP,
RETF,
@ -647,14 +651,11 @@ pub enum Mnemonic {
ROUNDPS,
ROUNDSD,
ROUNDSS,
RSDC,
RSLDT,
RSM,
RSQRTPS,
RSQRTSS,
RSSSP,
RSTORSSP,
RSTS,
SAHF,
SAL,
SALC,
@ -691,7 +692,6 @@ pub enum Mnemonic {
SKINIT,
SLDT,
SLWPCB,
SMINT,
SMSW,
SPFLT,
SQRTPD,
@ -713,9 +713,6 @@ pub enum Mnemonic {
SUBPS,
SUBSD,
SUBSS,
SVDC,
SVLDT,
SVTS,
SWAPGS,
SYSCALL,
SYSENTER,
@ -754,6 +751,8 @@ pub enum Mnemonic {
UNPCKHPS,
UNPCKLPD,
UNPCKLPS,
URDMSR,
UWRMSR,
V4FMADDPS,
V4FMADDSS,
V4FNMADDPS,
@ -1621,18 +1620,12 @@ pub enum Mnemonic {
WRMSRLIST,
WRMSRNS,
WRPKRU,
WRSHR,
WRSS,
WRUSS,
XABORT,
XADD,
XBEGIN,
XCHG,
XCRYPTCBC,
XCRYPTCFB,
XCRYPTCTR,
XCRYPTECB,
XCRYPTOFB,
XEND,
XGETBV,
XLATB,
@ -1647,9 +1640,6 @@ pub enum Mnemonic {
XSAVEOPT,
XSAVES,
XSETBV,
XSHA1,
XSHA256,
XSTORE,
XSUSLDTRK,
XTEST,
}
@ -1658,6 +1648,7 @@ pub enum Mnemonic {
impl TryFrom<ffi::ND_INS_CLASS> for Mnemonic {
type Error = DecodeError;
#[allow(clippy::too_many_lines)]
fn try_from(value: ffi::ND_INS_CLASS) -> Result<Self, Self::Error> {
match value {
ffi::_ND_INS_CLASS::ND_INS_INVALID => Err(DecodeError::InternalError(value as u64)),
@ -1691,7 +1682,6 @@ impl TryFrom<ffi::ND_INS_CLASS> for Mnemonic {
ffi::_ND_INS_CLASS::ND_INS_AESENCWIDE256KL => Ok(Mnemonic::AESENCWIDE256KL),
ffi::_ND_INS_CLASS::ND_INS_AESIMC => Ok(Mnemonic::AESIMC),
ffi::_ND_INS_CLASS::ND_INS_AESKEYGENASSIST => Ok(Mnemonic::AESKEYGENASSIST),
ffi::_ND_INS_CLASS::ND_INS_ALTINST => Ok(Mnemonic::ALTINST),
ffi::_ND_INS_CLASS::ND_INS_AND => Ok(Mnemonic::AND),
ffi::_ND_INS_CLASS::ND_INS_ANDN => Ok(Mnemonic::ANDN),
ffi::_ND_INS_CLASS::ND_INS_ANDNPD => Ok(Mnemonic::ANDNPD),
@ -1737,8 +1727,10 @@ impl TryFrom<ffi::ND_INS_CLASS> for Mnemonic {
ffi::_ND_INS_CLASS::ND_INS_CALLNI => Ok(Mnemonic::CALLNI),
ffi::_ND_INS_CLASS::ND_INS_CALLNR => Ok(Mnemonic::CALLNR),
ffi::_ND_INS_CLASS::ND_INS_CBW => Ok(Mnemonic::CBW),
ffi::_ND_INS_CLASS::ND_INS_CCMP => Ok(Mnemonic::CCMP),
ffi::_ND_INS_CLASS::ND_INS_CDQ => Ok(Mnemonic::CDQ),
ffi::_ND_INS_CLASS::ND_INS_CDQE => Ok(Mnemonic::CDQE),
ffi::_ND_INS_CLASS::ND_INS_CFCMOV => Ok(Mnemonic::CFCMOV),
ffi::_ND_INS_CLASS::ND_INS_CLAC => Ok(Mnemonic::CLAC),
ffi::_ND_INS_CLASS::ND_INS_CLC => Ok(Mnemonic::CLC),
ffi::_ND_INS_CLASS::ND_INS_CLD => Ok(Mnemonic::CLD),
@ -1784,10 +1776,9 @@ impl TryFrom<ffi::ND_INS_CLASS> for Mnemonic {
ffi::_ND_INS_CLASS::ND_INS_COMISD => Ok(Mnemonic::COMISD),
ffi::_ND_INS_CLASS::ND_INS_COMISS => Ok(Mnemonic::COMISS),
ffi::_ND_INS_CLASS::ND_INS_CPUID => Ok(Mnemonic::CPUID),
ffi::_ND_INS_CLASS::ND_INS_CPU_READ => Ok(Mnemonic::CPU_READ),
ffi::_ND_INS_CLASS::ND_INS_CPU_WRITE => Ok(Mnemonic::CPU_WRITE),
ffi::_ND_INS_CLASS::ND_INS_CQO => Ok(Mnemonic::CQO),
ffi::_ND_INS_CLASS::ND_INS_CRC32 => Ok(Mnemonic::CRC32),
ffi::_ND_INS_CLASS::ND_INS_CTEST => Ok(Mnemonic::CTEST),
ffi::_ND_INS_CLASS::ND_INS_CVTDQ2PD => Ok(Mnemonic::CVTDQ2PD),
ffi::_ND_INS_CLASS::ND_INS_CVTDQ2PS => Ok(Mnemonic::CVTDQ2PS),
ffi::_ND_INS_CLASS::ND_INS_CVTPD2DQ => Ok(Mnemonic::CVTPD2DQ),
@ -1821,7 +1812,6 @@ impl TryFrom<ffi::ND_INS_CLASS> for Mnemonic {
ffi::_ND_INS_CLASS::ND_INS_DIVPS => Ok(Mnemonic::DIVPS),
ffi::_ND_INS_CLASS::ND_INS_DIVSD => Ok(Mnemonic::DIVSD),
ffi::_ND_INS_CLASS::ND_INS_DIVSS => Ok(Mnemonic::DIVSS),
ffi::_ND_INS_CLASS::ND_INS_DMINT => Ok(Mnemonic::DMINT),
ffi::_ND_INS_CLASS::ND_INS_DPPD => Ok(Mnemonic::DPPD),
ffi::_ND_INS_CLASS::ND_INS_DPPS => Ok(Mnemonic::DPPS),
ffi::_ND_INS_CLASS::ND_INS_EMMS => Ok(Mnemonic::EMMS),
@ -1965,6 +1955,7 @@ impl TryFrom<ffi::ND_INS_CLASS> for Mnemonic {
ffi::_ND_INS_CLASS::ND_INS_INVPCID => Ok(Mnemonic::INVPCID),
ffi::_ND_INS_CLASS::ND_INS_INVVPID => Ok(Mnemonic::INVVPID),
ffi::_ND_INS_CLASS::ND_INS_IRET => Ok(Mnemonic::IRET),
ffi::_ND_INS_CLASS::ND_INS_JMPABS => Ok(Mnemonic::JMPABS),
ffi::_ND_INS_CLASS::ND_INS_JMPE => Ok(Mnemonic::JMPE),
ffi::_ND_INS_CLASS::ND_INS_JMPFD => Ok(Mnemonic::JMPFD),
ffi::_ND_INS_CLASS::ND_INS_JMPFI => Ok(Mnemonic::JMPFI),
@ -2032,7 +2023,6 @@ impl TryFrom<ffi::ND_INS_CLASS> for Mnemonic {
ffi::_ND_INS_CLASS::ND_INS_MINSS => Ok(Mnemonic::MINSS),
ffi::_ND_INS_CLASS::ND_INS_MONITOR => Ok(Mnemonic::MONITOR),
ffi::_ND_INS_CLASS::ND_INS_MONITORX => Ok(Mnemonic::MONITORX),
ffi::_ND_INS_CLASS::ND_INS_MONTMUL => Ok(Mnemonic::MONTMUL),
ffi::_ND_INS_CLASS::ND_INS_MOV => Ok(Mnemonic::MOV),
ffi::_ND_INS_CLASS::ND_INS_MOVAPD => Ok(Mnemonic::MOVAPD),
ffi::_ND_INS_CLASS::ND_INS_MOVAPS => Ok(Mnemonic::MOVAPS),
@ -2207,10 +2197,13 @@ impl TryFrom<ffi::ND_INS_CLASS> for Mnemonic {
ffi::_ND_INS_CLASS::ND_INS_PMULLW => Ok(Mnemonic::PMULLW),
ffi::_ND_INS_CLASS::ND_INS_PMULUDQ => Ok(Mnemonic::PMULUDQ),
ffi::_ND_INS_CLASS::ND_INS_POP => Ok(Mnemonic::POP),
ffi::_ND_INS_CLASS::ND_INS_POP2 => Ok(Mnemonic::POP2),
ffi::_ND_INS_CLASS::ND_INS_POP2P => Ok(Mnemonic::POP2P),
ffi::_ND_INS_CLASS::ND_INS_POPA => Ok(Mnemonic::POPA),
ffi::_ND_INS_CLASS::ND_INS_POPAD => Ok(Mnemonic::POPAD),
ffi::_ND_INS_CLASS::ND_INS_POPCNT => Ok(Mnemonic::POPCNT),
ffi::_ND_INS_CLASS::ND_INS_POPF => Ok(Mnemonic::POPF),
ffi::_ND_INS_CLASS::ND_INS_POPP => Ok(Mnemonic::POPP),
ffi::_ND_INS_CLASS::ND_INS_POR => Ok(Mnemonic::POR),
ffi::_ND_INS_CLASS::ND_INS_PREFETCH => Ok(Mnemonic::PREFETCH),
ffi::_ND_INS_CLASS::ND_INS_PREFETCHE => Ok(Mnemonic::PREFETCHE),
@ -2263,9 +2256,12 @@ impl TryFrom<ffi::ND_INS_CLASS> for Mnemonic {
ffi::_ND_INS_CLASS::ND_INS_PUNPCKLQDQ => Ok(Mnemonic::PUNPCKLQDQ),
ffi::_ND_INS_CLASS::ND_INS_PUNPCKLWD => Ok(Mnemonic::PUNPCKLWD),
ffi::_ND_INS_CLASS::ND_INS_PUSH => Ok(Mnemonic::PUSH),
ffi::_ND_INS_CLASS::ND_INS_PUSH2 => Ok(Mnemonic::PUSH2),
ffi::_ND_INS_CLASS::ND_INS_PUSH2P => Ok(Mnemonic::PUSH2P),
ffi::_ND_INS_CLASS::ND_INS_PUSHA => Ok(Mnemonic::PUSHA),
ffi::_ND_INS_CLASS::ND_INS_PUSHAD => Ok(Mnemonic::PUSHAD),
ffi::_ND_INS_CLASS::ND_INS_PUSHF => Ok(Mnemonic::PUSHF),
ffi::_ND_INS_CLASS::ND_INS_PUSHP => Ok(Mnemonic::PUSHP),
ffi::_ND_INS_CLASS::ND_INS_PVALIDATE => Ok(Mnemonic::PVALIDATE),
ffi::_ND_INS_CLASS::ND_INS_PXOR => Ok(Mnemonic::PXOR),
ffi::_ND_INS_CLASS::ND_INS_RCL => Ok(Mnemonic::RCL),
@ -2282,7 +2278,6 @@ impl TryFrom<ffi::ND_INS_CLASS> for Mnemonic {
ffi::_ND_INS_CLASS::ND_INS_RDPRU => Ok(Mnemonic::RDPRU),
ffi::_ND_INS_CLASS::ND_INS_RDRAND => Ok(Mnemonic::RDRAND),
ffi::_ND_INS_CLASS::ND_INS_RDSEED => Ok(Mnemonic::RDSEED),
ffi::_ND_INS_CLASS::ND_INS_RDSHR => Ok(Mnemonic::RDSHR),
ffi::_ND_INS_CLASS::ND_INS_RDTSC => Ok(Mnemonic::RDTSC),
ffi::_ND_INS_CLASS::ND_INS_RDTSCP => Ok(Mnemonic::RDTSCP),
ffi::_ND_INS_CLASS::ND_INS_RETF => Ok(Mnemonic::RETF),
@ -2297,14 +2292,11 @@ impl TryFrom<ffi::ND_INS_CLASS> for Mnemonic {
ffi::_ND_INS_CLASS::ND_INS_ROUNDPS => Ok(Mnemonic::ROUNDPS),
ffi::_ND_INS_CLASS::ND_INS_ROUNDSD => Ok(Mnemonic::ROUNDSD),
ffi::_ND_INS_CLASS::ND_INS_ROUNDSS => Ok(Mnemonic::ROUNDSS),
ffi::_ND_INS_CLASS::ND_INS_RSDC => Ok(Mnemonic::RSDC),
ffi::_ND_INS_CLASS::ND_INS_RSLDT => Ok(Mnemonic::RSLDT),
ffi::_ND_INS_CLASS::ND_INS_RSM => Ok(Mnemonic::RSM),
ffi::_ND_INS_CLASS::ND_INS_RSQRTPS => Ok(Mnemonic::RSQRTPS),
ffi::_ND_INS_CLASS::ND_INS_RSQRTSS => Ok(Mnemonic::RSQRTSS),
ffi::_ND_INS_CLASS::ND_INS_RSSSP => Ok(Mnemonic::RSSSP),
ffi::_ND_INS_CLASS::ND_INS_RSTORSSP => Ok(Mnemonic::RSTORSSP),
ffi::_ND_INS_CLASS::ND_INS_RSTS => Ok(Mnemonic::RSTS),
ffi::_ND_INS_CLASS::ND_INS_SAHF => Ok(Mnemonic::SAHF),
ffi::_ND_INS_CLASS::ND_INS_SAL => Ok(Mnemonic::SAL),
ffi::_ND_INS_CLASS::ND_INS_SALC => Ok(Mnemonic::SALC),
@ -2341,7 +2333,6 @@ impl TryFrom<ffi::ND_INS_CLASS> for Mnemonic {
ffi::_ND_INS_CLASS::ND_INS_SKINIT => Ok(Mnemonic::SKINIT),
ffi::_ND_INS_CLASS::ND_INS_SLDT => Ok(Mnemonic::SLDT),
ffi::_ND_INS_CLASS::ND_INS_SLWPCB => Ok(Mnemonic::SLWPCB),
ffi::_ND_INS_CLASS::ND_INS_SMINT => Ok(Mnemonic::SMINT),
ffi::_ND_INS_CLASS::ND_INS_SMSW => Ok(Mnemonic::SMSW),
ffi::_ND_INS_CLASS::ND_INS_SPFLT => Ok(Mnemonic::SPFLT),
ffi::_ND_INS_CLASS::ND_INS_SQRTPD => Ok(Mnemonic::SQRTPD),
@ -2363,9 +2354,6 @@ impl TryFrom<ffi::ND_INS_CLASS> for Mnemonic {
ffi::_ND_INS_CLASS::ND_INS_SUBPS => Ok(Mnemonic::SUBPS),
ffi::_ND_INS_CLASS::ND_INS_SUBSD => Ok(Mnemonic::SUBSD),
ffi::_ND_INS_CLASS::ND_INS_SUBSS => Ok(Mnemonic::SUBSS),
ffi::_ND_INS_CLASS::ND_INS_SVDC => Ok(Mnemonic::SVDC),
ffi::_ND_INS_CLASS::ND_INS_SVLDT => Ok(Mnemonic::SVLDT),
ffi::_ND_INS_CLASS::ND_INS_SVTS => Ok(Mnemonic::SVTS),
ffi::_ND_INS_CLASS::ND_INS_SWAPGS => Ok(Mnemonic::SWAPGS),
ffi::_ND_INS_CLASS::ND_INS_SYSCALL => Ok(Mnemonic::SYSCALL),
ffi::_ND_INS_CLASS::ND_INS_SYSENTER => Ok(Mnemonic::SYSENTER),
@ -2404,6 +2392,8 @@ impl TryFrom<ffi::ND_INS_CLASS> for Mnemonic {
ffi::_ND_INS_CLASS::ND_INS_UNPCKHPS => Ok(Mnemonic::UNPCKHPS),
ffi::_ND_INS_CLASS::ND_INS_UNPCKLPD => Ok(Mnemonic::UNPCKLPD),
ffi::_ND_INS_CLASS::ND_INS_UNPCKLPS => Ok(Mnemonic::UNPCKLPS),
ffi::_ND_INS_CLASS::ND_INS_URDMSR => Ok(Mnemonic::URDMSR),
ffi::_ND_INS_CLASS::ND_INS_UWRMSR => Ok(Mnemonic::UWRMSR),
ffi::_ND_INS_CLASS::ND_INS_V4FMADDPS => Ok(Mnemonic::V4FMADDPS),
ffi::_ND_INS_CLASS::ND_INS_V4FMADDSS => Ok(Mnemonic::V4FMADDSS),
ffi::_ND_INS_CLASS::ND_INS_V4FNMADDPS => Ok(Mnemonic::V4FNMADDPS),
@ -3271,18 +3261,12 @@ impl TryFrom<ffi::ND_INS_CLASS> for Mnemonic {
ffi::_ND_INS_CLASS::ND_INS_WRMSRLIST => Ok(Mnemonic::WRMSRLIST),
ffi::_ND_INS_CLASS::ND_INS_WRMSRNS => Ok(Mnemonic::WRMSRNS),
ffi::_ND_INS_CLASS::ND_INS_WRPKRU => Ok(Mnemonic::WRPKRU),
ffi::_ND_INS_CLASS::ND_INS_WRSHR => Ok(Mnemonic::WRSHR),
ffi::_ND_INS_CLASS::ND_INS_WRSS => Ok(Mnemonic::WRSS),
ffi::_ND_INS_CLASS::ND_INS_WRUSS => Ok(Mnemonic::WRUSS),
ffi::_ND_INS_CLASS::ND_INS_XABORT => Ok(Mnemonic::XABORT),
ffi::_ND_INS_CLASS::ND_INS_XADD => Ok(Mnemonic::XADD),
ffi::_ND_INS_CLASS::ND_INS_XBEGIN => Ok(Mnemonic::XBEGIN),
ffi::_ND_INS_CLASS::ND_INS_XCHG => Ok(Mnemonic::XCHG),
ffi::_ND_INS_CLASS::ND_INS_XCRYPTCBC => Ok(Mnemonic::XCRYPTCBC),
ffi::_ND_INS_CLASS::ND_INS_XCRYPTCFB => Ok(Mnemonic::XCRYPTCFB),
ffi::_ND_INS_CLASS::ND_INS_XCRYPTCTR => Ok(Mnemonic::XCRYPTCTR),
ffi::_ND_INS_CLASS::ND_INS_XCRYPTECB => Ok(Mnemonic::XCRYPTECB),
ffi::_ND_INS_CLASS::ND_INS_XCRYPTOFB => Ok(Mnemonic::XCRYPTOFB),
ffi::_ND_INS_CLASS::ND_INS_XEND => Ok(Mnemonic::XEND),
ffi::_ND_INS_CLASS::ND_INS_XGETBV => Ok(Mnemonic::XGETBV),
ffi::_ND_INS_CLASS::ND_INS_XLATB => Ok(Mnemonic::XLATB),
@ -3297,9 +3281,6 @@ impl TryFrom<ffi::ND_INS_CLASS> for Mnemonic {
ffi::_ND_INS_CLASS::ND_INS_XSAVEOPT => Ok(Mnemonic::XSAVEOPT),
ffi::_ND_INS_CLASS::ND_INS_XSAVES => Ok(Mnemonic::XSAVES),
ffi::_ND_INS_CLASS::ND_INS_XSETBV => Ok(Mnemonic::XSETBV),
ffi::_ND_INS_CLASS::ND_INS_XSHA1 => Ok(Mnemonic::XSHA1),
ffi::_ND_INS_CLASS::ND_INS_XSHA256 => Ok(Mnemonic::XSHA256),
ffi::_ND_INS_CLASS::ND_INS_XSTORE => Ok(Mnemonic::XSTORE),
ffi::_ND_INS_CLASS::ND_INS_XSUSLDTRK => Ok(Mnemonic::XSUSLDTRK),
ffi::_ND_INS_CLASS::ND_INS_XTEST => Ok(Mnemonic::XTEST),
}

@ -29,10 +29,6 @@ impl OpAddr {
offset: raw.Offset,
}
}
pub(crate) fn new(base_seg: u16, offset: u64) -> Self {
Self { base_seg, offset }
}
}
/// The type of a register.
@ -188,7 +184,7 @@ pub struct OpReg {
///
/// # Remarks
///
/// If [kind](OpReg::kind) is [OpRegType::Gpr](OpRegType::Gpr), the high and low part of 16-bit registers will have
/// If [kind](OpReg::kind) is [`OpRegType::Gpr`], the high and low part of 16-bit registers will have
/// the same index (for example, `AH` and `AL`). To differentiate between them use [is_high8](OpReg::is_high8).
pub index: usize,
@ -223,7 +219,7 @@ impl OpReg {
kind,
size: raw.Size,
index,
count: raw.Count,
count: raw.Count as u32,
is_high8,
is_block: raw.IsBlock() != 0,
})
@ -279,6 +275,7 @@ impl ShadowStackAccess {
}
/// Describes a memory operand.
#[allow(clippy::struct_excessive_bools)]
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
pub struct OpMem {
/// `true` if the memory operand is a broadcast operand.
@ -353,19 +350,23 @@ pub struct OpMem {
impl OpMem {
pub(crate) fn from_raw(raw: ffi::ND_OPDESC_MEMORY) -> Result<Self, DecodeError> {
let seg = if raw.HasSeg() != 0 {
Some(raw.Seg)
Some(raw.Seg())
} else {
None
};
let (base, base_size) = if raw.HasBase() != 0 {
(Some(raw.Base), Some(raw.BaseSize))
(Some(raw.Base()), Some(raw.BaseSize as u32))
} else {
(None, None)
};
let (index, index_size, scale) = if raw.HasIndex() != 0 {
(Some(raw.Index), Some(raw.IndexSize), Some(raw.Scale))
(
Some(raw.Index),
Some(raw.IndexSize as u32),
Some(raw.Scale()),
)
} else {
(None, None, None)
};
@ -385,10 +386,10 @@ impl OpMem {
let (vsib, index_size) = if raw.IsVsib() != 0 {
(
Some(Vsib {
vsib_element_size: raw.Vsib.ElemSize,
vsib_element_count: raw.Vsib.ElemCount,
vsib_element_size: unsafe { raw.__bindgen_anon_1.Vsib.ElemSize },
vsib_element_count: unsafe { raw.__bindgen_anon_1.Vsib.ElemCount },
}),
Some(raw.Vsib.IndexSize.into()),
Some(unsafe { raw.__bindgen_anon_1.Vsib.IndexSize.into() }),
)
} else {
(None, index_size)
@ -460,7 +461,9 @@ impl Default for OpInfo {
}
impl OpInfo {
/// Returns the associated [OpReg](OpReg) for register operands. Returns [`None`] otherwise.
/// Returns the associated [`OpReg`] for register operands. Returns [`None`] otherwise.
#[inline]
#[must_use]
pub fn as_reg(&self) -> Option<&OpReg> {
if let OpInfo::Reg(o) = self {
Some(o)
@ -469,7 +472,9 @@ impl OpInfo {
}
}
/// Returns the associated [OpMem](OpMem) for memory operands. Returns [`None`] otherwise.
/// Returns the associated [`OpMem`] for memory operands. Returns [`None`] otherwise.
#[inline]
#[must_use]
pub fn as_mem(&self) -> Option<&OpMem> {
if let OpInfo::Mem(o) = self {
Some(o)
@ -479,6 +484,8 @@ impl OpInfo {
}
/// Returns the associated immediate value for immediate operands. Returns [`None`] otherwise.
#[inline]
#[must_use]
pub fn as_imm(&self) -> Option<u64> {
if let OpInfo::Imm(o) = self {
Some(*o)
@ -487,7 +494,9 @@ impl OpInfo {
}
}
/// Returns the associated [OpAddr](OpAddr) for absolute address operands. Returns [`None`] otherwise.
/// Returns the associated [`OpAddr`] for absolute address operands. Returns [`None`] otherwise.
#[inline]
#[must_use]
pub fn as_addr(&self) -> Option<&OpAddr> {
if let OpInfo::Addr(o) = self {
Some(o)
@ -497,6 +506,8 @@ impl OpInfo {
}
/// Returns the associated constant value for constant operands. Returns [`None`] otherwise.
#[inline]
#[must_use]
pub fn as_const(&self) -> Option<u64> {
if let OpInfo::Const(o) = self {
Some(*o)
@ -506,6 +517,8 @@ impl OpInfo {
}
/// Returns `Some` for bank operands. Returns [`None`] otherwise.
#[inline]
#[must_use]
pub fn as_bank(&self) -> Option<()> {
if let OpInfo::Bank = self {
Some(())
@ -515,31 +528,43 @@ impl OpInfo {
}
/// Returns `true` for register operands. Returns `false` otherwise.
#[inline]
#[must_use]
pub fn is_reg(&self) -> bool {
self.as_reg().is_some()
}
/// Returns `true` for memory operands. Returns `false` otherwise.
#[inline]
#[must_use]
pub fn is_mem(&self) -> bool {
self.as_mem().is_some()
}
/// Returns `true` for immediate operands. Returns `false` otherwise.
#[inline]
#[must_use]
pub fn is_imm(&self) -> bool {
self.as_imm().is_some()
}
/// Returns `true` for absolute address operands. Returns `false` otherwise.
#[inline]
#[must_use]
pub fn is_addr(&self) -> bool {
self.as_addr().is_some()
}
/// Returns `true` for constant operands. Returns `false` otherwise.
#[inline]
#[must_use]
pub fn is_const(&self) -> bool {
self.as_const().is_some()
}
/// Returns `true` for bank operands. Returns `false` otherwise.
#[inline]
#[must_use]
pub fn is_bank(&self) -> bool {
self.as_bank().is_some()
}
@ -548,25 +573,26 @@ impl OpInfo {
#[doc(hidden)]
impl OpInfo {
pub(crate) fn from_raw(raw: ffi::ND_OPERAND) -> Result<Self, DecodeError> {
match raw.Type {
ffi::_ND_OPERAND_TYPE::ND_OP_NOT_PRESENT => Ok(OpInfo::None),
ffi::_ND_OPERAND_TYPE::ND_OP_REG => {
Ok(OpInfo::Reg(OpReg::from_raw(unsafe { raw.Info.Register })?))
}
ffi::_ND_OPERAND_TYPE::ND_OP_MEM => {
Ok(OpInfo::Mem(OpMem::from_raw(unsafe { raw.Info.Memory })?))
}
ffi::_ND_OPERAND_TYPE::ND_OP_IMM => Ok(OpInfo::Imm(unsafe { raw.Info.Immediate }.Imm)),
ffi::_ND_OPERAND_TYPE::ND_OP_OFFS => {
Ok(OpInfo::Offs(unsafe { raw.Info.RelativeOffset }.Rel))
}
ffi::_ND_OPERAND_TYPE::ND_OP_ADDR => {
Ok(OpInfo::Addr(OpAddr::from_raw(unsafe { raw.Info.Address })))
}
ffi::_ND_OPERAND_TYPE::ND_OP_CONST => {
Ok(OpInfo::Const(unsafe { raw.Info.Constant }.Const))
}
ffi::_ND_OPERAND_TYPE::ND_OP_BANK => Ok(OpInfo::Bank),
let typ = raw.Type() as i32;
if typ == ffi::_ND_OPERAND_TYPE::ND_OP_NOT_PRESENT as i32 {
Ok(OpInfo::None)
} else if typ == ffi::_ND_OPERAND_TYPE::ND_OP_REG as i32 {
Ok(OpInfo::Reg(OpReg::from_raw(unsafe { raw.Info.Register })?))
} else if typ == ffi::_ND_OPERAND_TYPE::ND_OP_MEM as i32 {
Ok(OpInfo::Mem(OpMem::from_raw(unsafe { raw.Info.Memory })?))
} else if typ == ffi::_ND_OPERAND_TYPE::ND_OP_IMM as i32 {
Ok(OpInfo::Imm(unsafe { raw.Info.Immediate }.Imm))
} else if typ == ffi::_ND_OPERAND_TYPE::ND_OP_OFFS as i32 {
Ok(OpInfo::Offs(unsafe { raw.Info.RelativeOffset }.Rel))
} else if typ == ffi::_ND_OPERAND_TYPE::ND_OP_ADDR as i32 {
Ok(OpInfo::Addr(OpAddr::from_raw(unsafe { raw.Info.Address })))
} else if typ == ffi::_ND_OPERAND_TYPE::ND_OP_CONST as i32 {
Ok(OpInfo::Const(unsafe { raw.Info.Constant }.Const))
} else if typ == ffi::_ND_OPERAND_TYPE::ND_OP_BANK as i32 {
Ok(OpInfo::Bank)
} else {
Err(DecodeError::InternalError(0))
}
}
}
@ -620,7 +646,6 @@ impl fmt::Display for OpSize {
impl OpSize {
pub(crate) fn from_raw(value: ffi::ND_OPERAND_SIZE) -> Result<Self, DecodeError> {
match value {
0 => Ok(OpSize::Bytes(0)),
ffi::ND_SIZE_8BIT => Ok(OpSize::Bytes(1)),
ffi::ND_SIZE_16BIT => Ok(OpSize::Bytes(2)),
ffi::ND_SIZE_32BIT => Ok(OpSize::Bytes(4)),
@ -645,6 +670,7 @@ impl OpSize {
}
/// Operand access mode.
#[allow(clippy::struct_excessive_bools)]
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Default)]
pub struct OpAccess {
/// The operand is read.
@ -701,32 +727,6 @@ pub struct Decorator {
pub broadcast: Option<Broadcast>,
}
#[doc(hidden)]
impl Decorator {
pub(crate) fn from_raw(raw: ffi::ND_OPERAND_DECORATOR) -> Decorator {
let mask_register = if raw.HasMask() != 0 {
Some(raw.Mask.Msk)
} else {
None
};
let broadcast = if raw.HasBroadcast() != 0 {
Some(Broadcast {
count: raw.Broadcast.Count,
size: raw.Broadcast.Size,
})
} else {
None
};
Self {
mask_register,
has_zero: raw.HasZero() != 0,
broadcast,
}
}
}
/// Describes an instruction operand.
///
/// Each operand type encodes different information. See [`OpInfo`] for details.
@ -775,23 +775,11 @@ pub struct Operand {
/// cases.
pub size: OpSize,
/// Raw size inside the instruction.
///
/// This will usually be identical to [size](Operand::size), however, some instructions force the actual size of
/// their operands to 64 bit (`PUSH`/`POP` or branches are good examples).
///
/// Although the raw size of the relative offset or the immediate will be [raw_size](Operand::raw_size), internally,
/// the CPU will use [size](Operand::size) (usually sign-extended).
pub raw_size: OpSize,
/// Access mode.
pub access: OpAccess,
/// `true` if the operand is default. This also applies to implicit operands.
pub is_default: bool,
/// Decorator information.
pub decorator: Decorator,
}
#[doc(hidden)]
@ -800,10 +788,8 @@ impl Operand {
Ok(Self {
info: OpInfo::from_raw(raw)?,
size: OpSize::from_raw(raw.Size)?,
raw_size: OpSize::from_raw(raw.RawSize)?,
access: OpAccess::from_raw(raw.Access),
is_default: unsafe { raw.Flags.__bindgen_anon_1 }.IsDefault() != 0,
decorator: Decorator::from_raw(raw.Decorator),
})
}
}
@ -932,6 +918,7 @@ impl<'a> OperandsLookup<'a> {
/// This function will panic if the result of the C library is unrecognized. This can not happen under normal
/// circumstances.
#[inline]
#[must_use]
pub fn dest(&self, index: usize) -> Option<Operand> {
let op = match index {
0 => unsafe { self.op_rlut.Dst1.as_ref() },
@ -961,6 +948,7 @@ impl<'a> OperandsLookup<'a> {
/// This function will panic if the result of the C library is unrecognized. This can not happen under normal
/// circumstances.
#[inline]
#[must_use]
pub fn src(&self, index: usize) -> Option<Operand> {
let op = match index {
0 => unsafe { self.op_rlut.Src1.as_ref() },
@ -991,6 +979,7 @@ impl<'a> OperandsLookup<'a> {
/// This function will panic if the result of the C library is unrecognized. This can not happen under normal
/// circumstances.
#[inline]
#[must_use]
pub fn mem(&self, index: usize) -> Option<Operand> {
let op = match index {
0 => unsafe { self.op_rlut.Mem1.as_ref() },
@ -1013,6 +1002,7 @@ impl<'a> OperandsLookup<'a> {
/// This function will panic if the result of the C library is unrecognized. This can not happen under normal
/// circumstances.
#[inline]
#[must_use]
pub fn stack(&self) -> Option<Operand> {
let op = unsafe { self.op_rlut.Stack.as_ref() };
@ -1031,6 +1021,7 @@ impl<'a> OperandsLookup<'a> {
/// This function will panic if the result of the C library is unrecognized. This can not happen under normal
/// circumstances.
#[inline]
#[must_use]
pub fn flags(&self) -> Option<Operand> {
let op = unsafe { self.op_rlut.Flags.as_ref() };
@ -1049,6 +1040,7 @@ impl<'a> OperandsLookup<'a> {
/// This function will panic if the result of the C library is unrecognized. This can not happen under normal
/// circumstances.
#[inline]
#[must_use]
pub fn rip(&self) -> Option<Operand> {
let op = unsafe { self.op_rlut.Rip.as_ref() };
@ -1067,6 +1059,7 @@ impl<'a> OperandsLookup<'a> {
/// This function will panic if the result of the C library is unrecognized. This can not happen under normal
/// circumstances.
#[inline]
#[must_use]
pub fn cs(&self) -> Option<Operand> {
let op = unsafe { self.op_rlut.Cs.as_ref() };
@ -1085,6 +1078,7 @@ impl<'a> OperandsLookup<'a> {
/// This function will panic if the result of the C library is unrecognized. This can not happen under normal
/// circumstances.
#[inline]
#[must_use]
pub fn ss(&self) -> Option<Operand> {
let op = unsafe { self.op_rlut.Ss.as_ref() };
@ -1103,6 +1097,7 @@ impl<'a> OperandsLookup<'a> {
/// This function will panic if the result of the C library is unrecognized. This can not happen under normal
/// circumstances.
#[inline]
#[must_use]
pub fn rax(&self) -> Option<Operand> {
let op = unsafe { self.op_rlut.Rax.as_ref() };
@ -1121,6 +1116,7 @@ impl<'a> OperandsLookup<'a> {
/// This function will panic if the result of the C library is unrecognized. This can not happen under normal
/// circumstances.
#[inline]
#[must_use]
pub fn rcx(&self) -> Option<Operand> {
let op = unsafe { self.op_rlut.Rcx.as_ref() };
@ -1139,6 +1135,7 @@ impl<'a> OperandsLookup<'a> {
/// This function will panic if the result of the C library is unrecognized. This can not happen under normal
/// circumstances.
#[inline]
#[must_use]
pub fn rdx(&self) -> Option<Operand> {
let op = unsafe { self.op_rlut.Rdx.as_ref() };
@ -1157,6 +1154,7 @@ impl<'a> OperandsLookup<'a> {
/// This function will panic if the result of the C library is unrecognized. This can not happen under normal
/// circumstances.
#[inline]
#[must_use]
pub fn rbx(&self) -> Option<Operand> {
let op = unsafe { self.op_rlut.Rbx.as_ref() };
@ -1175,6 +1173,7 @@ impl<'a> OperandsLookup<'a> {
/// This function will panic if the result of the C library is unrecognized. This can not happen under normal
/// circumstances.
#[inline]
#[must_use]
pub fn rsp(&self) -> Option<Operand> {
let op = unsafe { self.op_rlut.Rsp.as_ref() };
@ -1193,6 +1192,7 @@ impl<'a> OperandsLookup<'a> {
/// This function will panic if the result of the C library is unrecognized. This can not happen under normal
/// circumstances.
#[inline]
#[must_use]
pub fn rbp(&self) -> Option<Operand> {
let op = unsafe { self.op_rlut.Rbp.as_ref() };
@ -1211,6 +1211,7 @@ impl<'a> OperandsLookup<'a> {
/// This function will panic if the result of the C library is unrecognized. This can not happen under normal
/// circumstances.
#[inline]
#[must_use]
pub fn rsi(&self) -> Option<Operand> {
let op = unsafe { self.op_rlut.Rsi.as_ref() };
@ -1229,6 +1230,7 @@ impl<'a> OperandsLookup<'a> {
/// This function will panic if the result of the C library is unrecognized. This can not happen under normal
/// circumstances.
#[inline]
#[must_use]
pub fn rdi(&self) -> Option<Operand> {
let op = unsafe { self.op_rlut.Rdi.as_ref() };
@ -1236,7 +1238,7 @@ impl<'a> OperandsLookup<'a> {
}
}
/// A collection of [Operand](Operand)s.
/// A collection of [`Operand`]s.
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Default)]
pub struct Operands {
pub(crate) operands: [Operand; 10],
@ -1266,7 +1268,6 @@ mod tests {
let dest = operands[0];
assert_eq!(dest.size, OpSize::Bytes(1));
assert_eq!(dest.raw_size, OpSize::Bytes(1));
assert_eq!(dest.is_default, false);
assert!(dest.access.write);
@ -1281,7 +1282,6 @@ mod tests {
let src = operands[1];
assert_eq!(src.size, OpSize::Bytes(1));
assert_eq!(src.raw_size, OpSize::Bytes(1));
assert_eq!(src.is_default, false);
assert!(src.access.read);

@ -0,0 +1,198 @@
import os
import subprocess
import sys
from pathlib import Path
from git import Repo
repo = Repo(search_parent_directories=True)
root = Path(repo.working_tree_dir)
print(f"Repo root: {root}")
hdr_dirs = root / "inc"
x86_constants = hdr_dirs / "bdx86_constants.h"
print(f"Looking for enums in {x86_constants}")
with open(x86_constants, "r") as data:
nd_ins = []
nd_ins_set = []
nd_ins_type = []
for line in data:
if "INVALID" in line:
continue
if line.startswith(" ND_CAT_"):
token = line.replace(',', '').strip()
nd_ins_type.append(token)
continue
if line.startswith(" ND_SET_"):
token = line.replace(',', '').strip()
nd_ins_set.append(token)
continue
if line.startswith(" ND_INS_"):
token = line.replace(',', '').strip()
nd_ins.append(token)
continue
print(f"ND_INS_: {len(nd_ins)} ND_SET_: {len(nd_ins_set)} ND_CAT_: {len(nd_ins_type)}")
bindings = root / "bindings/rsbddisasm/bddisasm/src"
mnemonic = bindings / "mnemonic.rs"
ins_cat = bindings / "instruction_category.rs"
isa_set = bindings / "isa_set.rs"
license_header = """
/*
* Copyright (c) 2021 Bitdefender
* SPDX-License-Identifier: Apache-2.0
*/
"""
print(f"Generating {mnemonic}")
with open(mnemonic, "w") as fmnemonic:
fmnemonic.write(license_header)
fmnemonic.write("//! Mnemonics.\n")
fmnemonic.write("\n")
fmnemonic.write("use super::decode_error::DecodeError;\n")
fmnemonic.write("use core::convert::TryFrom;\n")
mnemonic_enum_def = """
/// Uniquely identifies an instruction.
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
#[allow(non_camel_case_types)]
pub enum Mnemonic {
"""
fmnemonic.write(mnemonic_enum_def)
for ins in nd_ins:
line = ins.replace("ND_INS_", "")
fmnemonic.write(f"{line},\n")
fmnemonic.write("}\n")
try_from = """
#[doc(hidden)]
impl TryFrom<ffi::ND_INS_CLASS> for Mnemonic {
type Error = DecodeError;
#[allow(clippy::too_many_lines)]
fn try_from(value: ffi::ND_INS_CLASS) -> Result<Self, Self::Error> {
match value {
ffi::_ND_INS_CLASS::ND_INS_INVALID => Err(DecodeError::InternalError(value as u64)),
"""
fmnemonic.write(try_from)
for ins in nd_ins:
line = f"ffi::_ND_INS_CLASS::{ins} => Ok(Mnemonic::{ins.replace('ND_INS_', '')}),\n"
fmnemonic.write(line)
end = """
}
}
}
"""
fmnemonic.write(end)
print(f"Generating {ins_cat}")
with open(ins_cat, "w") as finscat:
finscat.write(license_header)
finscat.write("//! Instruction categories.\n")
finscat.write("\n")
finscat.write("use super::decode_error::DecodeError;\n")
finscat.write("use core::convert::TryFrom;\n")
ins_cat_enum_def = """
/// Instruction category.
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
#[allow(non_camel_case_types)]
pub enum Category {
"""
finscat.write(ins_cat_enum_def)
for ins in nd_ins_type:
line = ins.replace("ND_CAT_", "")
if line[0].isdigit():
line = f"I{line}"
finscat.write(f"{line},\n")
finscat.write("}\n")
try_from = """
#[doc(hidden)]
impl TryFrom<ffi::ND_INS_CATEGORY> for Category {
type Error = DecodeError;
#[allow(clippy::too_many_lines)]
fn try_from(value: ffi::ND_INS_CATEGORY) -> Result<Self, Self::Error> {
match value {
ffi::_ND_INS_TYPE::ND_CAT_INVALID => Err(DecodeError::InternalError(value as u64)),
"""
finscat.write(try_from)
for ins in nd_ins_type:
ok = ins.replace('ND_CAT_', '')
if ok[0].isdigit():
ok = f"I{ok}"
line = f"ffi::_ND_INS_TYPE::{ins} => Ok(Category::{ok}),\n"
finscat.write(line)
end = """
}
}
}
"""
finscat.write(end)
print(f"Generating {isa_set}")
with open(isa_set, "w") as fset:
fset.write(license_header)
fset.write("//! Instruction sets.\n")
fset.write("\n")
fset.write("use super::decode_error::DecodeError;\n")
fset.write("use core::convert::TryFrom;\n")
ins_set_enum_def = """
/// ISA set.
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
#[allow(non_camel_case_types)]
pub enum IsaSet {
"""
fset.write(ins_set_enum_def)
for ins in nd_ins_set:
line = ins.replace("ND_SET_", "")
if line[0].isdigit():
line = f"I{line}"
fset.write(f"{line},\n")
fset.write("}\n")
try_from = """
#[doc(hidden)]
impl TryFrom<ffi::ND_INS_SET> for IsaSet {
type Error = DecodeError;
#[allow(clippy::too_many_lines)]
fn try_from(value: ffi::ND_INS_SET) -> Result<Self, Self::Error> {
match value {
ffi::_ND_INS_SET::ND_SET_INVALID => Err(DecodeError::InternalError(value as u64)),
"""
fset.write(try_from)
for ins in nd_ins_set:
ok = ins.replace('ND_SET_', '')
if ok[0].isdigit():
ok = f"I{ok}"
line = f"ffi::_ND_INS_SET::{ins} => Ok(IsaSet::{ok}),\n"
fset.write(line)
end = """
}
}
}
"""
fset.write(end)
subprocess.check_output(["cargo", "fmt"])

@ -50,9 +50,7 @@ else ()
-Wno-unused-function
-Wno-multichar
-Wno-incompatible-pointer-types
-Wno-discarded-qualifiers
-Wnull-dereference
-Wduplicated-cond
-Werror=implicit-function-declaration
-pipe
-fwrapv
@ -65,4 +63,10 @@ else ()
-gdwarf-4
-grecord-gcc-switches
-march=westmere)
if (CMAKE_C_COMPILER_ID STREQUAL "GNU")
target_compile_options(
disasmtool
PRIVATE -Wno-discarded-qualifiers
-Wduplicated-cond)
endif ()
endif ()

File diff suppressed because it is too large Load Diff

@ -5,6 +5,24 @@
#ifndef DISASMTOOL_H
#define DISASMTOOL_H
#include <stdbool.h>
#include <stdint.h>
#ifndef WIN32
#define _In_
#define _Inout_
#define _Out_
#define _Success_(x)
typedef char CHAR, *PCHAR;
typedef unsigned char BYTE, *PBYTE;
typedef int32_t INT32;
typedef uint32_t DWORD;
#define UNREFERENCED_PARAMETER(P) (void)(P)
#define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0]))
#endif // !WIN32
typedef enum _DISASM_COMMAND
{
@ -29,26 +47,24 @@ typedef struct _DISASM_OPTIONS
size_t Size; // Buffer size.
size_t Offset; // Offset inside the buffer.
size_t Rip; // Virtual RIP.
BOOLEAN Highlight; // Highlight instruction components, if true.
BOOLEAN ExtendedInfo; // Display extended instruction info, if true.
BOOLEAN BitFields; // Display the various bitfields inside the instruction, if true.
BOOLEAN Skip16; // Automatically jump over 16 bytes after each instruction.
BOOLEAN Stats; // Display disassembly stats (clocks / instruction, instructions / second), if true.
BOOLEAN Print; // Print instruction disassembly, if true.
bool Highlight; // Highlight instruction components, if true.
bool ExtendedInfo; // Display extended instruction info, if true.
bool BitFields; // Display the various bitfields inside the instruction, if true.
bool Skip16; // Automatically jump over 16 bytes after each instruction.
bool Skip1; // Automatically jump over one single byte after each instruction.
bool Stats; // Display disassembly stats (clocks / instruction, instructions / second), if true.
bool Print; // Print instruction disassembly, if true.
uint8_t Mode; // Mode - 16, 32 or 64-bit mode.
uint8_t Ring; // Ring - 0, 1, 2 or 3.
uint8_t Vendor; // Preffered vendor.
uint8_t Feature; // Used features.
char *FileName; // Input file, if any.
size_t ShemuRegs[ND_MAX_GPR_REGS];
BOOLEAN UseShemuRegs; // If truue, the registers in ShemuRegs will be used for shemu input.
BOOLEAN BypassSelfWrites; // If true, shemu emulation will ignore self-modifications made by the shellcode.
bool UseShemuRegs; // If truue, the registers in ShemuRegs will be used for shemu input.
bool BypassSelfWrites; // If true, shemu emulation will ignore self-modifications made by the shellcode.
// Internal.
INPUT_MODE InputMode;
HANDLE HandleFile;
HANDLE HandleMapping;
} DISASM_OPTIONS, *PDISASM_OPTIONS;

@ -1,65 +0,0 @@
cmake_minimum_required(VERSION 3.16)
project(disasmtool LANGUAGES CXX)
# Use Release as the build type if no build type was specified and we're not using a multi-config generator .
if (NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
message(STATUS "No build type given. Will use 'Release'")
set(CMAKE_BUILD_TYPE
"Release"
CACHE STRING "Choose the type of build." FORCE)
# Set the possible values of build type for cmake-gui.
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release")
endif ()
add_executable(disasmtool disasmtool.cpp dumpers.cpp rapidjson.cpp)
target_compile_options(
disasmtool
PRIVATE "$<$<CONFIG:Release>:-U_FORTIFY_SOURCE>"
"$<$<CONFIG:Release>:-D_FORTIFY_SOURCE=2>"
-Wall
-Wextra
-Wshadow
-Wformat-security
-Wstrict-overflow=2
-Wno-unused-function
-Wno-multichar
-Werror=format-security
-pipe
-fpie
-fwrapv
-fno-strict-aliasing
-fstack-protector-strong
-ffunction-sections
-fdata-sections
-g3
-gdwarf-4
-grecord-gcc-switches
-march=nehalem
-fno-omit-frame-pointer)
if (NOT TARGET bddisasm)
find_package(bddisasm REQUIRED)
endif ()
find_package(RapidJSON QUIET REQUIRED)
target_link_libraries(disasmtool PRIVATE bddisasm::bddisasm bddisasm::bdshemu)
# :( https://github.com/satishbabariya/modern-cmake#good-boys-export-their-targets
target_include_directories(disasmtool PRIVATE ${RapidJSON_INCLUDE_DIRS})
if ("${CMAKE_BUILD_TYPE}" STREQUAL "Release")
include(CheckIPOSupported)
check_ipo_supported(RESULT USE_IPO)
if (USE_IPO)
set_target_properties(disasmtool PROPERTIES INTERPROCEDURAL_OPTIMIZATION True)
endif ()
endif ()
set_target_properties(
disasmtool
PROPERTIES POSITION_INDEPENDENT_CODE ON
CXX_STANDARD 17
CXX_STANDARD_REQUIRED ON
CXX_EXTENSIONS ON)

@ -1,39 +0,0 @@
.PHONY: all last_build debug release
CMAKE_BUILD_DIR = build
CPUCOUNT := $(shell grep -c "^processor" /proc/cpuinfo)
ifneq (,$(CPUCOUNT))
EXTRA_MAKE_ARGS := -j$(CPUCOUNT)
endif
# NINJA := $(shell which ninja 2>/dev/null)
ifneq (,$(NINJA))
GENERATOR := "Ninja"
else
GENERATOR := "Unix Makefiles"
endif
$(shell if [ ! -d $(CMAKE_BUILD_DIR) ]; then mkdir $(CMAKE_BUILD_DIR); fi)
all: last_build
last_build:
@cmake -H. -G$(GENERATOR) -B$(CMAKE_BUILD_DIR) -DCMAKE_EXPORT_COMPILE_COMMANDS=ON
@cmake --build $(CMAKE_BUILD_DIR) -- $(EXTRA_MAKE_ARGS)
debug: CMAKE_BUILD_TYPE := Debug
debug: build
release: CMAKE_BUILD_TYPE := Release
release: build
clean:
@if [ -d $(CMAKE_BUILD_DIR) ]; then cmake --build $(CMAKE_BUILD_DIR) --target clean; fi
reset:
@if [ -d $(CMAKE_BUILD_DIR) ]; then rm -r $(CMAKE_BUILD_DIR); fi

@ -1,66 +0,0 @@
/*
* Copyright (c) 2020 Bitdefender
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <ctime>
#include <cstdint>
#include <rapidjson/stringbuffer.h>
using StringBuffer = rapidjson::StringBuffer;
extern "C"
{
// On windows, simply include Windows.h
#ifndef _WIN32
typedef void VOID, *PVOID;
typedef unsigned char BOOLEAN, *PBOOLEAN;
typedef char CHAR, *PCHAR;
typedef unsigned char BYTE, *PBYTE;
typedef unsigned short WORD, *PWORD;
typedef unsigned int DWORD, *PDWORD;
typedef unsigned long long QWORD, *PQWORD;
typedef size_t SIZE_T;
#endif
#ifndef FALSE
#define FALSE 0
#endif
#ifndef TRUE
#define TRUE 1
#endif
#ifndef MAX_PATH
#define MAX_PATH 255
#endif
// Main disasm header file.
#include "bdshemu.h"
#include "bddisasm.h"
#include <unistd.h>
#include <time.h>
}
#include <string>
std::string enc_mode_to_str(const uint8_t enc_mode);
std::string op_type_to_str(const ND_OPERAND_TYPE type);
std::string op_enc_to_str(const ND_OPERAND_ENCODING Encoding);
std::string ins_class_to_str(const ND_INS_CLASS cls);
std::string ins_cat_to_str(ND_INS_CATEGORY category);
std::string ins_set_to_str(ND_INS_SET ins_set);
std::string reg_to_str(const int reg, const ND_REG_TYPE type);
std::string reg_type_to_str(const ND_REG_TYPE type);
StringBuffer instrux_to_json(INSTRUX *instrux, size_t rip, bool text_only = false);
StringBuffer byte_to_json(uint8_t byte, size_t rip);
StringBuffer disassemble_one(uint8_t *bytes, size_t size, size_t rip, uint8_t bits, uint8_t vendor = ND_VEND_INTEL);
bool regs_from_json(const std::string &str, SHEMU_GPR_REGS &regs, bool &update_rsp);

@ -1,927 +0,0 @@
/*
* Copyright (c) 2020 Bitdefender
* SPDX-License-Identifier: Apache-2.0
*/
#include <iostream>
#include <fstream>
#include <memory>
#include <limits>
#include <cmath>
#include <cpuid.h>
#include "external/argparse.h"
#include "disasm.hpp"
#define STACK_SIZE 0x2000
#define PAGE_MASK 0xFFFFFFFFFFFFF000
static const long NSEC_PER_SEC = (1000ULL * 1000ULL * 1000ULL);
static const char *gSpaces[16] =
{
"",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
};
struct options {
size_t rip;
size_t offset;
size_t size;
size_t count;
uint8_t bits;
uint8_t vendor;
bool no_color;
bool verbose;
bool dump_stats;
bool interactive;
bool comm;
bool json_output;
bool extended;
bool shemu;
std::string shctx;
bool kernel;
std::string in_file;
std::string hex_string;
std::string hex_file;
std::string shctx_file;
std::string shdec_file;
// From here on, these are set internally
std::unique_ptr<uint8_t[]> bytes;
size_t actual_size;
int address_size;
bool output_redirected;
};
extern "C"
{
#if !defined(BDDISASM_HAS_VSNPRINTF)
int nd_vsnprintf_s(char *buffer, size_t sizeOfBuffer, [[maybe_unused]] size_t count, const char *format, va_list argptr)
{
return vsnprintf(buffer, sizeOfBuffer, format, argptr);
}
#endif // !defined(BDDISASM_HAS_VSNPRINTF)
#if !defined(BDDISASM_HAS_MEMSET)
void *
nd_memset(void *s, int c, size_t n)
{
return memset(s, c, n);
}
#endif // !defined(BDDISASM_HAS_MEMSET)
}
static bool _hexstring_to_bytes(options &opts)
{
if (!opts.hex_file.empty()) {
auto f = std::ifstream(opts.hex_file, std::ios::in);
if (!f.is_open()) {
std::cerr << "Failed to open file " << opts.hex_file << std::endl;
return false;
}
f.seekg(0, std::ios::end);
opts.hex_string.reserve(f.tellg());
f.seekg(0, std::ios::beg);
opts.hex_string.assign((std::istreambuf_iterator<char>(f)), std::istreambuf_iterator<char>());
}
if (opts.hex_string.empty())
return false;
opts.actual_size = 0;
opts.hex_string.erase(std::remove_if(opts.hex_string.begin(), opts.hex_string.end(), isspace), opts.hex_string.end());
// This is the maximum size, not the actual size
auto initial_size = opts.hex_string.length() / 2 + 1;
opts.bytes = std::make_unique<uint8_t[]>(initial_size);
auto bytes = opts.bytes.get();
for (size_t i = 0; i < opts.hex_string.length(); i += 2) {
auto pair = opts.hex_string.substr(i, 2);
char *end_ptr;
if (pair == "0x" || pair == "0X" || pair == "\\x")
continue;
auto b = static_cast<uint8_t>(std::strtoul(pair.c_str(), &end_ptr, 16));
size_t conv_size = static_cast<size_t>(end_ptr - pair.c_str());
if (conv_size != pair.length()) {
std::cerr << "Trying to convert invalid hex number: " << pair << std::endl;
return false;
}
bytes[opts.actual_size++] = b;
}
return true;
}
static bool _load_shctx(options &opts)
{
if (opts.shctx_file.empty())
return false;
auto f = std::ifstream(opts.shctx_file, std::ios::in);
if (!f.is_open()) {
std::cout << "Failed to open file " << opts.shctx_file << std::endl;
return false;
}
f.seekg(0, std::ios::end);
opts.shctx.reserve(f.tellg());
f.seekg(0, std::ios::beg);
opts.shctx.assign((std::istreambuf_iterator<char>(f)), std::istreambuf_iterator<char>());
return true;
}
static bool _file_to_bytes(options &opts)
{
auto f = std::ifstream(opts.in_file, std::ios::in | std::ios::binary);
if (!f.is_open()) {
std::cerr << "Failed to open file " << opts.in_file << std::endl;
return false;
}
f.seekg(0, std::ios::end);
opts.actual_size = f.tellg();
if (opts.offset >= opts.actual_size) {
std::cerr << "Offset bigger than file size" << std::endl;
return false;
}
f.seekg(0, std::ios::beg);
opts.bytes = std::make_unique<uint8_t[]>(opts.actual_size);
f.read(reinterpret_cast<char*>(opts.bytes.get()), opts.actual_size);
return true;
}
// Don't change the order (on linux these values are color codes)
enum Colors {
Reset = 0,
#if defined(_WIN32)
Red = FOREGROUND_INTENSITY | FOREGROUND_RED,
Green = FOREGROUND_INTENSITY | FOREGROUND_GREEN,
Yellow = FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_GREEN,
Blue = FOREGROUND_INTENSITY | FOREGROUND_BLUE,
Magenta = FOREGROUND_INTENSITY | FOREGROUND_BLUE | FOREGROUND_RED,
Cyan = FOREGROUND_INTENSITY | FOREGROUND_BLUE | FOREGROUND_GREEN,
White = FOREGROUND_INTENSITY | FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED,
#elif defined(__unix__)
Red,
Green,
Yellow,
Blue,
Magenta,
Cyan,
White,
#endif
};
static void _set_text_color(Colors color)
{
#if defined(_WIN32)
static WORD old_attrs = -1;
if (old_attrs == -1) {
CONSOLE_SCREEN_BUFFER_INFO buffer_info;
GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &buffer_info);
old_attrs = buffer_info.wAttributes;
}
if (color == Reset)
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), old_attrs);
else
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), color);
#elif defined(__unix__)
if (color == Reset)
std::cout << "\033[m";
else
std::cout << "\033[0;3" << color << "m";
#endif
}
static struct timespec diff_time(struct timespec const &end, struct timespec const &start)
{
struct timespec result;
if (end.tv_nsec > start.tv_nsec) {
result.tv_sec = end.tv_sec - start.tv_sec;
result.tv_nsec = end.tv_nsec - start.tv_nsec;
} else {
result.tv_sec = end.tv_sec - start.tv_sec - 1;
result.tv_nsec = NSEC_PER_SEC + end.tv_nsec - start.tv_nsec;
}
return result;
}
void print_instruction(const size_t rip, INSTRUX *instrux, const options &opts)
{
char instruxText[ND_MIN_BUF_SIZE];
uint32_t k = 0;
printf("%*zx ", opts.address_size, rip);
if (!opts.no_color)
{
_set_text_color(Magenta);
for (uint32_t idx = 0; idx < instrux->PrefLength; idx++, k++)
{
printf("%02x", instrux->InstructionBytes[k]);
}
_set_text_color(Green);
for (uint32_t idx = 0; idx < (DWORD)(ND_IS_3DNOW(instrux) ? instrux->OpLength - 1 : instrux->OpLength); idx++, k++)
{
printf("%02x", instrux->InstructionBytes[k]);
}
_set_text_color(Yellow);
for (uint32_t idx = 0; idx < (DWORD)(instrux->HasModRm + instrux->HasSib); idx++, k++)
{
printf("%02x", instrux->InstructionBytes[k]);
}
_set_text_color(Blue);
for (uint32_t idx = 0; idx < (DWORD)(instrux->DispLength); idx++, k++)
{
printf("%02x", instrux->InstructionBytes[k]);
}
_set_text_color(Red);
for (uint32_t idx = 0; idx < (DWORD)(instrux->Imm1Length + instrux->Imm2Length +
instrux->RelOffsLength + instrux->MoffsetLength +
instrux->HasSseImm + instrux->AddrLength); idx++, k++)
{
printf("%02x", instrux->InstructionBytes[k]);
}
if (ND_IS_3DNOW(instrux))
{
_set_text_color(Green);
for (; k < instrux->Length; k++)
{
printf("%02x", instrux->InstructionBytes[k]);
}
}
_set_text_color(Reset);
}
for (; k < instrux->Length; k++)
{
printf("%02x", instrux->InstructionBytes[k]);
}
std::cout << gSpaces[16 - instrux->Length];
NdToText(instrux, rip, sizeof(instruxText), instruxText);
std::cout << instruxText << std::endl;
if (opts.extended) {
const uint8_t opsize[3] = { 2, 4, 8 };
const uint8_t adsize[3] = { 2, 4, 8 };
const uint8_t veclen[3] = { 16, 32, 64 };
printf(" DSIZE: %2d, ASIZE: %2d, VLEN: ",
opsize[instrux->EfOpMode] * 8, adsize[instrux->AddrMode] * 8);
if (ND_HAS_VECTOR(instrux)) {
printf("%2d\n", veclen[instrux->VecMode] * 8);
} else {
printf("-\n");
}
printf(" ISA Set: %s, Ins cat: %s, Ins class: %d, CET tracked: %s\n",
ins_set_to_str(instrux->IsaSet).c_str(), ins_cat_to_str(instrux->Category).c_str(), instrux->Instruction,
instrux->IsCetTracked ? "yes" : "no");
if (0 != instrux->CpuidFlag.Flag) {
const char *regs[4] = { "eax", "ecx", "edx", "ebx" };
printf(" CPUID leaf: 0x%08x", instrux->CpuidFlag.Leaf);
if (instrux->CpuidFlag.SubLeaf != ND_CFF_NO_SUBLEAF)
{
printf(", sub-leaf: 0x%08x", instrux->CpuidFlag.SubLeaf);
}
printf(", reg: %s, bit %u\n", regs[instrux->CpuidFlag.Reg], instrux->CpuidFlag.Bit);
}
printf(" FLAGS access: ");
uint32_t all = instrux->FlagsAccess.Tested.Raw | instrux->FlagsAccess.Modified.Raw | instrux->FlagsAccess.Set.Raw
| instrux->FlagsAccess.Cleared.Raw | instrux->FlagsAccess.Undefined.Raw;
const char *flags[22] = { "CF", nullptr, "PF", nullptr, "AF", nullptr, "ZF", "SF", "TF", "IF", "DF", "OF", "IOPL", nullptr, "NT", nullptr, "RF", "VM", "AC", "VIF", "VIP", "ID" };
for (uint32_t fidx = 0; fidx < 21; fidx++) {
if (flags[fidx] != nullptr) {
if (0 == (all & (1ULL << fidx))) {
continue;
}
printf("%s: ", flags[fidx]);
if (instrux->FlagsAccess.Tested.Raw & (1ULL << fidx)) {
printf("t");
}
if (instrux->FlagsAccess.Modified.Raw & (1ULL << fidx)) {
printf("m");
}
if (instrux->FlagsAccess.Set.Raw & (1ULL << fidx)) {
printf("1");
}
if (instrux->FlagsAccess.Cleared.Raw & (1ULL << fidx)) {
printf("0");
}
if (instrux->FlagsAccess.Undefined.Raw & (1ULL << fidx)) {
printf("u");
}
printf("; ");
}
}
printf("\n");
printf(" Valid modes: R0: %s, R1: %s, R2: %s, R3: %s, Real: %s, V8086: %s, Prot: %s, Compat: %s, Long: %s, SMM: %s, SGX: %s, TSX: %s, VMXRoot: %s, VMXNonRoot: %s\n",
instrux->ValidModes.Ring0 ? "yes" : "no",
instrux->ValidModes.Ring1 ? "yes" : "no",
instrux->ValidModes.Ring2 ? "yes" : "no",
instrux->ValidModes.Ring3 ? "yes" : "no",
instrux->ValidModes.Real ? "yes" : "no",
instrux->ValidModes.V8086 ? "yes" : "no",
instrux->ValidModes.Protected ? "yes" : "no",
instrux->ValidModes.Compat ? "yes" : "no",
instrux->ValidModes.Long ? "yes" : "no",
instrux->ValidModes.Smm ? "yes" : "no",
instrux->ValidModes.Sgx ? "yes" : "no",
instrux->ValidModes.Tsx ? "yes" : "no",
instrux->ValidModes.VmxRoot ? "yes" : "no",
instrux->ValidModes.VmxNonRoot ? "yes" : "no");
for (uint8_t i = 0; i < instrux->OperandsCount; i++) {
printf(" Operand %d %s Type: %10s, Size: %2d, RawSize: %2d, Encoding: %s", i,
instrux->Operands[i].Access.Read && instrux->Operands[i].Access.Write ? "RW" :
instrux->Operands[i].Access.Write ? "-W" : instrux->Operands[i].Access.Read ? "R-" : "--",
op_type_to_str(instrux->Operands[i].Type).c_str(), (int)instrux->Operands[i].Size,
(int)instrux->Operands[i].RawSize, op_enc_to_str(instrux->Operands[i].Encoding).c_str());
if (ND_OP_MEM == instrux->Operands[i].Type) {
printf(", ");
if (instrux->Operands[i].Info.Memory.IsAG) {
printf("Address Generator, ");
}
if (instrux->Operands[i].Info.Memory.IsBitbase) {
printf("Bitbase Addressing, ");
}
if (instrux->Operands[i].Info.Memory.IsMib) {
printf("MIB Addressing, ");
}
if (instrux->Operands[i].Info.Memory.IsVsib) {
printf("VSIB Addressing, ");
}
if (instrux->Operands[i].Info.Memory.IsStack) {
printf("Stack, ");
}
if (instrux->Operands[i].Info.Memory.IsShadowStack) {
printf("Shadow Stack, ");
}
}
if (ND_OP_REG == instrux->Operands[i].Type) {
printf(", RegType: %16s, RegSize: %2u, ",
reg_type_to_str(instrux->Operands[i].Info.Register.Type).c_str(),
instrux->Operands[i].Info.Register.Size);
if (instrux->Operands[i].Info.Register.Type == ND_REG_MSR)
{
printf("RegId: 0x%08x, RegCount: %u\n",
instrux->Operands[i].Info.Register.Reg,
instrux->Operands[i].Info.Register.Count);
}
else
{
printf("RegId: %u, RegCount: %u\n",
instrux->Operands[i].Info.Register.Reg,
instrux->Operands[i].Info.Register.Count);
}
}
printf("\n");
if (instrux->Operands[i].Decorator.HasBroadcast) {
printf(" Decorator: Broadcast %d bytes element %d times\n",
instrux->Operands[i].Decorator.Broadcast.Size,
instrux->Operands[i].Decorator.Broadcast.Count);
}
if (instrux->Operands[i].Decorator.HasMask) {
printf(" Decorator: Mask k%d\n", instrux->Operands[i].Decorator.Mask.Msk);
}
if (instrux->Operands[i].Decorator.HasZero) {
printf(" Decorator: Zero (no merging)\n");
}
}
printf("\n");
}
}
StringBuffer disassemble_one(uint8_t *bytes, size_t size, size_t rip, uint8_t bits, uint8_t vendor /* = ND_VEND_INTEL */)
{
INSTRUX instrux;
auto status = NdDecodeEx2(&instrux, bytes, size, bits, bits, bits, vendor);
if (!ND_SUCCESS(status))
return byte_to_json(bytes[0], rip);
else
return instrux_to_json(&instrux, rip);
}
void shemu_log(PCHAR msg)
{
printf("%s", msg);
}
ND_BOOL shemu_access_mem(void * /* Ctx */, uint64_t /* Gla */, size_t Size, uint8_t *Buffer, ND_BOOL Store)
{
if (!Store)
{
memset(Buffer, 0, Size);
}
return ND_TRUE;
}
void shemu(options &opts)
{
SHEMU_CONTEXT ctx = { };
SHEMU_STATUS shstatus;
auto stack = std::make_unique<uint8_t[]>(STACK_SIZE);
auto intbuf = std::make_unique<uint8_t[]>(opts.actual_size + STACK_SIZE);
auto shellcode = std::make_unique<uint8_t[]>(opts.actual_size);
ctx.Stack = stack.get();
memset(ctx.Stack, 0, STACK_SIZE);
ctx.Intbuf = intbuf.get();
memset(ctx.Intbuf, 0, opts.actual_size + STACK_SIZE);
ctx.Shellcode = shellcode.get();
memcpy(ctx.Shellcode, opts.bytes.get(), opts.actual_size);
ctx.ShellcodeSize = opts.actual_size;
ctx.StackSize = STACK_SIZE;
ctx.Registers.RegRsp = 0x101000;
ctx.IntbufSize = opts.actual_size + STACK_SIZE;
ctx.Registers.RegFlags = NDR_RFLAG_IF | 2;
ctx.Registers.RegRip = opts.rip ? opts.rip : 0x200000;
ctx.Segments.Cs.Selector = 0x10;
ctx.Segments.Ds.Selector = 0x28;
ctx.Segments.Es.Selector = 0x28;
ctx.Segments.Ss.Selector = 0x28;
ctx.Segments.Fs.Selector = 0x30;
ctx.Segments.Fs.Base = 0x7FFF0000;
ctx.Segments.Gs.Selector = 0x30;
ctx.Segments.Gs.Base = 0x7FFF0000;
// Dummy values, to resemble regular CR0/CR4 values.
ctx.Registers.RegCr0 = 0x0000000080050031;
ctx.Registers.RegCr4 = 0x0000000000170678;
ctx.Mode = opts.bits;
ctx.Ring = opts.kernel ? 0 : 3;
ctx.TibBase = (opts.bits == ND_DATA_32 ? ctx.Segments.Fs.Base : ctx.Segments.Gs.Base);
ctx.MaxInstructionsCount = 4096;
ctx.Options = SHEMU_OPT_TRACE_EMULATION;
ctx.Log = shemu_log;
ctx.AccessMemory = shemu_access_mem;
uint32_t eax, ebx, ecx, edx;
eax = ebx = ecx = edx = 0;
__get_cpuid(1, &eax, &ebx, &ecx, &edx);
if (!!(ecx & (1UL << 25)))
{
ctx.Options |= SHEMU_OPT_SUPPORT_AES;
}
// Configurable thresholds.
ctx.NopThreshold = SHEMU_DEFAULT_NOP_THRESHOLD;
ctx.StrThreshold = SHEMU_DEFAULT_STR_THRESHOLD;
ctx.MemThreshold = SHEMU_DEFAULT_MEM_THRESHOLD;
bool update_rsp = false;
if (!opts.shctx.empty() && !regs_from_json(opts.shctx, ctx.Registers, update_rsp)) {
std::cerr << "Failed to parse context file." << std::endl;
return;
}
// Consider the stack base at least with a page before the current RSP. In case of pushes or operations
// which decrease the RSP, we will always give SHEMU_ABORT_BRANCH_OUTSIDE otherwise.
ctx.StackBase = ctx.Registers.RegRsp - 0x1000;
ctx.ShellcodeBase = (ctx.Registers.RegRip ? ctx.Registers.RegRip & PAGE_MASK : 0x200000);
shstatus = ShemuEmulate(&ctx);
printf("Emulation terminated with status 0x%08x, flags: 0x%llx, %u NOPs\n",
shstatus, (unsigned long long)ctx.Flags, ctx.NopCount);
if (ctx.Flags & SHEMU_FLAG_NOP_SLED)
{
printf(" SHEMU_FLAG_NOP_SLED\n");
}
if (ctx.Flags & SHEMU_FLAG_LOAD_RIP)
{
printf(" SHEMU_FLAG_LOAD_RIP\n");
}
if (ctx.Flags & SHEMU_FLAG_WRITE_SELF)
{
printf(" SHEMU_FLAG_WRITE_SELF\n");
}
if (ctx.Flags & SHEMU_FLAG_TIB_ACCESS)
{
printf(" SHEMU_FLAG_TIB_ACCESS\n");
}
if (ctx.Flags & SHEMU_FLAG_SYSCALL)
{
printf(" SHEMU_FLAG_SYSCALL\n");
}
if (ctx.Flags & SHEMU_FLAG_STACK_STR)
{
printf(" SHEMU_FLAG_STACK_STR\n");
}
if (ctx.Flags & SHEMU_FLAG_KPCR_ACCESS)
{
printf(" SHEMU_FLAG_KPCR_ACCESS\n");
}
if (ctx.Flags & SHEMU_FLAG_SWAPGS)
{
printf(" SHEMU_FLAG_SWAPGS\n");
}
if (ctx.Flags & SHEMU_FLAG_SYSCALL_MSR_READ)
{
printf(" SHEMU_FLAG_SYSCALL_MSR_READ\n");
}
if (ctx.Flags & SHEMU_FLAG_SYSCALL_MSR_WRITE)
{
printf(" SHEMU_FLAG_SYSCALL_MSR_WRITE\n");
}
if (!opts.shdec_file.empty()) {
auto f = std::ofstream(opts.shdec_file, std::ios::out | std::ios::binary);
if (!f.is_open())
std::cerr << "Failed to open file " << opts.shdec_file<< std::endl;
else
f.write(reinterpret_cast<char*>(ctx.Shellcode), ctx.ShellcodeSize);
}
}
size_t disassemble(options &opts)
{
struct timespec start;
clock_gettime(CLOCK_THREAD_CPUTIME_ID, &start);
size_t icount = 0, miss_count = 0, ibytes = 0;
size_t rel_rip = opts.offset;
size_t total_disasm = 0;
auto bytes = opts.bytes.get();
auto disasm_size = std::min(opts.actual_size - opts.offset, opts.size);
opts.address_size = int(std::ceil(((8 * sizeof(opts.actual_size)) - __builtin_clzll(opts.actual_size)) / 4.0));
while ((total_disasm < disasm_size) && (icount < opts.count)) {
INSTRUX instrux;
auto status = NdDecodeEx2(&instrux,
&bytes[rel_rip],
opts.actual_size - rel_rip,
opts.bits,
opts.bits,
opts.bits,
opts.vendor);
if (!ND_SUCCESS(status)) {
if (!opts.dump_stats) {
if (opts.json_output) {
auto j = byte_to_json(bytes[rel_rip], rel_rip + opts.rip);
std::cout << j.GetString() << std::endl;
} else {
printf("%*zx ", opts.address_size, rel_rip + opts.rip);
printf("%02x", bytes[rel_rip]);
printf("%s", gSpaces[16 - opts.address_size]);
printf("db 0x%02x\n", bytes[rel_rip]);
}
}
rel_rip++;
total_disasm++;
miss_count++;
} else {
icount++;
ibytes += instrux.Length;
if (!opts.dump_stats) {
if (opts.json_output) {
auto j = instrux_to_json(&instrux, rel_rip + opts.rip);
std::cout << j.GetString() << std::endl;
} else
print_instruction(rel_rip + opts.rip, &instrux, opts);
} else if (opts.json_output)
instrux_to_json(&instrux, rel_rip + opts.rip);
rel_rip += instrux.Length;
total_disasm += instrux.Length;
}
}
struct timespec end;
clock_gettime(CLOCK_THREAD_CPUTIME_ID, &end);
if (opts.dump_stats)
{
auto result = diff_time(end, start);
long total_ns = result.tv_sec * NSEC_PER_SEC + result.tv_nsec;
printf("Disassembled %zu instructions took %ld.%09ld seconds, %lu ns / instr.\n",
icount, result.tv_sec, result.tv_nsec, total_ns / icount);
printf("Invalid: %zu/%zu (%.2f) bytes\n", miss_count, ibytes,
(static_cast<double>(miss_count) / static_cast<double>(disasm_size)) * 100.0);
}
opts.rip += rel_rip;
return icount;
}
static bool _validate_and_fix_args(options& opts)
{
if (!opts.interactive && !opts.comm) {
int total = 0;
if (!opts.hex_string.empty())
total++;
if (!opts.hex_file.empty())
total++;
if (!opts.in_file.empty())
total++;
if (total == 0) {
std::cerr << "Give hex, file or hex-file..." << std::endl;
return false;
} else if (total > 1) {
std::cerr << "Only one of hex, file or hex-file can be present..." << std::endl;
return false;
}
}
if (opts.interactive || opts.comm) {
if (!opts.in_file.empty() || !opts.hex_string.empty() || !opts.hex_file.empty()) {
std::cerr << "Interactive mode doesn't work with file, hex-string or hex-file" << std::endl;
return false;
}
if (opts.size || opts.count || opts.offset) {
std::cerr << "Interactive mode doesn't work with size, count or offset" << std::endl;
return false;
}
}
switch (opts.bits) {
case 64:
opts.bits = ND_DATA_64;
break;
case 32:
opts.bits = ND_DATA_32;
break;
case 16:
opts.bits = ND_DATA_16;
break;
default:
std::cerr << "Please give --bits [64,32,16]" << std::endl;
return false;
}
if (0 == opts.size)
opts.size = std::numeric_limits<std::size_t>::max();
if (0 == opts.count)
opts.count = std::numeric_limits<std::size_t>::max();
if (!isatty(fileno(stdout)))
opts.output_redirected = true;
if (!opts.hex_file.empty())
opts.shdec_file = opts.hex_file + "_decoded.bin";
else if (!opts.in_file.empty())
opts.shdec_file = opts.in_file + "_decoded.bin";
else
opts.shdec_file = "hex_string_decoded.bin";
return true;
}
static size_t _get_hex_opt(argparse::ArgumentParser &parser, const std::string &field)
{
return std::strtoul(parser.get<std::string>(field).c_str(), nullptr, 0);
}
int main(int argc, const char **argv)
{
auto opts = options{};
auto parser = argparse::ArgumentParser(argv[0], "Disassembler tool for Linux");
parser.add_argument("-i", "--interactive", "Interactive mode", false);
parser.add_argument("-c", "--comm", "Comm mode", false);
parser.add_argument("-r", "--rip", "Use this rip to disassemble", false);
parser.add_argument("-f", "--file", "Use this input file", false);
parser.add_argument("-x", "--hex", "Use this hex-string", false);
parser.add_argument("--hexfile", "Use this input file as a hex-string", false);
parser.add_argument("--no-color", "Don't use colors", false);
parser.add_argument("--offset", "Use this offset in file/hex-string", false);
parser.add_argument("--size", "Only disasemble this size from file/hex-string", false);
parser.add_argument("--count", "Only disasemble this many instructions", false);
parser.add_argument("--stats", "Dump statistics (time, count, etc.)", false);
parser.add_argument("-b", "--bits", "Use the arch [16, 32, 64]", false);
parser.add_argument("--verbose", "Verbose mode", false);
parser.add_argument("--json", "Output to json", false);
parser.add_argument("--extended", "Extended instruction info", false);
parser.add_argument("--shemu", "Emulate the input hexfile", false);
parser.add_argument("--kernel", "Kernel mode for shemu context", false);
parser.add_argument("--shctx", "Shemu context file. Must be a JSON file.", false);
parser.enable_help();
auto err = parser.parse(argc, argv);
if (err) {
std::cout << err << std::endl;
return -1;
}
if (parser.exists("help")) {
parser.print_help();
return 0;
}
opts.bits = parser.get<uint64_t>("bits");
opts.interactive = parser.exists("interactive");
opts.comm = parser.exists("comm");
opts.offset = _get_hex_opt(parser, "offset");
opts.size = _get_hex_opt(parser, "size");
opts.count = _get_hex_opt(parser, "count");
opts.rip = _get_hex_opt(parser, "rip");
opts.in_file = parser.get<std::string>("file");
opts.hex_string = parser.get<std::string>("hex");
opts.hex_file = parser.get<std::string>("hexfile");
opts.no_color = parser.exists("no-color");
opts.dump_stats = parser.exists("stats");
opts.verbose = parser.exists("verbose");
opts.json_output = parser.exists("json");
opts.extended = parser.exists("extended");
opts.shemu = parser.exists("shemu");
opts.kernel = parser.exists("kernel");
opts.shctx_file = parser.get<std::string>("shctx");
if (opts.verbose) {
std::cout << "interactive: " << opts.interactive << std::endl;
std::cout << "comm: " << opts.comm << std::endl;
std::cout << "rip: " << opts.rip << std::endl;
std::cout << "bits: " << static_cast<uint16_t>(opts.bits) << std::endl;
std::cout << "offset: " << opts.offset << std::endl;
std::cout << "size: " << opts.offset << std::endl;
std::cout << "count: " << opts.count << std::endl;
std::cout << "in_file: " << opts.in_file << std::endl;
std::cout << "no-color: " << opts.no_color << std::endl;
std::cout << "stats: " << opts.dump_stats << std::endl;
std::cout << "hex: " << opts.hex_string << std::endl;
std::cout << "json: " << opts.json_output << std::endl;
std::cout << "extended: " << opts.extended << std::endl;
std::cout << "shemu:" << opts.shemu << std::endl;
std::cout << "kernel:" << opts.kernel << std::endl;
std::cout << "shctx:" << opts.shctx_file << std::endl;
}
if (!_validate_and_fix_args(opts)) {
return 1;
}
if (!opts.interactive && !opts.comm) {
if (!opts.hex_string.empty() || !opts.hex_file.empty()) {
if (!_hexstring_to_bytes(opts))
return 1;
} else if (!opts.in_file.empty()) {
if (!_file_to_bytes(opts))
return 1;
}
if (opts.offset >= opts.actual_size)
return 1;
if (!opts.shemu) {
disassemble(opts);
}
else {
_load_shctx(opts);
shemu(opts);
}
} else {
while (true) {
opts.hex_string.clear();
if (!opts.comm)
std::cout << ">> ";
std::getline(std::cin, opts.hex_string);
if (opts.hex_string == "q"
|| opts.hex_string == "quit"
|| opts.hex_string == "exit"
|| opts.hex_string.empty()) {
if (!opts.comm)
std::cout << "Bye!" << std::endl;
break;
}
_hexstring_to_bytes(opts);
disassemble(opts);
std::cout.flush();
}
}
return 0;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -1,566 +0,0 @@
/**
* License: Apache 2.0 with LLVM Exception or GPL v3
*
* Author: Jesse Laning
*/
#ifndef ARGPARSE_H
#define ARGPARSE_H
#include <algorithm>
#include <cctype>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <locale>
#include <map>
#include <numeric>
#include <sstream>
#include <stdexcept>
#include <string>
#include <unordered_map>
#include <vector>
namespace argparse {
namespace detail {
static inline bool _not_space(int ch) { return !std::isspace(ch); }
static inline void _ltrim(std::string &s, bool (*f)(int) = _not_space) {
s.erase(s.begin(), std::find_if(s.begin(), s.end(), f));
}
static inline void _rtrim(std::string &s, bool (*f)(int) = _not_space) {
s.erase(std::find_if(s.rbegin(), s.rend(), f).base(), s.end());
}
static inline void _trim(std::string &s, bool (*f)(int) = _not_space) {
_ltrim(s, f);
_rtrim(s, f);
}
static inline std::string _ltrim_copy(std::string s,
bool (*f)(int) = _not_space) {
_ltrim(s, f);
return s;
}
static inline std::string _rtrim_copy(std::string s,
bool (*f)(int) = _not_space) {
_rtrim(s, f);
return s;
}
static inline std::string _trim_copy(std::string s,
bool (*f)(int) = _not_space) {
_trim(s, f);
return s;
}
template <typename InputIt>
static inline std::string _join(InputIt begin, InputIt end,
const std::string &separator = " ") {
std::ostringstream ss;
if (begin != end) {
ss << *begin++;
}
while (begin != end) {
ss << separator;
ss << *begin++;
}
return ss.str();
}
static inline bool _is_number(const std::string &arg) {
std::istringstream iss(arg);
float f;
iss >> std::noskipws >> f;
return iss.eof() && !iss.fail();
}
static inline int _find_equal(const std::string &s) {
for (size_t i = 0; i < s.length(); ++i) {
// if find graph symbol before equal, end search
// i.e. don't accept --asd)f=0 arguments
// but allow --asd_f and --asd-f arguments
if (std::ispunct(static_cast<int>(s[i]))) {
if (s[i] == '=') {
return static_cast<int>(i);
} else if (s[i] == '_' || s[i] == '-') {
continue;
}
return -1;
}
}
return -1;
}
static inline size_t _find_name_end(const std::string &s) {
size_t i;
for (i = 0; i < s.length(); ++i) {
if (std::ispunct(static_cast<int>(s[i]))) {
break;
}
}
return i;
}
namespace is_vector_impl {
template <typename T>
struct is_vector : std::false_type {};
template <typename... Args>
struct is_vector<std::vector<Args...>> : std::true_type {};
} // namespace is_vector_impl
// type trait to utilize the implementation type traits as well as decay the
// type
template <typename T>
struct is_vector {
static constexpr bool const value =
is_vector_impl::is_vector<typename std::decay<T>::type>::value;
};
} // namespace detail
class ArgumentParser {
private:
public:
class Argument;
class Result {
public:
Result() {}
Result(std::string err) noexcept : _error(true), _what(err) {}
operator bool() const { return _error; }
friend std::ostream &operator<<(std::ostream &os, const Result &dt);
const std::string &what() const { return _what; }
private:
bool _error{false};
std::string _what{};
};
class Argument {
public:
enum Position : int { LAST = -1, DONT_CARE = -2 };
enum Count : int { ANY = -1 };
Argument &name(const std::string &name) {
_names.push_back(name);
return *this;
}
Argument &names(std::vector<std::string> names) {
_names.insert(_names.end(), names.begin(), names.end());
return *this;
}
Argument &description(const std::string &description) {
_desc = description;
return *this;
}
Argument &required(bool req) {
_required = req;
return *this;
}
Argument &position(int position) {
if (position != Position::LAST) {
// position + 1 because technically argument zero is the name of the
// executable
_position = position + 1;
} else {
_position = position;
}
return *this;
}
Argument &count(int count) {
_count = count;
return *this;
}
bool found() const { return _found; }
template <typename T>
typename std::enable_if<detail::is_vector<T>::value, T>::type get() {
T t = T();
typename T::value_type vt;
for (auto &s : _values) {
std::istringstream in(s);
in >> vt;
t.push_back(vt);
}
return t;
}
template <typename T>
typename std::enable_if<!detail::is_vector<T>::value, T>::type get() {
std::istringstream in(get<std::string>());
T t = T();
in >> t >> std::ws;
return t;
}
private:
Argument(const std::string &name, const std::string &desc,
bool required = false)
: _desc(desc), _required(required) {
_names.push_back(name);
}
Argument() {}
friend class ArgumentParser;
int _position{Position::DONT_CARE};
int _count{Count::ANY};
std::vector<std::string> _names{};
std::string _desc{};
bool _found{false};
bool _required{false};
int _index{-1};
std::vector<std::string> _values{};
};
ArgumentParser(const std::string &bin, const std::string &desc)
: _bin(bin), _desc(desc) {}
Argument &add_argument() {
_arguments.push_back({});
_arguments.back()._index = static_cast<int>(_arguments.size()) - 1;
return _arguments.back();
}
Argument &add_argument(const std::string &name, const std::string &long_name,
const std::string &desc, const bool required = false) {
_arguments.push_back(Argument(name, desc, required));
_arguments.back()._names.push_back(long_name);
_arguments.back()._index = static_cast<int>(_arguments.size()) - 1;
return _arguments.back();
}
Argument &add_argument(const std::string &name, const std::string &desc,
const bool required = false) {
_arguments.push_back(Argument(name, desc, required));
_arguments.back()._index = static_cast<int>(_arguments.size()) - 1;
return _arguments.back();
}
void print_help(size_t count = 0, size_t page = 0) {
if (page * count > _arguments.size()) {
return;
}
if (page == 0) {
std::cout << "Usage: " << _bin;
if (_positional_arguments.empty()) {
std::cout << " [options...]" << std::endl;
} else {
int current = 1;
for (auto &v : _positional_arguments) {
if (v.first != Argument::Position::LAST) {
for (; current < v.first; current++) {
std::cout << " [" << current << "]";
}
std::cout
<< " ["
<< detail::_ltrim_copy(
_arguments[static_cast<size_t>(v.second)]._names[0],
[](int c) -> bool { return c != static_cast<int>('-'); })
<< "]";
}
}
auto it = _positional_arguments.find(Argument::Position::LAST);
if (it == _positional_arguments.end()) {
std::cout << " [options...]";
} else {
std::cout
<< " [options...] ["
<< detail::_ltrim_copy(
_arguments[static_cast<size_t>(it->second)]._names[0],
[](int c) -> bool { return c != static_cast<int>('-'); })
<< "]";
}
std::cout << std::endl;
}
std::cout << "Options:" << std::endl;
}
if (count == 0) {
page = 0;
count = _arguments.size();
}
for (size_t i = page * count;
i < std::min<size_t>(page * count + count, _arguments.size()); i++) {
Argument &a = _arguments[i];
std::string name = a._names[0];
for (size_t n = 1; n < a._names.size(); ++n) {
name.append(", " + a._names[n]);
}
std::cout << " " << std::setw(23) << std::left << name << std::setw(23)
<< a._desc;
if (a._required) {
std::cout << " (Required)";
}
std::cout << std::endl;
}
}
Result parse(int argc, const char *argv[]) {
Result err;
if (argc > 1) {
// build name map
for (auto &a : _arguments) {
for (auto &n : a._names) {
std::string name = detail::_ltrim_copy(
n, [](int c) -> bool { return c != static_cast<int>('-'); });
if (_name_map.find(name) != _name_map.end()) {
return Result("Duplicate of argument name: " + n);
}
_name_map[name] = a._index;
}
if (a._position >= 0 || a._position == Argument::Position::LAST) {
_positional_arguments[a._position] = a._index;
}
}
if (err) {
return err;
}
// parse
std::string current_arg;
size_t arg_len;
for (int argv_index = 1; argv_index < argc; ++argv_index) {
current_arg = std::string(argv[argv_index]);
arg_len = current_arg.length();
if (arg_len == 0) {
continue;
}
if (_help_enabled && (current_arg == "-h" || current_arg == "--help")) {
_arguments[static_cast<size_t>(_name_map["help"])]._found = true;
} else if (argv_index == argc - 1 &&
_positional_arguments.find(Argument::Position::LAST) !=
_positional_arguments.end()) {
err = _end_argument();
Result b = err;
err = _add_value(current_arg, Argument::Position::LAST);
if (b) {
return b;
}
if (err) {
return err;
}
} else if (arg_len >= 2 &&
!detail::_is_number(current_arg)) { // ignores the case if
// the arg is just a -
// look for -a (short) or --arg (long) args
if (current_arg[0] == '-') {
err = _end_argument();
if (err) {
return err;
}
// look for --arg (long) args
if (current_arg[1] == '-') {
err = _begin_argument(current_arg.substr(2), true, argv_index);
if (err) {
return err;
}
} else { // short args
err = _begin_argument(current_arg.substr(1), false, argv_index);
if (err) {
return err;
}
}
} else { // argument value
err = _add_value(current_arg, argv_index);
if (err) {
return err;
}
}
} else { // argument value
err = _add_value(current_arg, argv_index);
if (err) {
return err;
}
}
}
}
if (_help_enabled && exists("help")) {
return Result();
}
err = _end_argument();
if (err) {
return err;
}
for (auto &p : _positional_arguments) {
Argument &a = _arguments[static_cast<size_t>(p.second)];
if (a._values.size() > 0 && a._values[0][0] == '-') {
std::string name = detail::_ltrim_copy(a._values[0], [](int c) -> bool {
return c != static_cast<int>('-');
});
if (_name_map.find(name) != _name_map.end()) {
if (a._position == Argument::Position::LAST) {
return Result(
"Poisitional argument expected at the end, but argument " +
a._values[0] + " found instead");
} else {
return Result("Poisitional argument expected in position " +
std::to_string(a._position) + ", but argument " +
a._values[0] + " found instead");
}
}
}
}
for (auto &a : _arguments) {
if (a._required && !a._found) {
return Result("Required argument not found: " + a._names[0]);
}
if (a._position >= 0 && argc >= a._position && !a._found) {
return Result("Argument " + a._names[0] + " expected in position " +
std::to_string(a._position));
}
}
return Result();
}
void enable_help() {
add_argument("-h", "--help", "Shows this page", false);
_help_enabled = true;
}
bool exists(const std::string &name) const {
std::string n = detail::_ltrim_copy(
name, [](int c) -> bool { return c != static_cast<int>('-'); });
auto it = _name_map.find(n);
if (it != _name_map.end()) {
return _arguments[static_cast<size_t>(it->second)]._found;
}
return false;
}
template <typename T>
T get(const std::string &name) {
auto t = _name_map.find(name);
if (t != _name_map.end()) {
return _arguments[static_cast<size_t>(t->second)].get<T>();
}
return T();
}
private:
Result _begin_argument(const std::string &arg, bool longarg, int position) {
auto it = _positional_arguments.find(position);
if (it != _positional_arguments.end()) {
Result err = _end_argument();
Argument &a = _arguments[static_cast<size_t>(it->second)];
a._values.push_back((longarg ? "--" : "-") + arg);
a._found = true;
return err;
}
if (_current != -1) {
return Result("Current argument left open");
}
size_t name_end = detail::_find_name_end(arg);
std::string arg_name = arg.substr(0, name_end);
if (longarg) {
int equal_pos = detail::_find_equal(arg);
auto nmf = _name_map.find(arg_name);
if (nmf == _name_map.end()) {
return Result("Unrecognized command line option '" + arg_name + "'");
}
_current = nmf->second;
_arguments[static_cast<size_t>(nmf->second)]._found = true;
if (equal_pos == 0 ||
(equal_pos < 0 &&
arg_name.length() < arg.length())) { // malformed argument
return Result("Malformed argument: " + arg);
} else if (equal_pos > 0) {
std::string arg_value = arg.substr(name_end + 1);
_add_value(arg_value, position);
}
} else {
Result r;
if (arg_name.length() == 1) {
return _begin_argument(arg, true, position);
} else {
for (char &c : arg_name) {
r = _begin_argument(std::string(1, c), true, position);
if (r) {
return r;
}
r = _end_argument();
if (r) {
return r;
}
}
}
}
return Result();
}
Result _add_value(const std::string &value, int location) {
if (_current >= 0) {
Result err;
Argument &a = _arguments[static_cast<size_t>(_current)];
if (a._count >= 0 && static_cast<int>(a._values.size()) >= a._count) {
err = _end_argument();
if (err) {
return err;
}
goto unnamed;
}
a._values.push_back(value);
if (a._count >= 0 && static_cast<int>(a._values.size()) >= a._count) {
err = _end_argument();
if (err) {
return err;
}
}
return Result();
} else {
unnamed:
auto it = _positional_arguments.find(location);
if (it != _positional_arguments.end()) {
Argument &a = _arguments[static_cast<size_t>(it->second)];
a._values.push_back(value);
a._found = true;
}
// TODO
return Result();
}
}
Result _end_argument() {
if (_current >= 0) {
Argument &a = _arguments[static_cast<size_t>(_current)];
_current = -1;
if (static_cast<int>(a._values.size()) < a._count) {
return Result("Too few arguments given for " + a._names[0]);
}
if (a._count >= 0) {
if (static_cast<int>(a._values.size()) > a._count) {
return Result("Too many arguments given for " + a._names[0]);
}
}
}
return Result();
}
bool _help_enabled{false};
int _current{-1};
std::string _bin{};
std::string _desc{};
std::vector<Argument> _arguments{};
std::map<int, int> _positional_arguments{};
std::map<std::string, int> _name_map{};
};
std::ostream &operator<<(std::ostream &os, const ArgumentParser::Result &r) {
os << r.what();
return os;
}
template <>
inline std::string ArgumentParser::Argument::get<std::string>() {
return detail::_join(_values.begin(), _values.end());
}
template <>
inline std::vector<std::string>
ArgumentParser::Argument::get<std::vector<std::string>>() {
return _values;
}
} // namespace argparse
#endif

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -2,8 +2,8 @@
* Copyright (c) 2020 Bitdefender
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef DISASMSTATUS_H
#define DISASMSTATUS_H
#ifndef BDDISASM_STATUS_H
#define BDDISASM_STATUS_H
//
// Return statuses.
@ -48,6 +48,7 @@ typedef ND_UINT32 NDSTATUS;
#define ND_STATUS_SIBMEM_WITHOUT_SIB 0x80000042 // Instruction uses SIBMEM, but SIB is not present.
#define ND_STATUS_INVALID_TILE_REGS 0x80000043 // Tile registers are not unique.
#define ND_STATUS_INVALID_DEST_REGS 0x80000044 // Destination register is not unique (used as src).
#define ND_STATUS_INVALID_EVEX_BYTE3 0x80000045 // EVEX payload byte 3 is invalid.
// Not encoding specific.
@ -60,4 +61,4 @@ typedef ND_UINT32 NDSTATUS;
#define ND_SUCCESS(status) (status < 0x80000000)
#endif
#endif // BDDISASM_STATUS_H

@ -2,8 +2,8 @@
* Copyright (c) 2020 Bitdefender
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef DISASM_TYPES_H
#define DISASM_TYPES_H
#ifndef BDDISASM_TYPES_H
#define BDDISASM_TYPES_H
#if defined(_MSC_VER) || defined(__ICC) || defined(__INTEL_COMPILER)
@ -58,14 +58,17 @@ typedef int64_t ND_SINT64;
#elif defined(_M_IX86) || defined(__i386__)
#define ND_ARCH_X86
#define ND_ARCH_IA32
#elif defined(_M_ARM64) || defined(__aarch64__)
#define ND_ARCH_AARCH64
#define ND_ARCH_A64
#elif defined(_M_ARM) || defined(__arm__)
#define ND_ARCH_ARM
#define ND_ARCH_A32
#else
@ -75,11 +78,11 @@ typedef int64_t ND_SINT64;
// Handle architecture definitions.
#if defined(ND_ARCH_X64) || defined(ND_ARCH_AARCH64)
#if defined(ND_ARCH_X64) || defined(ND_ARCH_A64)
typedef ND_UINT64 ND_SIZET;
#elif defined(ND_ARCH_X86) || defined(ND_ARCH_ARM)
#elif defined(ND_ARCH_X86) || defined(ND_ARCH_A32)
typedef ND_UINT32 ND_SIZET;
@ -93,8 +96,23 @@ typedef ND_UINT32 ND_SIZET;
// Common definitions.
typedef ND_UINT8 ND_BOOL;
#define ND_NULL ((void *)(0))
#define ND_TRUE (1)
#define ND_FALSE (0)
#if defined(__cplusplus)
#define ND_NULL nullptr
#else
#define ND_NULL ((void *)(0))
#endif
#define ND_TRUE (1)
#define ND_FALSE (0)
// Static assertion.
#ifdef _MSC_VER
// When used without include <assert.h>, automatically maps to _Static_assert. Using static_assert is prefered, as
// it works on both C and C++.
#define ND_STATIC_ASSERT static_assert
#else
// Reserved keyword. MSVC only recognizes this if you include <assert.h>.
#define ND_STATIC_ASSERT _Static_assert
#endif
#endif // BDDISASM_TYPES_H

@ -0,0 +1,16 @@
/*
* Copyright (c) 2020 Bitdefender
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef BDDISASM_VERSION_H
#define BDDISASM_VERSION_H
#define DISASM_VERSION_MAJOR 2
#define DISASM_VERSION_MINOR 1
#define DISASM_VERSION_REVISION 0
#define SHEMU_VERSION_MAJOR DISASM_VERSION_MAJOR
#define SHEMU_VERSION_MINOR DISASM_VERSION_MINOR
#define SHEMU_VERSION_REVISION DISASM_VERSION_REVISION
#endif // BDDISASM_VERSION_H

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save