Merge branch 'develop'

This commit is contained in:
athre0z 2015-05-22 17:45:06 +02:00
commit 5bab2410fc
17 changed files with 460 additions and 184 deletions

View File

@ -16,7 +16,7 @@ if (NOT CONFIGURED_ONCE)
set(compiler_specific "-Werror") set(compiler_specific "-Werror")
set(compiler_specific_cxx "-std=c++14") set(compiler_specific_cxx "-std=c++14")
elseif (MSVC) elseif (MSVC)
set(compiler_specific "/WX /W4 /D_CRT_SECURE_NO_WARNINGS") set(compiler_specific "/WX /W4 /D_CRT_SECURE_NO_WARNINGS /GR-")
endif () endif ()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${compiler_specific} ${compiler_specific_cxx}" set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${compiler_specific} ${compiler_specific_cxx}"
@ -27,7 +27,7 @@ endif ()
# CMake always orders MSVC to build with a shared CRT. Hack CMake variables in order # CMake always orders MSVC to build with a shared CRT. Hack CMake variables in order
# to generate with a statically linked CRT when we build as a static library. # to generate with a statically linked CRT when we build as a static library.
if (MSVC AND NOT BUILD_SHARED_LIBS AND NOT FORCE_SHARED_CRT) if (MSVC AND NOT FORCE_SHARED_CRT)
set(manipulated_vars set(manipulated_vars
CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_DEBUG
CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_MINSIZEREL
@ -58,6 +58,11 @@ set(sources
"Zydis/ZydisSymbolResolver.cpp" "Zydis/ZydisSymbolResolver.cpp"
"Zydis/ZydisUtils.cpp") "Zydis/ZydisUtils.cpp")
if (BUILD_SHARED_LIBS AND WIN32)
set(sources ${sources}
"Zydis/VersionInfo.rc")
endif ()
if (BUILD_C_BINDINGS) if (BUILD_C_BINDINGS)
set(headers ${headers} set(headers ${headers}
"Zydis/ZydisAPI.h") "Zydis/ZydisAPI.h")
@ -66,6 +71,7 @@ if (BUILD_C_BINDINGS)
endif () endif ()
add_library("Zydis" ${headers} ${sources}) add_library("Zydis" ${headers} ${sources})
set_target_properties("Zydis" PROPERTIES COMPILE_DEFINITIONS "Zydis_EXPORTS")
generate_export_header( generate_export_header(
"Zydis" "Zydis"
BASE_NAME "ZYDIS" BASE_NAME "ZYDIS"
@ -78,6 +84,8 @@ if (BUILD_EXAMPLES)
add_executable("SimpleDemo_CPP" "Examples/CPP/SimpleDemo/SimpleDemo.cpp") add_executable("SimpleDemo_CPP" "Examples/CPP/SimpleDemo/SimpleDemo.cpp")
target_link_libraries("SimpleDemo_CPP" "Zydis") target_link_libraries("SimpleDemo_CPP" "Zydis")
add_executable("CustomDataSource_CPP" "Examples/CPP/CustomDataSource/CustomDataSource.cpp")
target_link_libraries("CustomDataSource_CPP" "Zydis")
if (BUILD_C_BINDINGS) if (BUILD_C_BINDINGS)
add_executable("SimpleDemo_C" "Examples/C/SimpleDemo/SimpleDemo.c") add_executable("SimpleDemo_C" "Examples/C/SimpleDemo/SimpleDemo.c")

View File

@ -154,7 +154,7 @@ int main()
puts("64 bit test ...\n\n"); puts("64 bit test ...\n\n");
while (ZydisDecodeInstruction(decoder, &info)) while (ZydisDecodeInstruction(decoder, &info))
{ {
printf("%016"PRIu64"X ", info.instrAddress); printf("%016"PRIX64" ", info.instrAddress);
if (info.flags & ZYDIS_IF_ERROR_MASK) if (info.flags & ZYDIS_IF_ERROR_MASK)
{ {
printf("db %02X", info.data[0]); printf("db %02X", info.data[0]);

View File

@ -0,0 +1,169 @@
/***************************************************************************************************
Zyan Disassembler Engine
Version 1.0
Remarks : Freeware, Copyright must be included
Original Author : Florian Bernd
Modifications : Joel Höner
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
***************************************************************************************************/
#include <stdint.h>
#include <iostream>
#include <iomanip>
#include <vector>
#include <string>
#include <sstream>
#include <Zydis.hpp>
class ZydisStdinInput : public Zydis::BaseInput
{
private:
std::vector<uint8_t> m_buffer;
uint32_t m_position = 0;
uint64_t m_globalPosition = 0;
private:
void gatherInput();
protected:
uint8_t internalInputPeek() override;
uint8_t internalInputNext() override;
public:
bool isEndOfInput() const override;
uint64_t getPosition() const override;
bool setPosition(uint64_t position) override;
};
void ZydisStdinInput::gatherInput()
{
if (m_position != m_buffer.size())
{
return;
}
std::vector<uint8_t> buffer;
bool valid;
do
{
valid = true;
buffer.clear();
std::string input;
std::getline(std::cin, input);
if (input.empty())
{
valid = false;
continue;
}
std::istringstream ss(input);
uint32_t x;
do
{
ss >> std::hex >> x;
if (ss.fail())
{
std::cout << std::endl << "# Error: Invalid hex input." << std::endl << std::endl;
ss.ignore();
valid = false;
break;
}
if (buffer.size() == buffer.capacity())
{
buffer.reserve(buffer.capacity() + 512);
}
if (x > 255)
{
std::cout << std::endl << "# Warning: 0x"
<< std::hex << std::setw(8) << std::setfill('0') << std::uppercase << x
<< " converted to uint8_t. Possible data loss." << std::endl << std::endl;
}
buffer.resize(buffer.size() + 1);
buffer[buffer.size() - 1] = static_cast<uint8_t>(x);
} while (!ss.eof());
} while (!valid);
m_buffer = buffer;
m_position = 0;
}
uint8_t ZydisStdinInput::internalInputPeek()
{
gatherInput();
return m_buffer[m_position];
}
uint8_t ZydisStdinInput::internalInputNext()
{
gatherInput();
m_globalPosition++;
return m_buffer[m_position++];
}
bool ZydisStdinInput::isEndOfInput() const
{
return false;
}
uint64_t ZydisStdinInput::getPosition() const
{
return m_globalPosition;
}
bool ZydisStdinInput::setPosition(uint64_t position)
{
if (position > m_globalPosition)
{
return false;
}
int64_t delta = m_globalPosition - position;
if (delta > m_position)
{
return false;
}
m_position = m_position - static_cast<int32_t>(delta);
m_globalPosition = position;
return true;
}
int main()
{
Zydis::InstructionInfo info;
Zydis::InstructionDecoder decoder;
Zydis::IntelInstructionFormatter formatter;
ZydisStdinInput input;
decoder.setDisassemblerMode(Zydis::DisassemblerMode::M32BIT);
decoder.setDataSource(&input);
decoder.setInstructionPointer(0x00000000);
while (decoder.decodeInstruction(info))
{
std::cout << std::hex << std::setw(8) << std::setfill('0') << std::uppercase
<< info.instrAddress << " ";
if (info.flags & Zydis::IF_ERROR_MASK)
{
std::cout << "db " << std::setw(2) << static_cast<int>(info.data[0]) << std::endl;
} else
{
std::cout << formatter.formatInstruction(info) << std::endl;
}
}
return 0;
}

View File

@ -78,7 +78,7 @@ int main()
<< info.instrAddress << " "; << info.instrAddress << " ";
if (info.flags & Zydis::IF_ERROR_MASK) if (info.flags & Zydis::IF_ERROR_MASK)
{ {
std::cout << "db " << std::setw(2) << info.data[0]; std::cout << "db " << std::setw(2) << static_cast<int>(info.data[0]) << std::endl;
} else } else
{ {
std::cout << formatter.formatInstruction(info) << std::endl; std::cout << formatter.formatInstruction(info) << std::endl;
@ -97,7 +97,7 @@ int main()
<< info.instrAddress << " "; << info.instrAddress << " ";
if (info.flags & Zydis::IF_ERROR_MASK) if (info.flags & Zydis::IF_ERROR_MASK)
{ {
std::cout << "db " << std::setw(2) << info.data[0]; std::cout << "db " << std::setw(2) << static_cast<int>(info.data[0]) << std::endl;
} else } else
{ {
std::cout << formatter.formatInstruction(info) << std::endl; std::cout << formatter.formatInstruction(info) << std::endl;

View File

@ -1,5 +1,5 @@
Zyan Disassembler Engine (Zydis) Zyan Disassembler Engine (Zydis) [![Build Status](https://travis-ci.org/zyantific/zyan-disassembler-engine.svg?branch=master)](https://travis-ci.org/zyantific/zyan-disassembler-engine)
================================== ================================
Fast and lightweight x86/x86-64 disassembler library. Fast and lightweight x86/x86-64 disassembler library.
@ -20,7 +20,7 @@ Fast and lightweight x86/x86-64 disassembler library.
The following example program uses Zydis to disassemble a given memory buffer and prints the output to the console. The following example program uses Zydis to disassemble a given memory buffer and prints the output to the console.
```C++ ```c++
#include <tchar.h> #include <tchar.h>
#include <iostream> #include <iostream>
#include <stdint.h> #include <stdint.h>
@ -35,7 +35,7 @@ int _tmain(int argc, _TCHAR* argv[])
Zydis::MemoryInput input(&data[0], sizeof(data)); Zydis::MemoryInput input(&data[0], sizeof(data));
Zydis::InstructionInfo info; Zydis::InstructionInfo info;
Zydis::InstructionDecoder decoder; Zydis::InstructionDecoder decoder;
decoder.setDisassemblerMode(Zydis::ZydisMode::M32BIT); decoder.setDisassemblerMode(Zydis::DisassemblerMode::M32BIT);
decoder.setDataSource(&input); decoder.setDataSource(&input);
decoder.setInstructionPointer(0); decoder.setInstructionPointer(0);
Zydis::IntelInstructionFormatter formatter; Zydis::IntelInstructionFormatter formatter;
@ -47,8 +47,13 @@ int _tmain(int argc, _TCHAR* argv[])
``` ```
## Compilation ## ## Compilation ##
Zydis builds cleanly on most platforms without any external dependencies. You can use CMake to generate project files for your favorite C++14 compiler. Zydis builds cleanly on most platforms without any external dependencies. You can use CMake to generate project files for your favorite C++14 compiler.
## Documentation ##
[The HTML Doxygen documentation](https://www.zyantific.com/doc/zydis/index.html) is automatically built from master every 12 hours.
## License ## ## License ##
Zyan Disassembler Engine is licensed under the MIT License. Dependencies are under their respective licenses. Zyan Disassembler Engine is licensed under the MIT License. Dependencies are under their respective licenses.

BIN
Zydis/VersionInfo.rc Normal file

Binary file not shown.

View File

@ -28,12 +28,73 @@
***************************************************************************************************/ ***************************************************************************************************/
#ifndef _ZYDIS_DISASSEMBLER_HPP_ /**
#define _ZYDIS_DISASSEMBLER_HPP_ * @file
* @brief C++ API include file.
*/
/**
* @mainpage Zyan Disassembler Engine (Zydis)
*
* Zydis is a fast and lightweight x86/x86-64 disassembler library.
*
* @section Features
* - Supports all x86 and x86-64 (AMD64) General purpose and System instructions.
* - Supported ISA extensions:
* - MMX, FPU (x87), AMD 3DNow
* - SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, AES,
* - AMD-V, INTEL-VMX, SMX
* - Optimized for high performance
* - Very small overhead compared to other common disassembler libraries (about 60KiB)
* - Abstract formatter and symbol-resolver classes for custom syntax implementations.
* - Intel syntax is implemented by default
* - Complete doxygen documentation
*
* @section Quick Example
* The following example program uses Zydis to disassemble a given memory buffer and prints the
* output to the console.
*
* @code
* #include <tchar.h>
* #include <iostream>
* #include <stdint.h>
* #include "Zydis.hpp"
*
* int _tmain(int argc, _TCHAR* argv[])
* {
* uint8_t data[] =
* {
* 0x90, 0xE9, 0x00, 0x00, 0x00, 0x00, 0xC3
* };
* Zydis::MemoryInput input(&data[0], sizeof(data));
* Zydis::InstructionInfo info;
* Zydis::InstructionDecoder decoder;
* decoder.setDisassemblerMode(Zydis::DisassemblerMode::M32BIT);
* decoder.setDataSource(&input);
* decoder.setInstructionPointer(0);
* Zydis::IntelInstructionFormatter formatter;
* while (decoder.decodeInstruction(info))
* {
* std::cout << formatter.formatInstruction(info) << std::endl;
* }
* }
* @endcode
*
* @section Compilation
* Zydis builds cleanly on most platforms without any external dependencies. You can use CMake
* to generate project files for your favorite C++14 compiler.
*
* @section License
* Zyan Disassembler Engine is licensed under the MIT License. Dependencies are under their
* respective licenses.
*/
#ifndef _ZYDIS_HPP_
#define _ZYDIS_HPP_
#include "ZydisInstructionDecoder.hpp" #include "ZydisInstructionDecoder.hpp"
#include "ZydisInstructionFormatter.hpp" #include "ZydisInstructionFormatter.hpp"
#include "ZydisSymbolResolver.hpp" #include "ZydisSymbolResolver.hpp"
#include "ZydisUtils.hpp" #include "ZydisUtils.hpp"
#endif /*_ZYDIS_DISASSEMBLER_HPP_ */ #endif /*_ZYDIS_HPP_ */

View File

@ -85,6 +85,7 @@ private:
using FullClassT = ZydisClassEx<ZydisClassT>; using FullClassT = ZydisClassEx<ZydisClassT>;
public: public:
uint32_t type; uint32_t type;
uint32_t align;
std::conditional_t<std::is_abstract<ZydisClassT>::value, char, ZydisClassT> instance; std::conditional_t<std::is_abstract<ZydisClassT>::value, char, ZydisClassT> instance;
public: public:
/** /**
@ -99,6 +100,7 @@ public:
typename... InstanceCtorArgsT> typename... InstanceCtorArgsT>
ZydisClassEx(uint32_t classType, InstanceCtorArgsT... args) ZydisClassEx(uint32_t classType, InstanceCtorArgsT... args)
: type(classType) : type(classType)
, align(0)
, instance(args...) { }; , instance(args...) { };
public: public:
/** /**
@ -126,7 +128,9 @@ public:
static FullClassT* fromInstance(ZydisClassT* instance) static FullClassT* fromInstance(ZydisClassT* instance)
{ {
return reinterpret_cast<FullClassT*>( return reinterpret_cast<FullClassT*>(
reinterpret_cast<uintptr_t>(instance) - sizeof(std::declval<FullClassT>().type)); reinterpret_cast<uintptr_t>(instance)
- sizeof(std::declval<FullClassT>().type)
- sizeof(std::declval<FullClassT>().align));
} }
}; };
#pragma pack(pop) #pragma pack(pop)

View File

@ -28,11 +28,14 @@
***************************************************************************************************/ ***************************************************************************************************/
/**
* @file
* @brief C API for Zydis.
*/
#ifndef _ZYDIS_API_H_ #ifndef _ZYDIS_API_H_
#define _ZYDIS_API_H_ #define _ZYDIS_API_H_
#define Zydis_EXPORTS
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
#include <stddef.h> #include <stddef.h>

View File

@ -61,7 +61,7 @@ bool InstructionDecoder::decodeRegisterOperand(InstructionInfo& info,
break; break;
case 8: case 8:
// TODO: Only REX? Or VEX too? // TODO: Only REX? Or VEX too?
if (m_disassemblerMode == DisassemblerMode::M64BIT&& (info.flags& IF_PREFIX_REX)) if (m_disassemblerMode == DisassemblerMode::M64BIT && (info.flags & IF_PREFIX_REX))
{ {
if (registerId >= 4) if (registerId >= 4)
{ {
@ -88,7 +88,7 @@ bool InstructionDecoder::decodeRegisterOperand(InstructionInfo& info,
break; break;
case RegisterClass::MMX: case RegisterClass::MMX:
reg = static_cast<Register>( reg = static_cast<Register>(
static_cast<uint16_t>(Register::MM0) + (registerId& 0x07)); static_cast<uint16_t>(Register::MM0) + (registerId & 0x07));
break; break;
case RegisterClass::CONTROL: case RegisterClass::CONTROL:
reg = static_cast<Register>(static_cast<uint16_t>(Register::CR0) + registerId); reg = static_cast<Register>(static_cast<uint16_t>(Register::CR0) + registerId);
@ -97,13 +97,13 @@ bool InstructionDecoder::decodeRegisterOperand(InstructionInfo& info,
reg = static_cast<Register>(static_cast<uint16_t>(Register::DR0) + registerId); reg = static_cast<Register>(static_cast<uint16_t>(Register::DR0) + registerId);
break; break;
case RegisterClass::SEGMENT: case RegisterClass::SEGMENT:
if ((registerId& 7) > 5) if ((registerId & 7) > 5)
{ {
info.flags |= IF_ERROR_OPERAND; info.flags |= IF_ERROR_OPERAND;
return false; return false;
} }
reg = static_cast<Register>( reg = static_cast<Register>(
static_cast<uint16_t>(Register::ES) + (registerId& 0x07)); static_cast<uint16_t>(Register::ES) + (registerId & 0x07));
break; break;
case RegisterClass::XMM: case RegisterClass::XMM:
reg = static_cast<Register>(registerId + static_cast<uint16_t>( reg = static_cast<Register>(registerId + static_cast<uint16_t>(
@ -125,7 +125,7 @@ bool InstructionDecoder::decodeRegisterMemoryOperand(InstructionInfo& info,
{ {
return false; return false;
} }
assert(info.flags& IF_MODRM); assert(info.flags & IF_MODRM);
// Decode register operand // Decode register operand
if (info.modrm_mod == 3) if (info.modrm_mod == 3)
{ {
@ -147,10 +147,10 @@ bool InstructionDecoder::decodeRegisterMemoryOperand(InstructionInfo& info,
Register::SI, Register::DI, Register::SI, Register::DI, Register::SI, Register::DI, Register::SI, Register::DI,
Register::NONE, Register::NONE, Register::NONE, Register::NONE, Register::NONE, Register::NONE,
Register::NONE }; Register::NONE };
operand.base = static_cast<Register>(bases[info.modrm_rm_ext& 0x07]); operand.base = static_cast<Register>(bases[info.modrm_rm_ext & 0x07]);
operand.index = static_cast<Register>(indices[info.modrm_rm_ext& 0x07]); operand.index = static_cast<Register>(indices[info.modrm_rm_ext & 0x07]);
operand.scale = 0; operand.scale = 0;
if (info.modrm_mod == 0&& info.modrm_rm_ext == 6) { if (info.modrm_mod == 0 && info.modrm_rm_ext == 6) {
offset = 16; offset = 16;
operand.base = Register::NONE; operand.base = Register::NONE;
} else if (info.modrm_mod == 1) { } else if (info.modrm_mod == 1) {
@ -181,7 +181,7 @@ bool InstructionDecoder::decodeRegisterMemoryOperand(InstructionInfo& info,
default: default:
assert(0); assert(0);
} }
if ((info.modrm_rm_ext& 0x07) == 4) if ((info.modrm_rm_ext & 0x07) == 4)
{ {
if (!decodeSIB(info)) if (!decodeSIB(info))
{ {
@ -193,7 +193,7 @@ bool InstructionDecoder::decodeRegisterMemoryOperand(InstructionInfo& info,
operand.index = operand.index =
static_cast<Register>(static_cast<uint16_t>(Register::EAX) + static_cast<Register>(static_cast<uint16_t>(Register::EAX) +
info.sib_index_ext); info.sib_index_ext);
operand.scale = (1 << info.sib_scale)& ~1; operand.scale = (1 << info.sib_scale) & ~1;
if (operand.index == Register::ESP) if (operand.index == Register::ESP)
{ {
operand.index = Register::NONE; operand.index = Register::NONE;
@ -225,7 +225,7 @@ bool InstructionDecoder::decodeRegisterMemoryOperand(InstructionInfo& info,
switch (info.modrm_mod) switch (info.modrm_mod)
{ {
case 0: case 0:
if ((info.modrm_rm_ext& 0x07) == 5) if ((info.modrm_rm_ext & 0x07) == 5)
{ {
info.flags |= IF_RELATIVE; info.flags |= IF_RELATIVE;
operand.base = Register::RIP; operand.base = Register::RIP;
@ -241,7 +241,7 @@ bool InstructionDecoder::decodeRegisterMemoryOperand(InstructionInfo& info,
default: default:
assert(0); assert(0);
} }
if ((info.modrm_rm_ext& 0x07) == 4) if ((info.modrm_rm_ext & 0x07) == 4)
{ {
if (!decodeSIB(info)) if (!decodeSIB(info))
{ {
@ -259,7 +259,7 @@ bool InstructionDecoder::decodeRegisterMemoryOperand(InstructionInfo& info,
operand.scale = 0; operand.scale = 0;
} else } else
{ {
operand.scale = (1 << info.sib_scale)& ~1; operand.scale = (1 << info.sib_scale) & ~1;
} }
if ((operand.base == Register::RBP) || (operand.base == Register::R13)) if ((operand.base == Register::RBP) || (operand.base == Register::R13))
{ {
@ -318,7 +318,7 @@ bool InstructionDecoder::decodeImmediate(InstructionInfo& info, OperandInfo& ope
// TODO: Maybe return false instead of assert // TODO: Maybe return false instead of assert
assert(0); assert(0);
} }
if (!operand.lval.uqword&& (info.flags& IF_ERROR_MASK)) if (!operand.lval.uqword && (info.flags & IF_ERROR_MASK))
{ {
return false; return false;
} }
@ -350,7 +350,7 @@ bool InstructionDecoder::decodeDisplacement(InstructionInfo& info,
// TODO: Maybe return false instead of assert // TODO: Maybe return false instead of assert
assert(0); assert(0);
} }
if (!operand.lval.uqword&& (info.flags& IF_ERROR_MASK)) if (!operand.lval.uqword && (info.flags & IF_ERROR_MASK))
{ {
return false; return false;
} }
@ -359,17 +359,17 @@ bool InstructionDecoder::decodeDisplacement(InstructionInfo& info,
bool InstructionDecoder::decodeModrm(InstructionInfo& info) bool InstructionDecoder::decodeModrm(InstructionInfo& info)
{ {
if (!(info.flags& IF_MODRM)) if (!(info.flags & IF_MODRM))
{ {
info.modrm = inputNext(info); info.modrm = inputNext(info);
if (!info.modrm&& (info.flags& IF_ERROR_MASK)) if (!info.modrm && (info.flags & IF_ERROR_MASK))
{ {
return false; return false;
} }
info.flags |= IF_MODRM; info.flags |= IF_MODRM;
info.modrm_mod = (info.modrm >> 6)& 0x03; info.modrm_mod = (info.modrm >> 6) & 0x03;
info.modrm_reg = (info.modrm >> 3)& 0x07; info.modrm_reg = (info.modrm >> 3) & 0x07;
info.modrm_rm = (info.modrm >> 0)& 0x07; info.modrm_rm = (info.modrm >> 0) & 0x07;
} }
// The @c decodeModrm method might get called multiple times during the opcode- and the // The @c decodeModrm method might get called multiple times during the opcode- and the
// operand decoding, but the effective REX/VEX fields are not initialized before the end of // operand decoding, but the effective REX/VEX fields are not initialized before the end of
@ -382,19 +382,19 @@ bool InstructionDecoder::decodeModrm(InstructionInfo& info)
bool InstructionDecoder::decodeSIB(InstructionInfo& info) bool InstructionDecoder::decodeSIB(InstructionInfo& info)
{ {
assert(info.flags& IF_MODRM); assert(info.flags & IF_MODRM);
assert((info.modrm_rm& 0x7) == 4); assert((info.modrm_rm & 0x7) == 4);
if (!(info.flags& IF_SIB)) if (!(info.flags & IF_SIB))
{ {
info.sib = inputNext(info); info.sib = inputNext(info);
if (!info.sib&& (info.flags& IF_ERROR_MASK)) if (!info.sib && (info.flags & IF_ERROR_MASK))
{ {
return false; return false;
} }
info.flags |= IF_SIB; info.flags |= IF_SIB;
info.sib_scale = (info.sib >> 6)& 0x03; info.sib_scale = (info.sib >> 6) & 0x03;
info.sib_index = (info.sib >> 3)& 0x07; info.sib_index = (info.sib >> 3) & 0x07;
info.sib_base = (info.sib >> 0)& 0x07; info.sib_base = (info.sib >> 0) & 0x07;
// The @c decodeSib method is only called during the operand decoding, so updating the // The @c decodeSib method is only called during the operand decoding, so updating the
// extended values at this point should be safe. // extended values at this point should be safe.
info.sib_index_ext = (info.eff_rexvex_x << 3) | info.sib_index; info.sib_index_ext = (info.eff_rexvex_x << 3) | info.sib_index;
@ -405,45 +405,45 @@ bool InstructionDecoder::decodeSIB(InstructionInfo& info)
bool InstructionDecoder::decodeVex(InstructionInfo& info) bool InstructionDecoder::decodeVex(InstructionInfo& info)
{ {
if (!(info.flags& IF_PREFIX_VEX)) if (!(info.flags & IF_PREFIX_VEX))
{ {
info.vex_op = inputCurrent(); info.vex_op = inputCurrent();
switch (info.vex_op) switch (info.vex_op)
{ {
case 0xC4: case 0xC4:
info.vex_b1 = inputNext(info); info.vex_b1 = inputNext(info);
if (!info.vex_b1 || (info.flags& IF_ERROR_MASK)) if (!info.vex_b1 || (info.flags & IF_ERROR_MASK))
{ {
return false; return false;
} }
info.vex_b2 = inputNext(info); info.vex_b2 = inputNext(info);
if (!info.vex_b2 || (info.flags& IF_ERROR_MASK)) if (!info.vex_b2 || (info.flags & IF_ERROR_MASK))
{ {
return false; return false;
} }
info.vex_r = (info.vex_b1 >> 7)& 0x01; info.vex_r = (info.vex_b1 >> 7) & 0x01;
info.vex_x = (info.vex_b1 >> 6)& 0x01; info.vex_x = (info.vex_b1 >> 6) & 0x01;
info.vex_b = (info.vex_b1 >> 5)& 0x01; info.vex_b = (info.vex_b1 >> 5) & 0x01;
info.vex_m_mmmm = (info.vex_b1 >> 0)& 0x1F; info.vex_m_mmmm = (info.vex_b1 >> 0) & 0x1F;
info.vex_w = (info.vex_b2 >> 7)& 0x01; info.vex_w = (info.vex_b2 >> 7) & 0x01;
info.vex_vvvv = (info.vex_b2 >> 3)& 0x0F; info.vex_vvvv = (info.vex_b2 >> 3) & 0x0F;
info.vex_l = (info.vex_b2 >> 2)& 0x01; info.vex_l = (info.vex_b2 >> 2) & 0x01;
info.vex_pp = (info.vex_b2 >> 0)& 0x03; info.vex_pp = (info.vex_b2 >> 0) & 0x03;
break; break;
case 0xC5: case 0xC5:
info.vex_b1 = inputNext(info); info.vex_b1 = inputNext(info);
if (!info.vex_b1 || (info.flags& IF_ERROR_MASK)) if (!info.vex_b1 || (info.flags & IF_ERROR_MASK))
{ {
return false; return false;
} }
info.vex_r = (info.vex_b1 >> 7)& 0x01; info.vex_r = (info.vex_b1 >> 7) & 0x01;
info.vex_x = 1; info.vex_x = 1;
info.vex_b = 1; info.vex_b = 1;
info.vex_m_mmmm = 1; info.vex_m_mmmm = 1;
info.vex_w = 0; info.vex_w = 0;
info.vex_vvvv = (info.vex_b1 >> 3)& 0x0F; info.vex_vvvv = (info.vex_b1 >> 3) & 0x0F;
info.vex_l = (info.vex_b1 >> 2)& 0x01; info.vex_l = (info.vex_b1 >> 2) & 0x01;
info.vex_pp = (info.vex_b1 >> 0)& 0x03; info.vex_pp = (info.vex_b1 >> 0) & 0x03;
break; break;
default: default:
assert(0); assert(0);
@ -513,19 +513,19 @@ bool InstructionDecoder::decodeOperands(InstructionInfo& info)
info.operand[i].access_mode = OperandAccessMode::READ; info.operand[i].access_mode = OperandAccessMode::READ;
if (i == 0) if (i == 0)
{ {
if (info.instrDefinition->flags& IDF_OPERAND1_WRITE) if (info.instrDefinition->flags & IDF_OPERAND1_WRITE)
{ {
info.operand[0].access_mode = OperandAccessMode::WRITE; info.operand[0].access_mode = OperandAccessMode::WRITE;
} else if (info.instrDefinition->flags& IDF_OPERAND1_READWRITE) } else if (info.instrDefinition->flags & IDF_OPERAND1_READWRITE)
{ {
info.operand[0].access_mode = OperandAccessMode::READWRITE; info.operand[0].access_mode = OperandAccessMode::READWRITE;
} }
} else if (i == 1) } else if (i == 1)
{ {
if (info.instrDefinition->flags& IDF_OPERAND2_WRITE) if (info.instrDefinition->flags & IDF_OPERAND2_WRITE)
{ {
info.operand[1].access_mode = OperandAccessMode::WRITE; info.operand[1].access_mode = OperandAccessMode::WRITE;
} else if (info.instrDefinition->flags& IDF_OPERAND2_READWRITE) } else if (info.instrDefinition->flags & IDF_OPERAND2_READWRITE)
{ {
info.operand[1].access_mode = OperandAccessMode::READWRITE; info.operand[1].access_mode = OperandAccessMode::READWRITE;
} }
@ -556,7 +556,7 @@ bool InstructionDecoder::decodeOperand(InstructionInfo& info, OperandInfo& opera
operand.lval.ptr.off = inputNext<uint32_t>(info); operand.lval.ptr.off = inputNext<uint32_t>(info);
operand.lval.ptr.seg = inputNext<uint16_t>(info); operand.lval.ptr.seg = inputNext<uint16_t>(info);
} }
if ((!operand.lval.ptr.off || !operand.lval.ptr.seg)&& (info.flags& IF_ERROR_MASK)) if ((!operand.lval.ptr.off || !operand.lval.ptr.seg) && (info.flags & IF_ERROR_MASK))
{ {
return false; return false;
} }
@ -596,7 +596,7 @@ bool InstructionDecoder::decodeOperand(InstructionInfo& info, OperandInfo& opera
info.modrm_reg_ext, operandSize); info.modrm_reg_ext, operandSize);
case DefinedOperandType::H: case DefinedOperandType::H:
assert(info.vex_op != 0); assert(info.vex_op != 0);
return decodeRegisterOperand(info, operand, RegisterClass::XMM, (0xF& ~info.vex_vvvv), return decodeRegisterOperand(info, operand, RegisterClass::XMM, (0xF & ~info.vex_vvvv),
operandSize); operandSize);
case DefinedOperandType::sI: case DefinedOperandType::sI:
operand.signed_lval = true; operand.signed_lval = true;
@ -619,12 +619,12 @@ bool InstructionDecoder::decodeOperand(InstructionInfo& info, OperandInfo& opera
{ {
assert(info.vex_op != 0); assert(info.vex_op != 0);
uint8_t imm = inputNext(info); uint8_t imm = inputNext(info);
if (!imm&& (info.flags& IF_ERROR_MASK)) if (!imm && (info.flags & IF_ERROR_MASK))
{ {
return false; return false;
} }
uint8_t mask = (m_disassemblerMode == DisassemblerMode::M64BIT) ? 0xF : 0x7; uint8_t mask = (m_disassemblerMode == DisassemblerMode::M64BIT) ? 0xF : 0x7;
return decodeRegisterOperand(info, operand, RegisterClass::XMM, mask& (imm >> 4), return decodeRegisterOperand(info, operand, RegisterClass::XMM, mask & (imm >> 4),
operandSize); operandSize);
} }
case DefinedOperandType::MR: case DefinedOperandType::MR:
@ -729,7 +729,7 @@ bool InstructionDecoder::decodeOperand(InstructionInfo& info, OperandInfo& opera
case DefinedOperandType::GS: case DefinedOperandType::GS:
if (m_disassemblerMode == DisassemblerMode::M64BIT) if (m_disassemblerMode == DisassemblerMode::M64BIT)
{ {
if ((operandType != DefinedOperandType::FS)&& if ((operandType != DefinedOperandType::FS) &&
(operandType != DefinedOperandType::GS)) (operandType != DefinedOperandType::GS))
{ {
info.flags |= IF_ERROR_OPERAND; info.flags |= IF_ERROR_OPERAND;
@ -768,25 +768,25 @@ void InstructionDecoder::resolveOperandAndAddressMode(InstructionInfo& info) con
switch (m_disassemblerMode) switch (m_disassemblerMode)
{ {
case DisassemblerMode::M16BIT: case DisassemblerMode::M16BIT:
info.operand_mode = (info.flags& IF_PREFIX_OPERAND_SIZE) ? 32 : 16; info.operand_mode = (info.flags & IF_PREFIX_OPERAND_SIZE) ? 32 : 16;
info.address_mode = (info.flags& IF_PREFIX_ADDRESS_SIZE) ? 32 : 16; info.address_mode = (info.flags & IF_PREFIX_ADDRESS_SIZE) ? 32 : 16;
break; break;
case DisassemblerMode::M32BIT: case DisassemblerMode::M32BIT:
info.operand_mode = (info.flags& IF_PREFIX_OPERAND_SIZE) ? 16 : 32; info.operand_mode = (info.flags & IF_PREFIX_OPERAND_SIZE) ? 16 : 32;
info.address_mode = (info.flags& IF_PREFIX_ADDRESS_SIZE) ? 16 : 32; info.address_mode = (info.flags & IF_PREFIX_ADDRESS_SIZE) ? 16 : 32;
break; break;
case DisassemblerMode::M64BIT: case DisassemblerMode::M64BIT:
if (info.eff_rexvex_w) if (info.eff_rexvex_w)
{ {
info.operand_mode = 64; info.operand_mode = 64;
} else if ((info.flags& IF_PREFIX_OPERAND_SIZE)) } else if ((info.flags & IF_PREFIX_OPERAND_SIZE))
{ {
info.operand_mode = 16; info.operand_mode = 16;
} else } else
{ {
info.operand_mode = (info.instrDefinition->flags& IDF_DEFAULT_64) ? 64 : 32; info.operand_mode = (info.instrDefinition->flags & IDF_DEFAULT_64) ? 64 : 32;
} }
info.address_mode = (info.flags& IF_PREFIX_ADDRESS_SIZE) ? 32 : 64; info.address_mode = (info.flags & IF_PREFIX_ADDRESS_SIZE) ? 32 : 64;
break; break;
default: default:
assert(0); assert(0);
@ -797,26 +797,26 @@ void InstructionDecoder::calculateEffectiveRexVexValues(InstructionInfo& info) c
{ {
assert(info.instrDefinition); assert(info.instrDefinition);
uint8_t rex = info.rex; uint8_t rex = info.rex;
if (info.flags& IF_PREFIX_VEX) if (info.flags & IF_PREFIX_VEX)
{ {
switch (info.vex_op) switch (info.vex_op)
{ {
case 0xC4: case 0xC4:
rex = ((~(info.vex_b1 >> 5)& 0x07) | ((info.vex_b2 >> 4)& 0x08)); rex = ((~(info.vex_b1 >> 5) & 0x07) | ((info.vex_b2 >> 4) & 0x08));
break; break;
case 0xC5: case 0xC5:
rex = (~(info.vex_b1 >> 5))& 4; rex = (~(info.vex_b1 >> 5)) & 4;
break; break;
default: default:
assert(0); assert(0);
} }
} }
rex &= (info.instrDefinition->flags& 0x000F); rex &= (info.instrDefinition->flags & 0x000F);
info.eff_rexvex_w = (rex >> 3)& 0x01; info.eff_rexvex_w = (rex >> 3) & 0x01;
info.eff_rexvex_r = (rex >> 2)& 0x01; info.eff_rexvex_r = (rex >> 2) & 0x01;
info.eff_rexvex_x = (rex >> 1)& 0x01; info.eff_rexvex_x = (rex >> 1) & 0x01;
info.eff_rexvex_b = (rex >> 0)& 0x01; info.eff_rexvex_b = (rex >> 0) & 0x01;
info.eff_vex_l = info.vex_l&& (info.instrDefinition->flags& IDF_ACCEPTS_VEXL); info.eff_vex_l = info.vex_l && (info.instrDefinition->flags & IDF_ACCEPTS_VEXL);
} }
bool InstructionDecoder::decodePrefixes(InstructionInfo& info) bool InstructionDecoder::decodePrefixes(InstructionInfo& info)
@ -870,8 +870,8 @@ bool InstructionDecoder::decodePrefixes(InstructionInfo& info)
info.flags |= IF_PREFIX_ADDRESS_SIZE; info.flags |= IF_PREFIX_ADDRESS_SIZE;
break; break;
default: default:
if ((m_disassemblerMode == DisassemblerMode::M64BIT)&& if ((m_disassemblerMode == DisassemblerMode::M64BIT) &&
(inputCurrent()& 0xF0) == 0x40) (inputCurrent() & 0xF0) == 0x40)
{ {
info.flags |= IF_PREFIX_REX; info.flags |= IF_PREFIX_REX;
info.rex = inputCurrent(); info.rex = inputCurrent();
@ -884,7 +884,7 @@ bool InstructionDecoder::decodePrefixes(InstructionInfo& info)
// Increase the input offset, if a prefix was found // Increase the input offset, if a prefix was found
if (!done) if (!done)
{ {
if (!inputNext(info)&& (info.flags& IF_ERROR_MASK)) if (!inputNext(info) && (info.flags & IF_ERROR_MASK))
{ {
return false; return false;
} }
@ -892,12 +892,12 @@ bool InstructionDecoder::decodePrefixes(InstructionInfo& info)
} while (!done); } while (!done);
// TODO: Check for multiple prefixes of the same group // TODO: Check for multiple prefixes of the same group
// Parse REX Prefix // Parse REX Prefix
if (info.flags& IF_PREFIX_REX) if (info.flags & IF_PREFIX_REX)
{ {
info.rex_w = (info.rex >> 3)& 0x01; info.rex_w = (info.rex >> 3) & 0x01;
info.rex_r = (info.rex >> 2)& 0x01; info.rex_r = (info.rex >> 2) & 0x01;
info.rex_x = (info.rex >> 1)& 0x01; info.rex_x = (info.rex >> 1) & 0x01;
info.rex_b = (info.rex >> 0)& 0x01; info.rex_b = (info.rex >> 0) & 0x01;
} }
return true; return true;
} }
@ -906,7 +906,7 @@ bool InstructionDecoder::decodeOpcode(InstructionInfo& info)
{ {
using namespace Internal; using namespace Internal;
// Read first opcode byte // Read first opcode byte
if (!inputNext(info)&& (info.flags& IF_ERROR_MASK)) if (!inputNext(info) && (info.flags & IF_ERROR_MASK))
{ {
return false; return false;
} }
@ -934,8 +934,8 @@ bool InstructionDecoder::decodeOpcode(InstructionInfo& info)
const InstructionDefinition *instrDefinition = const InstructionDefinition *instrDefinition =
GetInstructionDefinition(node); GetInstructionDefinition(node);
// Check for invalid 64 bit instruction // Check for invalid 64 bit instruction
if ((m_disassemblerMode == DisassemblerMode::M64BIT)&& if ((m_disassemblerMode == DisassemblerMode::M64BIT) &&
(instrDefinition->flags& IDF_INVALID_64)) (instrDefinition->flags & IDF_INVALID_64))
{ {
info.flags |= IF_ERROR_INVALID_64; info.flags |= IF_ERROR_INVALID_64;
return false; return false;
@ -956,12 +956,12 @@ bool InstructionDecoder::decodeOpcode(InstructionInfo& info)
return true; return true;
case OpcodeTreeNodeType::TABLE: case OpcodeTreeNodeType::TABLE:
// Read next opcode byte // Read next opcode byte
if (!inputNext(info)&& (info.flags& IF_ERROR_MASK)) if (!inputNext(info) && (info.flags & IF_ERROR_MASK))
{ {
return false; return false;
} }
// Update instruction info // Update instruction info
assert((info.opcode_length > 0)&& (info.opcode_length < 3)); assert((info.opcode_length > 0) && (info.opcode_length < 3));
info.opcode[info.opcode_length] = inputCurrent(); info.opcode[info.opcode_length] = inputCurrent();
info.opcode_length++; info.opcode_length++;
// Set child node index for next iteration // Set child node index for next iteration
@ -993,13 +993,13 @@ bool InstructionDecoder::decodeOpcode(InstructionInfo& info)
break; break;
case OpcodeTreeNodeType::MANDATORY: case OpcodeTreeNodeType::MANDATORY:
// Check if there are any prefixes present // Check if there are any prefixes present
if (info.flags& IF_PREFIX_REP) if (info.flags & IF_PREFIX_REP)
{ {
index = 1; // F2 index = 1; // F2
} else if (info.flags& IF_PREFIX_REPNE) } else if (info.flags & IF_PREFIX_REPNE)
{ {
index = 2; // F3 index = 2; // F3
} else if (info.flags& IF_PREFIX_OPERAND_SIZE) } else if (info.flags & IF_PREFIX_OPERAND_SIZE)
{ {
index = 3; // 66 index = 3; // 66
} }
@ -1007,7 +1007,7 @@ bool InstructionDecoder::decodeOpcode(InstructionInfo& info)
{ {
index = 0; index = 0;
} }
if (index&& (GetOpcodeTreeChild(node, index) != 0)) if (index && (GetOpcodeTreeChild(node, index) != 0))
{ {
// Remove REP and REPNE prefix // Remove REP and REPNE prefix
info.flags &= ~IF_PREFIX_REP; info.flags &= ~IF_PREFIX_REP;
@ -1032,13 +1032,13 @@ bool InstructionDecoder::decodeOpcode(InstructionInfo& info)
switch (m_disassemblerMode) switch (m_disassemblerMode)
{ {
case DisassemblerMode::M16BIT: case DisassemblerMode::M16BIT:
index = (info.flags& IF_PREFIX_ADDRESS_SIZE) ? 1 : 0; index = (info.flags & IF_PREFIX_ADDRESS_SIZE) ? 1 : 0;
break; break;
case DisassemblerMode::M32BIT: case DisassemblerMode::M32BIT:
index = (info.flags& IF_PREFIX_ADDRESS_SIZE) ? 0 : 1; index = (info.flags & IF_PREFIX_ADDRESS_SIZE) ? 0 : 1;
break; break;
case DisassemblerMode::M64BIT: case DisassemblerMode::M64BIT:
index = (info.flags& IF_PREFIX_ADDRESS_SIZE) ? 1 : 2; index = (info.flags & IF_PREFIX_ADDRESS_SIZE) ? 1 : 2;
break; break;
default: default:
assert(0); assert(0);
@ -1048,13 +1048,13 @@ bool InstructionDecoder::decodeOpcode(InstructionInfo& info)
switch (m_disassemblerMode) switch (m_disassemblerMode)
{ {
case DisassemblerMode::M16BIT: case DisassemblerMode::M16BIT:
index = (info.flags& IF_PREFIX_OPERAND_SIZE) ? 1 : 0; index = (info.flags & IF_PREFIX_OPERAND_SIZE) ? 1 : 0;
break; break;
case DisassemblerMode::M32BIT: case DisassemblerMode::M32BIT:
index = (info.flags& IF_PREFIX_OPERAND_SIZE) ? 0 : 1; index = (info.flags & IF_PREFIX_OPERAND_SIZE) ? 0 : 1;
break; break;
case DisassemblerMode::M64BIT: case DisassemblerMode::M64BIT:
index = (info.rex_w) ? 2 : ((info.flags& IF_PREFIX_OPERAND_SIZE) ? 0 : 1); index = (info.rex_w) ? 2 : ((info.flags & IF_PREFIX_OPERAND_SIZE) ? 0 : 1);
break; break;
default: default:
assert(0); assert(0);
@ -1100,7 +1100,7 @@ bool InstructionDecoder::decodeOpcode(InstructionInfo& info)
} }
// Read the actual 3dnow opcode // Read the actual 3dnow opcode
info.opcode[2] = inputNext(info); info.opcode[2] = inputNext(info);
if (!info.opcode[2]&& (info.flags& IF_ERROR_MASK)) if (!info.opcode[2] && (info.flags & IF_ERROR_MASK))
{ {
return false; return false;
} }
@ -1125,20 +1125,20 @@ bool InstructionDecoder::decodeOpcode(InstructionInfo& info)
} }
if (info.operand[0].type != OperandType::NONE) if (info.operand[0].type != OperandType::NONE)
{ {
if (info.instrDefinition->flags& IDF_OPERAND1_WRITE) if (info.instrDefinition->flags & IDF_OPERAND1_WRITE)
{ {
info.operand[0].access_mode = OperandAccessMode::WRITE; info.operand[0].access_mode = OperandAccessMode::WRITE;
} else if (info.instrDefinition->flags& IDF_OPERAND1_READWRITE) } else if (info.instrDefinition->flags & IDF_OPERAND1_READWRITE)
{ {
info.operand[0].access_mode = OperandAccessMode::READWRITE; info.operand[0].access_mode = OperandAccessMode::READWRITE;
} }
} }
if (info.operand[1].type != OperandType::NONE) if (info.operand[1].type != OperandType::NONE)
{ {
if (info.instrDefinition->flags& IDF_OPERAND2_WRITE) if (info.instrDefinition->flags & IDF_OPERAND2_WRITE)
{ {
info.operand[1].access_mode = OperandAccessMode::WRITE; info.operand[1].access_mode = OperandAccessMode::WRITE;
} else if (info.instrDefinition->flags& IDF_OPERAND2_READWRITE) } else if (info.instrDefinition->flags & IDF_OPERAND2_READWRITE)
{ {
info.operand[1].access_mode = OperandAccessMode::READWRITE; info.operand[1].access_mode = OperandAccessMode::READWRITE;
} }
@ -1148,7 +1148,7 @@ bool InstructionDecoder::decodeOpcode(InstructionInfo& info)
} }
case OpcodeTreeNodeType::VEX: case OpcodeTreeNodeType::VEX:
if ((m_disassemblerMode == DisassemblerMode::M64BIT) || if ((m_disassemblerMode == DisassemblerMode::M64BIT) ||
(((inputCurrent() >> 6)& 0x03) == 0x03)) (((inputCurrent() >> 6) & 0x03) == 0x03))
{ {
// Decode vex prefix // Decode vex prefix
if (!decodeVex(info)) if (!decodeVex(info))
@ -1181,11 +1181,11 @@ bool InstructionDecoder::decodeOpcode(InstructionInfo& info)
} }
break; break;
case OpcodeTreeNodeType::VEXW: case OpcodeTreeNodeType::VEXW:
assert(info.flags& IF_PREFIX_VEX); assert(info.flags & IF_PREFIX_VEX);
index = info.vex_w; index = info.vex_w;
break; break;
case OpcodeTreeNodeType::VEXL: case OpcodeTreeNodeType::VEXL:
assert(info.flags& IF_PREFIX_VEX); assert(info.flags & IF_PREFIX_VEX);
index = info.vex_l; index = info.vex_l;
break; break;
default: default:
@ -1243,7 +1243,7 @@ bool InstructionDecoder::decodeInstruction(InstructionInfo& info)
goto DecodeError; goto DecodeError;
} }
// SWAPGS is only valid in 64 bit mode // SWAPGS is only valid in 64 bit mode
if ((info.mnemonic == InstructionMnemonic::SWAPGS)&& if ((info.mnemonic == InstructionMnemonic::SWAPGS) &&
(m_disassemblerMode != DisassemblerMode::M64BIT)) (m_disassemblerMode != DisassemblerMode::M64BIT))
{ {
info.flags &= IF_ERROR_INVALID; info.flags &= IF_ERROR_INVALID;
@ -1252,13 +1252,13 @@ bool InstructionDecoder::decodeInstruction(InstructionInfo& info)
// Handle aliases // Handle aliases
if (info.mnemonic == InstructionMnemonic::XCHG) if (info.mnemonic == InstructionMnemonic::XCHG)
{ {
if ((info.operand[0].type == OperandType::REGISTER&& if ((info.operand[0].type == OperandType::REGISTER &&
info.operand[0].base == Register::AX&& info.operand[0].base == Register::AX &&
info.operand[1].type == OperandType::REGISTER&& info.operand[1].type == OperandType::REGISTER &&
info.operand[1].base == Register::AX) || info.operand[1].base == Register::AX) ||
(info.operand[0].type == OperandType::REGISTER&& (info.operand[0].type == OperandType::REGISTER &&
info.operand[0].base == Register::EAX&& info.operand[0].base == Register::EAX &&
info.operand[1].type == OperandType::REGISTER&& info.operand[1].type == OperandType::REGISTER &&
info.operand[1].base == Register::EAX)) info.operand[1].base == Register::EAX))
{ {
info.mnemonic = InstructionMnemonic::NOP; info.mnemonic = InstructionMnemonic::NOP;
@ -1268,7 +1268,7 @@ bool InstructionDecoder::decodeInstruction(InstructionInfo& info)
info.operand[1].access_mode = OperandAccessMode::NA; info.operand[1].access_mode = OperandAccessMode::NA;
} }
} }
if ((info.mnemonic == InstructionMnemonic::NOP)&& (info.flags& IF_PREFIX_REP)) if ((info.mnemonic == InstructionMnemonic::NOP) && (info.flags & IF_PREFIX_REP))
{ {
info.mnemonic = InstructionMnemonic::PAUSE; info.mnemonic = InstructionMnemonic::PAUSE;
info.flags &= ~IF_PREFIX_REP; info.flags &= ~IF_PREFIX_REP;
@ -1282,7 +1282,7 @@ DecodeError:
// Increment instruction pointer. // Increment instruction pointer.
m_instructionPointer += 1; m_instructionPointer += 1;
// Backup all error flags, the instruction length and the instruction address // Backup all error flags, the instruction length and the instruction address
uint32_t flags = info.flags& (IF_ERROR_MASK | 0x00000007); uint32_t flags = info.flags & (IF_ERROR_MASK | 0x00000007);
uint8_t length = info.length; uint8_t length = info.length;
uint8_t firstByte = info.data[0]; uint8_t firstByte = info.data[0];
uint64_t instrAddress = info.instrAddress; uint64_t instrAddress = info.instrAddress;
@ -1303,7 +1303,7 @@ DecodeError:
} }
// Return with error, if the end of the input source was reached while decoding the // Return with error, if the end of the input source was reached while decoding the
// invalid instruction // invalid instruction
if (info.flags& IF_ERROR_END_OF_INPUT) if (info.flags & IF_ERROR_END_OF_INPUT)
{ {
info.length = 0; info.length = 0;
return false; return false;

View File

@ -28,6 +28,11 @@
***************************************************************************************************/ ***************************************************************************************************/
/**
* @file
* @brief Instruction decoder classes.
*/
#ifndef _ZYDIS_INSTRUCTIONDECODER_HPP_ #ifndef _ZYDIS_INSTRUCTIONDECODER_HPP_
#define _ZYDIS_INSTRUCTIONDECODER_HPP_ #define _ZYDIS_INSTRUCTIONDECODER_HPP_
@ -45,34 +50,10 @@ namespace Zydis
*/ */
class BaseInput class BaseInput
{ {
friend class InstructionDecoder;
private: private:
uint8_t m_currentInput; uint8_t m_currentInput;
protected: private:
/**
* @brief Override this method in your custom data source implementations.
* Reads the next byte from the data source. This method increases the current
* input position by one.
* @return The current input byte.
*/
virtual uint8_t internalInputPeek() = 0;
/**
* @brief Override this method in your custom data source implementations.
* Reads the next byte from the data source. This method does NOT increase the
* current input position.
* @return The current input byte.
*/
virtual uint8_t internalInputNext() = 0;
protected:
/**
* @brief Default constructor.
*/
BaseInput() { };
public:
/**
* @brief Destructor.
*/
virtual ~BaseInput() { };
public:
/** /**
* @brief Reads the next byte from the data source. This method does NOT increase the * @brief Reads the next byte from the data source. This method does NOT increase the
* current input position or the @c length field of the @c info parameter. * current input position or the @c length field of the @c info parameter.
@ -111,6 +92,31 @@ public:
* @return The current input byte. * @return The current input byte.
*/ */
uint8_t inputCurrent() const; uint8_t inputCurrent() const;
protected:
/**
* @brief Override this method in your custom data source implementations.
* Reads the next byte from the data source. This method increases the current
* input position by one.
* @return The current input byte.
*/
virtual uint8_t internalInputPeek() = 0;
/**
* @brief Override this method in your custom data source implementations.
* Reads the next byte from the data source. This method does NOT increase the
* current input position.
* @return The current input byte.
*/
virtual uint8_t internalInputNext() = 0;
protected:
/**
* @brief Default constructor.
*/
BaseInput() { };
public:
/**
* @brief Destructor.
*/
virtual ~BaseInput() { };
public: public:
/** /**
* @brief Override this method in your custom data source implementations. * @brief Override this method in your custom data source implementations.
@ -175,7 +181,7 @@ inline T BaseInput::inputNext(InstructionInfo& info)
for (unsigned i = 0; i < (sizeof(T) / sizeof(uint8_t)); ++i) for (unsigned i = 0; i < (sizeof(T) / sizeof(uint8_t)); ++i)
{ {
T b = inputNext(info); T b = inputNext(info);
if (!b&& (info.flags& IF_ERROR_MASK)) if (!b && (info.flags & IF_ERROR_MASK))
{ {
return 0; return 0;
} }

View File

@ -40,7 +40,7 @@ namespace Zydis
/* BaseInstructionFormatter ================================================================ */ /* BaseInstructionFormatter ================================================================ */
const char *BaseInstructionFormatter::m_registerStrings[] = const char* BaseInstructionFormatter::m_registerStrings[] =
{ {
/* 8 bit general purpose registers */ /* 8 bit general purpose registers */
"al", "cl", "dl", "bl", "al", "cl", "dl", "bl",
@ -238,13 +238,13 @@ void BaseInstructionFormatter::outputAppendAddress(const InstructionInfo& info,
} }
} else } else
{ {
if (info.flags& IF_DISASSEMBLER_MODE_16) if (info.flags & IF_DISASSEMBLER_MODE_16)
{ {
outputAppendFormatted("%.4X", address); outputAppendFormatted("%.4X", address);
} else if (info.flags& IF_DISASSEMBLER_MODE_32) } else if (info.flags & IF_DISASSEMBLER_MODE_32)
{ {
outputAppendFormatted("%.8lX", address); outputAppendFormatted("%.8lX", address);
} else if (info.flags& IF_DISASSEMBLER_MODE_64) } else if (info.flags & IF_DISASSEMBLER_MODE_64)
{ {
outputAppendFormatted("%.16llX", address); outputAppendFormatted("%.16llX", address);
} else } else
@ -294,7 +294,7 @@ void BaseInstructionFormatter::outputAppendImmediate(const InstructionInfo& info
} }
} }
uint64_t offset = 0; uint64_t offset = 0;
const char *name = nullptr; const char* name = nullptr;
if (resolveSymbols) if (resolveSymbols)
{ {
name = resolveSymbol(info, value, offset); name = resolveSymbol(info, value, offset);
@ -317,7 +317,7 @@ void BaseInstructionFormatter::outputAppendImmediate(const InstructionInfo& info
void BaseInstructionFormatter::outputAppendDisplacement(const OperandInfo& operand) void BaseInstructionFormatter::outputAppendDisplacement(const OperandInfo& operand)
{ {
assert(operand.offset > 0); assert(operand.offset > 0);
if ((operand.base == Register::NONE)&& (operand.index == Register::NONE)) if ((operand.base == Register::NONE) && (operand.index == Register::NONE))
{ {
// Assume the displacement value is unsigned // Assume the displacement value is unsigned
assert(operand.scale == 0); assert(operand.scale == 0);
@ -409,7 +409,7 @@ void IntelInstructionFormatter::formatOperand(const InstructionInfo& info,
outputAppend(registerToString(operand.base)); outputAppend(registerToString(operand.base));
break; break;
case OperandType::MEMORY: case OperandType::MEMORY:
if (info.flags& IF_PREFIX_SEGMENT) if (info.flags & IF_PREFIX_SEGMENT)
{ {
outputAppendFormatted("%s:", registerToString(info.segment)); outputAppendFormatted("%s:", registerToString(info.segment));
} }
@ -481,14 +481,14 @@ void IntelInstructionFormatter::formatOperand(const InstructionInfo& info,
void IntelInstructionFormatter::internalFormatInstruction(const InstructionInfo& info) void IntelInstructionFormatter::internalFormatInstruction(const InstructionInfo& info)
{ {
// Append string prefixes // Append string prefixes
if (info.flags& IF_PREFIX_LOCK) if (info.flags & IF_PREFIX_LOCK)
{ {
outputAppend("lock "); outputAppend("lock ");
} }
if (info.flags& IF_PREFIX_REP) if (info.flags & IF_PREFIX_REP)
{ {
outputAppend("rep "); outputAppend("rep ");
} else if (info.flags& IF_PREFIX_REPNE) } else if (info.flags & IF_PREFIX_REPNE)
{ {
outputAppend("repne "); outputAppend("repne ");
} }
@ -507,7 +507,7 @@ void IntelInstructionFormatter::internalFormatInstruction(const InstructionInfo&
(info.operand[0].size != info.operand[1].size)) (info.operand[0].size != info.operand[1].size))
{ {
cast = true; cast = true;
} else if (info.operand[1].type == OperandType::REGISTER&& } else if (info.operand[1].type == OperandType::REGISTER &&
info.operand[1].base == Register::CL) info.operand[1].base == Register::CL)
{ {
switch (info.mnemonic) switch (info.mnemonic)
@ -537,14 +537,14 @@ void IntelInstructionFormatter::internalFormatInstruction(const InstructionInfo&
{ {
outputAppend(", "); outputAppend(", ");
bool cast = false; bool cast = false;
if (info.operand[1].type == OperandType::MEMORY&& if (info.operand[1].type == OperandType::MEMORY &&
info.operand[0].size != info.operand[1].size&& info.operand[0].size != info.operand[1].size &&
((info.operand[0].type != OperandType::REGISTER) || ((info.operand[0].type != OperandType::REGISTER) ||
((info.operand[0].base != Register::ES)&& ((info.operand[0].base != Register::ES) &&
(info.operand[0].base != Register::CS)&& (info.operand[0].base != Register::CS) &&
(info.operand[0].base != Register::SS)&& (info.operand[0].base != Register::SS) &&
(info.operand[0].base != Register::DS)&& (info.operand[0].base != Register::DS) &&
(info.operand[0].base != Register::FS)&& (info.operand[0].base != Register::FS) &&
(info.operand[0].base != Register::GS)))) (info.operand[0].base != Register::GS))))
{ {
cast = true; cast = true;
@ -560,7 +560,7 @@ void IntelInstructionFormatter::internalFormatInstruction(const InstructionInfo&
{ {
outputAppend(", "); outputAppend(", ");
bool cast = false; bool cast = false;
if (info.operand[2].type == OperandType::MEMORY&& if (info.operand[2].type == OperandType::MEMORY &&
(info.operand[2].size != info.operand[1].size)) (info.operand[2].size != info.operand[1].size))
{ {
cast = true; cast = true;

View File

@ -28,6 +28,11 @@
***************************************************************************************************/ ***************************************************************************************************/
/**
* @file
* @brief Instruction formatting classes.
*/
#ifndef _ZYDIS_INSTRUCTIONFORMATTER_HPP_ #ifndef _ZYDIS_INSTRUCTIONFORMATTER_HPP_
#define _ZYDIS_INSTRUCTIONFORMATTER_HPP_ #define _ZYDIS_INSTRUCTIONFORMATTER_HPP_

View File

@ -28,6 +28,11 @@
***************************************************************************************************/ ***************************************************************************************************/
/**
* @file
* @brief The opcode table definition, mostly internal stuff.
*/
#ifndef _ZYDIS_OPCODETABLE_HPP_ #ifndef _ZYDIS_OPCODETABLE_HPP_
#define _ZYDIS_OPCODETABLE_HPP_ #define _ZYDIS_OPCODETABLE_HPP_
@ -1607,7 +1612,7 @@ extern const char* instrMnemonicStrings[];
*/ */
inline OpcodeTreeNodeType GetOpcodeNodeType(OpcodeTreeNode node) inline OpcodeTreeNodeType GetOpcodeNodeType(OpcodeTreeNode node)
{ {
return static_cast<OpcodeTreeNodeType>((node >> 12)& 0x0F); return static_cast<OpcodeTreeNodeType>((node >> 12) & 0x0F);
} }
/** /**
@ -1617,7 +1622,7 @@ inline OpcodeTreeNodeType GetOpcodeNodeType(OpcodeTreeNode node)
*/ */
inline uint16_t GetOpcodeNodeValue(OpcodeTreeNode node) inline uint16_t GetOpcodeNodeValue(OpcodeTreeNode node)
{ {
return (node& 0x0FFF); return (node & 0x0FFF);
} }
/** /**
@ -1698,7 +1703,7 @@ inline OpcodeTreeNode GetOpcodeTreeChild(OpcodeTreeNode parent, uint16_t index)
inline const InstructionDefinition* GetInstructionDefinition(OpcodeTreeNode node) inline const InstructionDefinition* GetInstructionDefinition(OpcodeTreeNode node)
{ {
assert(GetOpcodeNodeType(node) == OpcodeTreeNodeType::INSTRUCTION_DEFINITION); assert(GetOpcodeNodeType(node) == OpcodeTreeNodeType::INSTRUCTION_DEFINITION);
return& instrDefinitions[node& 0x0FFF]; return& instrDefinitions[node & 0x0FFF];
} }
/** /**
@ -1735,7 +1740,7 @@ inline uint16_t GetSimpleOperandSize(DefinedOperandSize operandSize)
*/ */
inline DefinedOperandSize GetComplexOperandMemSize(DefinedOperandSize operandSize) inline DefinedOperandSize GetComplexOperandMemSize(DefinedOperandSize operandSize)
{ {
return static_cast<DefinedOperandSize>(static_cast<uint8_t>(operandSize)& 0x0F); return static_cast<DefinedOperandSize>(static_cast<uint8_t>(operandSize) & 0x0F);
} }
/** /**
@ -1745,7 +1750,7 @@ inline DefinedOperandSize GetComplexOperandMemSize(DefinedOperandSize operandSiz
*/ */
inline DefinedOperandSize GetComplexOperandRegSize(DefinedOperandSize operandSize) inline DefinedOperandSize GetComplexOperandRegSize(DefinedOperandSize operandSize)
{ {
return static_cast<DefinedOperandSize>((static_cast<uint8_t>(operandSize) >> 4)& 0x0F); return static_cast<DefinedOperandSize>((static_cast<uint8_t>(operandSize) >> 4) & 0x0F);
} }
} }

View File

@ -28,6 +28,11 @@
***************************************************************************************************/ ***************************************************************************************************/
/**
* @file
* @brief Classes for symbol resolving in the disassembly.
*/
#ifndef _ZYDIS_SYMBOLRESOLVER_HPP_ #ifndef _ZYDIS_SYMBOLRESOLVER_HPP_
#define _ZYDIS_SYMBOLRESOLVER_HPP_ #define _ZYDIS_SYMBOLRESOLVER_HPP_

View File

@ -37,33 +37,33 @@ namespace Zydis
uint64_t CalcAbsoluteTarget(const InstructionInfo& info, const OperandInfo& operand) uint64_t CalcAbsoluteTarget(const InstructionInfo& info, const OperandInfo& operand)
{ {
assert((operand.type == OperandType::REL_IMMEDIATE) || assert((operand.type == OperandType::REL_IMMEDIATE) ||
((operand.type == OperandType::MEMORY)&& (operand.base == Register::RIP))); ((operand.type == OperandType::MEMORY) && (operand.base == Register::RIP)));
uint64_t truncMask = 0xFFFFFFFFFFFFFFFFull; uint64_t truncMask = 0xFFFFFFFFFFFFFFFFull;
if (!(info.flags& IF_DISASSEMBLER_MODE_64)) if (!(info.flags & IF_DISASSEMBLER_MODE_64))
{ {
truncMask >>= (64 - info.operand_mode); truncMask >>= (64 - info.operand_mode);
} }
uint16_t size = operand.size; uint16_t size = operand.size;
if ((operand.type == OperandType::MEMORY)&& (operand.base == Register::RIP)) if ((operand.type == OperandType::MEMORY) && (operand.base == Register::RIP))
{ {
size = operand.offset; size = operand.offset;
} }
switch (size) switch (size)
{ {
case 8: case 8:
return (info.instrPointer + operand.lval.sbyte)& truncMask; return (info.instrPointer + operand.lval.sbyte) & truncMask;
case 16: case 16:
{ {
uint32_t delta = operand.lval.sword& truncMask; uint32_t delta = operand.lval.sword & truncMask;
if ((info.instrPointer + delta) > 0xFFFF) if ((info.instrPointer + delta) > 0xFFFF)
{ {
return (info.instrPointer& 0xF0000) + ((info.instrPointer + delta)& 0xFFFF); return (info.instrPointer& 0xF0000) + ((info.instrPointer + delta) & 0xFFFF);
} }
return info.instrPointer + delta; return info.instrPointer + delta;
} }
case 32: case 32:
return (info.instrPointer + operand.lval.sdword)& truncMask; return (info.instrPointer + operand.lval.sdword) & truncMask;
default: default:
assert(0); assert(0);
} }

View File

@ -28,6 +28,11 @@
***************************************************************************************************/ ***************************************************************************************************/
/**
* @file
* @brief Utility functions.
*/
#ifndef _ZYDIS_UTILS_HPP_ #ifndef _ZYDIS_UTILS_HPP_
#define _ZYDIS_UTILS_HPP_ #define _ZYDIS_UTILS_HPP_