You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2330 lines
57 KiB
2330 lines
57 KiB
/*
|
|
* FCML - Free Code Manipulation Library.
|
|
* Copyright (C) 2010-2019 Slawomir Wojtasiak
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
|
|
/** @file fcml_disassembler.hpp
|
|
* C++ wrapper for the FCML disassembler.
|
|
*
|
|
* @copyright Copyright (C) 2010-2017 Slawomir Wojtasiak. All rights reserved.
|
|
* This project is released under the GNU Lesser General Public License.
|
|
*/
|
|
|
|
#ifndef FCML_DISASSEMBLER_HPP_
|
|
#define FCML_DISASSEMBLER_HPP_
|
|
|
|
#include <string.h>
|
|
|
|
#include "fcml_disassembler.h"
|
|
|
|
#include "fcml_common.hpp"
|
|
#include "fcml_errors.hpp"
|
|
#include "fcml_dialect.hpp"
|
|
|
|
namespace fcml {
|
|
|
|
/**
|
|
* Component can not be initialized correctly.
|
|
* @since 1.1.0
|
|
*/
|
|
class DisassemblingFailedException: public ErrorContainerAwareException {
|
|
public:
|
|
DisassemblingFailedException(const fcml_cstring &msg,
|
|
const ErrorContainer &errorContainer,
|
|
fcml_ceh_error error = FCML_CEH_GEC_NO_ERROR) :
|
|
ErrorContainerAwareException(msg, errorContainer, error) {
|
|
}
|
|
};
|
|
|
|
/** Disassembler configuration.
|
|
*
|
|
* It's counterpart to the fcml_st_disassembler_conf structure.
|
|
* @since 1.1.0
|
|
*/
|
|
class DisassemblerConf {
|
|
public:
|
|
|
|
/**
|
|
* Default constructor.
|
|
* @since 1.1.0
|
|
*/
|
|
DisassemblerConf() :
|
|
_throwExceptionOnError(true),
|
|
_incrementIP(true),
|
|
_enableErrorMessages(true),
|
|
_carryFlagConditionalSuffix(false),
|
|
_conditionalGroup(false),
|
|
_shortForms(false),
|
|
_extendDispToASA(false),
|
|
_failIfUnknownInstruction(false) {
|
|
}
|
|
|
|
/** @since 1.1.0 */
|
|
bool isCarryFlagConditionalSuffix() const {
|
|
return _carryFlagConditionalSuffix;
|
|
}
|
|
|
|
/** @since 1.1.0 */
|
|
void setCarryFlagConditionalSuffix(bool carryFlagConditionalSuffix) {
|
|
_carryFlagConditionalSuffix = carryFlagConditionalSuffix;
|
|
}
|
|
|
|
/** @since 1.1.0 */
|
|
fcml_uint8_t getConditionalGroup() const {
|
|
return _conditionalGroup;
|
|
}
|
|
|
|
/** @since 1.1.0 */
|
|
void setConditionalGroup(fcml_uint8_t conditionalGroup) {
|
|
_conditionalGroup = conditionalGroup;
|
|
}
|
|
|
|
/** @since 1.1.0 */
|
|
bool isEnableErrorMessages() const {
|
|
return _enableErrorMessages;
|
|
}
|
|
|
|
/** @since 1.1.0 */
|
|
void setEnableErrorMessages(bool enableErrorMessages) {
|
|
_enableErrorMessages = enableErrorMessages;
|
|
}
|
|
|
|
/** @since 1.1.0 */
|
|
bool isExtendDispToAsa() const {
|
|
return _extendDispToASA;
|
|
}
|
|
|
|
/** @since 1.1.0 */
|
|
void setExtendDispToAsa(bool extendDispToAsa) {
|
|
_extendDispToASA = extendDispToAsa;
|
|
}
|
|
|
|
/** @since 1.1.0 */
|
|
bool isFailIfUnknownInstruction() const {
|
|
return _failIfUnknownInstruction;
|
|
}
|
|
|
|
/** @since 1.1.0 */
|
|
void setFailIfUnknownInstruction(bool failIfUnknownInstruction) {
|
|
_failIfUnknownInstruction = failIfUnknownInstruction;
|
|
}
|
|
|
|
/** @since 1.1.0 */
|
|
bool isIncrementIp() const {
|
|
return _incrementIP;
|
|
}
|
|
|
|
/** @since 1.1.0 */
|
|
void setIncrementIp(bool incrementIp) {
|
|
_incrementIP = incrementIp;
|
|
}
|
|
|
|
/** @since 1.1.0 */
|
|
bool isShortForms() const {
|
|
return _shortForms;
|
|
}
|
|
|
|
/** @since 1.1.0 */
|
|
void setShortForms(bool shortForms) {
|
|
_shortForms = shortForms;
|
|
}
|
|
|
|
/**
|
|
* Returns true if exception should be thrown when disassembling fails.
|
|
*
|
|
* @return True if exception is the preferred way of error
|
|
* handling in case of failure.
|
|
* @since 1.1.0
|
|
*/
|
|
bool isThrowExceptionOnError() const {
|
|
return _throwExceptionOnError;
|
|
}
|
|
|
|
/**
|
|
* Sets the way how the error handling is done.
|
|
*
|
|
* @param throwExceptionOnError True if exception should be thrown
|
|
* in case of failure.
|
|
* @since 1.1.0
|
|
*/
|
|
void setThrowExceptionOnError(bool throwExceptionOnError) {
|
|
_throwExceptionOnError = throwExceptionOnError;
|
|
}
|
|
|
|
private:
|
|
bool _throwExceptionOnError;
|
|
bool _incrementIP;
|
|
bool _enableErrorMessages;
|
|
bool _carryFlagConditionalSuffix;
|
|
fcml_uint8_t _conditionalGroup;
|
|
bool _shortForms;
|
|
bool _extendDispToASA;
|
|
bool _failIfUnknownInstruction;
|
|
|
|
};
|
|
|
|
/** Disassembler context.
|
|
* @since 1.1.0
|
|
*/
|
|
class DisassemblerContext {
|
|
public:
|
|
|
|
/**
|
|
* Creates empty disassembler context.
|
|
* @since 1.1.0
|
|
*/
|
|
DisassemblerContext() :
|
|
_code(NULL), _codeLength(0) {
|
|
}
|
|
|
|
/**
|
|
* Creates disassembler context for given piece of machine code.
|
|
*
|
|
* @param code A buffer with the machine code.
|
|
* @param codeLength Size of the buffer in bytes.
|
|
* @since 1.1.0
|
|
*/
|
|
DisassemblerContext(fcml_ptr code, fcml_usize codeLength) :
|
|
_code(code), _codeLength(codeLength) {
|
|
}
|
|
|
|
public:
|
|
|
|
/**
|
|
* Gets pointer to the machine code buffer.
|
|
*
|
|
* @return A pointer to the machine code.
|
|
* @since 1.1.0
|
|
*/
|
|
fcml_ptr getCode() const {
|
|
return _code;
|
|
}
|
|
|
|
/**
|
|
* Sets a new buffer with machine code for the context.
|
|
*
|
|
* @param code The new code buffer.
|
|
* @since 1.1.0
|
|
*/
|
|
void setCode(fcml_ptr code) {
|
|
_code = code;
|
|
}
|
|
|
|
/**
|
|
* Gets length of the buffer in bytes.
|
|
*
|
|
* @return Size of the buffer.
|
|
* @since 1.1.0
|
|
*/
|
|
fcml_usize getCodeLength() const {
|
|
return _codeLength;
|
|
}
|
|
|
|
/**
|
|
* Sets length of the code buffer in bytes.
|
|
*
|
|
* @param codeLength Size of the code.
|
|
* @since 1.1.0
|
|
*/
|
|
void setCodeLength(fcml_usize codeLength) {
|
|
_codeLength = codeLength;
|
|
}
|
|
|
|
/**
|
|
* Gets a reference to the configuration object associated with the context.
|
|
*
|
|
* @return The disassembler configuration.
|
|
* @since 1.1.0
|
|
*/
|
|
const DisassemblerConf& getDisassemblerConf() const {
|
|
return _disassemblerConf;
|
|
}
|
|
|
|
/**
|
|
* Gets a reference to the configuration object associated with the context.
|
|
*
|
|
* @return The disassembler configuration.
|
|
* @since 1.1.0
|
|
*/
|
|
DisassemblerConf& getDisassemblerConf() {
|
|
return _disassemblerConf;
|
|
}
|
|
|
|
/**
|
|
* Sets a new disassembler configuration for the context.
|
|
*
|
|
* @param disassemblerConf The new disassembler configuration.
|
|
* @since 1.1.0
|
|
*/
|
|
void setDisassemblerConf(DisassemblerConf disassemblerConf) {
|
|
_disassemblerConf = disassemblerConf;
|
|
}
|
|
|
|
/**
|
|
* Gets reference to the constant entry point instance
|
|
* associated with the context.
|
|
*
|
|
* @return Reference to the constant entry point.
|
|
* @since 1.1.0
|
|
*/
|
|
const EntryPoint& getEntryPoint() const {
|
|
return _entryPoint;
|
|
}
|
|
|
|
/**
|
|
* Gets reference to the entry point instance associated with the context.
|
|
*
|
|
* @return Reference to the entry point.
|
|
* @since 1.1.0
|
|
*/
|
|
EntryPoint& getEntryPoint() {
|
|
return _entryPoint;
|
|
}
|
|
/**
|
|
* Copies given entry point to the instance associated with the context.
|
|
* Deep copy is performed, so passed object not need to be maintained as
|
|
* long as the context is used.
|
|
*
|
|
* @param entryPoint The entry point which is copied to the context.
|
|
* @since 1.1.0
|
|
*/
|
|
void setEntryPoint(const EntryPoint &entryPoint) {
|
|
_entryPoint = entryPoint;
|
|
}
|
|
|
|
/**
|
|
* Sets instruction pointer directly into the entry point.
|
|
*
|
|
* @param ip The new IP.
|
|
* @since 1.1.0
|
|
*/
|
|
void setIP(fcml_ip ip) {
|
|
_entryPoint.setIP(ip);
|
|
}
|
|
|
|
/**
|
|
* Increments entry point by given number of bytes.
|
|
*
|
|
* @param ip Number of bytes the instruction pointer has to be
|
|
* incremented by.
|
|
* @since 1.1.0
|
|
*/
|
|
void incrementIP(fcml_ip ip) {
|
|
_entryPoint.incrementIP(ip);
|
|
}
|
|
|
|
/**
|
|
* Sets processor operating mode directly into the entry point.
|
|
*
|
|
* @param operatingMode Processor operating mode to be set.
|
|
* @since 1.1.0
|
|
*/
|
|
void setOperatingMode(EntryPoint::OperatingMode operatingMode) {
|
|
_entryPoint.setOpMode(operatingMode);
|
|
}
|
|
|
|
/**
|
|
* Sets a new address size attribute for the entry point.
|
|
*
|
|
* @param addressSizeAttribute The address size attribute.
|
|
* @since 1.1.0
|
|
*/
|
|
void setAddressSizeAttribute(fcml_usize addressSizeAttribute) {
|
|
_entryPoint.setAddressSizeAttribute(addressSizeAttribute);
|
|
}
|
|
|
|
/**
|
|
* Sets a new operand size attribute for the entry point.
|
|
*
|
|
* @param operandSizeAttribute The operand size attribute.
|
|
* @since 1.1.0
|
|
*/
|
|
void setOperandSizeAttribute(fcml_usize operandSizeAttribute) {
|
|
_entryPoint.setOperandSizeAttribute(operandSizeAttribute);
|
|
}
|
|
|
|
private:
|
|
/** Disassembler configuration. */
|
|
DisassemblerConf _disassemblerConf;
|
|
/** Entry point. */
|
|
EntryPoint _entryPoint;
|
|
/** Code buffer. */
|
|
fcml_ptr _code;
|
|
/** Code length. */
|
|
fcml_usize _codeLength;
|
|
};
|
|
|
|
/** Instruction prefix.
|
|
* @since 1.1.0
|
|
*/
|
|
class InstructionPrefixDetails {
|
|
public:
|
|
|
|
/** Type of the instruction prefix.
|
|
* @since 1.1.0
|
|
*/
|
|
enum PrefixType {
|
|
PT_GROUP_UNKNOWN = FCML_PT_GROUP_UNKNOWN,
|
|
PT_GROUP_1 = FCML_PT_GROUP_1,
|
|
PT_GROUP_2 = FCML_PT_GROUP_2,
|
|
PT_GROUP_3 = FCML_PT_GROUP_3,
|
|
PT_GROUP_4 = FCML_PT_GROUP_4,
|
|
PT_REX = FCML_PT_REX,
|
|
PT_VEX = FCML_PT_VEX,
|
|
PT_XOP = FCML_PT_XOP,
|
|
PT_EVEX = FCML_PT_EVEX
|
|
};
|
|
|
|
/**
|
|
* Returns true if it's a mandatory prefix.
|
|
*
|
|
* @return True if it's a mandatory prefix.
|
|
* @since 1.1.0
|
|
*/
|
|
bool isMandatoryPrefix() const {
|
|
return _mandatoryPrefix;
|
|
}
|
|
|
|
/**
|
|
* Sets mandatory prefix flag for the prefix.
|
|
*
|
|
* @param mandatoryPrefix Set to true in order to make the
|
|
* prefix mandatory one.
|
|
* @since 1.1.0
|
|
*/
|
|
void setMandatoryPrefix(bool mandatoryPrefix) {
|
|
_mandatoryPrefix = mandatoryPrefix;
|
|
}
|
|
|
|
/**
|
|
* Gets the prefix byte.
|
|
*
|
|
* @return The prefix byte.
|
|
* @since 1.1.0
|
|
*/
|
|
fcml_uint8_t getPrefix() const {
|
|
return _prefix;
|
|
}
|
|
|
|
/**
|
|
* Sets the prefix byte.
|
|
*
|
|
* @param prefix The prefix byte.
|
|
* @since 1.1.0
|
|
*/
|
|
void setPrefix(fcml_uint8_t prefix) {
|
|
_prefix = prefix;
|
|
}
|
|
|
|
/**
|
|
* Gets the prefix type.
|
|
*
|
|
* @return The prefix byte.
|
|
* @since 1.1.0
|
|
*/
|
|
PrefixType getPrefixType() const {
|
|
return _prefixType;
|
|
}
|
|
|
|
/**
|
|
* Sets a new prefix type.
|
|
*
|
|
* @param prefixType The prefix byte to be set.
|
|
* @since 1.1.0
|
|
*/
|
|
void setPrefixType(PrefixType prefixType) {
|
|
_prefixType = prefixType;
|
|
}
|
|
|
|
/**
|
|
* Gets the second and third bytes of the XOP/VEX prefix.
|
|
*
|
|
* @return A pointer to the VEX/XOP bytes.
|
|
* @since 1.2.0
|
|
*/
|
|
const fcml_uint8_t* getAvxBytes() const {
|
|
return _AvxBytes;
|
|
}
|
|
|
|
/**
|
|
* Gets the second and third bytes of the XOP/VEX prefix.
|
|
*
|
|
* @return A pointer to the VEX/XOP bytes.
|
|
* @since 1.2.0
|
|
*/
|
|
fcml_uint8_t* getAvxBytes() {
|
|
return _AvxBytes;
|
|
}
|
|
|
|
private:
|
|
/** The first byte of the prefix. */
|
|
fcml_uint8_t _prefix;
|
|
/** Tye type of the prefix. */
|
|
PrefixType _prefixType;
|
|
/** True if the prefix is a mandatory one. */
|
|
bool _mandatoryPrefix;
|
|
/** The second and third byte of the AVX prefix.
|
|
* since 1.2.0
|
|
*/
|
|
fcml_uint8_t _AvxBytes[3];
|
|
};
|
|
|
|
/** Prefixes details.
|
|
* @since 1.1.0
|
|
*/
|
|
class PrefixesDetails {
|
|
public:
|
|
|
|
/**
|
|
* Default constructor.
|
|
* @since 1.1.0
|
|
*/
|
|
PrefixesDetails() :
|
|
_prefixesCount(0),
|
|
_prefixesBytesCount(0),
|
|
_isBranch(false),
|
|
_isNobranch(false),
|
|
_isLock(false),
|
|
_isRep(false),
|
|
_isRepne(false),
|
|
_isXrelease(false),
|
|
_isXacquire(false),
|
|
_isVex(false),
|
|
_isEvex(false),
|
|
_isXop(false),
|
|
_isAvx(false),
|
|
_isRex(false),
|
|
_AvxPrefixFirstByte(false),
|
|
_R(0),
|
|
_RPrim(0),
|
|
_X(0),
|
|
_B(0),
|
|
_W(0),
|
|
_L(0),
|
|
_LPrim(0),
|
|
_mmmm(0),
|
|
_vvvv(0),
|
|
_VPrim(0),
|
|
_pp(0),
|
|
_aaa(0),
|
|
_b(false),
|
|
_z(false) {
|
|
}
|
|
|
|
/**
|
|
* Gets reference to the instruction prefix at given index.
|
|
* @param index Number of the prefix.
|
|
* @return The instruction prefix for given index.
|
|
* @throw IllegalArgumentException Index out of bound.
|
|
* @since 1.1.0
|
|
*/
|
|
const InstructionPrefixDetails& operator[](fcml_usize index) const {
|
|
if (index >= FCML_DASM_PREFIXES_COUNT) {
|
|
throw IllegalArgumentException(FCML_TEXT("Index out of bound."));
|
|
}
|
|
return _prefixes[index];
|
|
}
|
|
|
|
/**
|
|
* Gets reference to the instruction prefix at given index.
|
|
* @param index Number of the prefix.
|
|
* @return The instruction prefix for given index.
|
|
* @throw IllegalArgumentException Index out of bound.
|
|
* @since 1.1.0
|
|
*/
|
|
InstructionPrefixDetails& operator[](fcml_usize index) {
|
|
if (index >= FCML_DASM_PREFIXES_COUNT) {
|
|
throw IllegalArgumentException(FCML_TEXT("Index out of bound."));
|
|
}
|
|
return _prefixes[index];
|
|
}
|
|
|
|
/**
|
|
* Gets b flag.
|
|
*
|
|
* @return The B flag.
|
|
* @since 1.1.0
|
|
*/
|
|
fcml_uint8_t getB() const {
|
|
return _B;
|
|
}
|
|
|
|
/**
|
|
* Sets B flag.
|
|
*
|
|
* @param b The B flag.
|
|
* @since 1.1.0
|
|
*/
|
|
void setB(fcml_uint8_t B) {
|
|
_B = B;
|
|
}
|
|
|
|
/**
|
|
* Gets true if branch prefix is available.
|
|
*
|
|
* @return True if branch prefix is available.
|
|
* @since 1.1.0
|
|
*/
|
|
bool isBranch() const {
|
|
return _isBranch;
|
|
}
|
|
|
|
/**
|
|
* Sets branch prefix availability.
|
|
*
|
|
* @param isBranch True if branch prefix is available.
|
|
* @since 1.1.0
|
|
*/
|
|
void setBranch(bool isBranch) {
|
|
_isBranch = isBranch;
|
|
}
|
|
|
|
/**
|
|
* Gets true if lock prefix is available.
|
|
*
|
|
* @return True if lock prefix is available.
|
|
* @since 1.1.0
|
|
*/
|
|
bool isLock() const {
|
|
return _isLock;
|
|
}
|
|
|
|
/**
|
|
* Sets lock prefix availability.
|
|
*
|
|
* @param isLock True if lock prefix is available.
|
|
* @since 1.1.0
|
|
*/
|
|
void setLock(bool isLock) {
|
|
_isLock = isLock;
|
|
}
|
|
|
|
/**
|
|
* Gets true if no-branch prefix is available.
|
|
*
|
|
* @return True if no-branch prefix is available.
|
|
* @since 1.1.0
|
|
*/
|
|
bool isNobranch() const {
|
|
return _isNobranch;
|
|
}
|
|
|
|
/**
|
|
* Sets no-branch prefix availability.
|
|
*
|
|
* @param isNobranch True if no-branch prefix is available.
|
|
* @since 1.1.0
|
|
*/
|
|
void setNobranch(bool isNobranch) {
|
|
_isNobranch = isNobranch;
|
|
}
|
|
|
|
/**
|
|
* Gets true if Rep prefix is available.
|
|
*
|
|
* @return True if Rep prefix is available.
|
|
* @since 1.1.0
|
|
*/
|
|
bool isRep() const {
|
|
return _isRep;
|
|
}
|
|
|
|
/**
|
|
* Sets Rep prefix availability.
|
|
*
|
|
* @param isRep True if Rep prefix is available.
|
|
* @since 1.1.0
|
|
*/
|
|
void setRep(bool isRep) {
|
|
_isRep = isRep;
|
|
}
|
|
|
|
/**
|
|
* Gets true if Repne prefix is available.
|
|
*
|
|
* @return True if Repne prefix is available.
|
|
* @since 1.1.0
|
|
*/
|
|
bool isRepne() const {
|
|
return _isRepne;
|
|
}
|
|
|
|
/**
|
|
* Sets Repne prefix availability.
|
|
*
|
|
* @param isRepne True if branch prefix is available.
|
|
* @since 1.1.0
|
|
*/
|
|
void setRepne(bool isRepne) {
|
|
_isRepne = isRepne;
|
|
}
|
|
|
|
/**
|
|
* Gets true if Rex prefix is available.
|
|
*
|
|
* @return True if Rex prefix is available.
|
|
* @since 1.1.0
|
|
*/
|
|
bool isRex() const {
|
|
return _isRex;
|
|
}
|
|
|
|
/**
|
|
* Sets REX prefix availability.
|
|
*
|
|
* @param isRex True if REX prefix is available.
|
|
* @since 1.1.0
|
|
*/
|
|
void setRex(bool isRex) {
|
|
_isRex = isRex;
|
|
}
|
|
|
|
/**
|
|
* Gets true if Vex prefix is available.
|
|
*
|
|
* @return True if Vex prefix is available.
|
|
* @since 1.1.0
|
|
*/
|
|
bool isVex() const {
|
|
return _isVex;
|
|
}
|
|
|
|
/**
|
|
* Sets VEX prefix availability.
|
|
*
|
|
* @param isVex True if VEX prefix is available.
|
|
* @since 1.1.0
|
|
*/
|
|
void setVex(bool isVex) {
|
|
_isVex = isVex;
|
|
}
|
|
|
|
/**
|
|
* Sets EVEX prefix availability.
|
|
*
|
|
* @param isEvex True if EVEX prefix is available.
|
|
* @since 1.2.0
|
|
*/
|
|
void setEvex(bool isEvex) {
|
|
_isEvex = isEvex;
|
|
}
|
|
|
|
/**
|
|
* Gets true if EVEX prefix is available.
|
|
*
|
|
* @return True if EVEX prefix is available.
|
|
* @since 1.2.0
|
|
*/
|
|
bool isEvex() const {
|
|
return _isEvex;
|
|
}
|
|
|
|
/**
|
|
* Gets true if xacquire prefix is available.
|
|
*
|
|
* @return True if xacquire prefix is available.
|
|
* @since 1.1.0
|
|
*/
|
|
bool isXacquire() const {
|
|
return _isXacquire;
|
|
}
|
|
|
|
/**
|
|
* Sets xacquire prefix availability.
|
|
*
|
|
* @param isXacquire True if xacquire prefix is available.
|
|
* @since 1.1.0
|
|
*/
|
|
void setXacquire(bool isXacquire) {
|
|
_isXacquire = isXacquire;
|
|
}
|
|
|
|
/**
|
|
* Gets true if XOP prefix is available.
|
|
*
|
|
* @return True if XOP prefix is available.
|
|
* @since 1.1.0
|
|
*/
|
|
bool isXop() const {
|
|
return _isXop;
|
|
}
|
|
|
|
/**
|
|
* Sets XOP prefix availability.
|
|
*
|
|
* @param isXop True if XOP prefix is available.
|
|
* @since 1.1.0
|
|
*/
|
|
void setXop(bool isXop) {
|
|
_isXop = isXop;
|
|
}
|
|
|
|
/**
|
|
* Gets true if any AVX prefix is available.
|
|
*
|
|
* @return True if any AVX prefix is available.
|
|
* @since 1.2.0
|
|
*/
|
|
bool isAvx() const {
|
|
return _isAvx;
|
|
}
|
|
|
|
/**
|
|
* Sets XOP prefix availability.
|
|
*
|
|
* @param isXop True if XOP prefix is available.
|
|
* @since 1.2.0
|
|
*/
|
|
void setAvx(bool isAvx) {
|
|
_isAvx = isAvx;
|
|
}
|
|
|
|
/**
|
|
* Gets true if xrelease prefix is available.
|
|
*
|
|
* @return True if xrelease prefix is available.
|
|
* @since 1.1.0
|
|
*/
|
|
bool isXrelease() const {
|
|
return _isXrelease;
|
|
}
|
|
|
|
/**
|
|
* Sets xrelease prefix availability.
|
|
*
|
|
* @param isXrelease True if xrelease prefix is available.
|
|
* @since 1.1.0
|
|
*/
|
|
void setXrelease(bool isXrelease) {
|
|
_isXrelease = isXrelease;
|
|
}
|
|
|
|
/**
|
|
* Gets L flag.
|
|
*
|
|
* @return The L flag.
|
|
* @since 1.1.0
|
|
*/
|
|
fcml_uint8_t getL() const {
|
|
return _L;
|
|
}
|
|
|
|
/**
|
|
* Sets L flag.
|
|
*
|
|
* @param l The L flag.
|
|
* @since 1.1.0
|
|
*/
|
|
void setL(fcml_uint8_t L) {
|
|
_L = L;
|
|
}
|
|
|
|
/**
|
|
* Gets L' flag.
|
|
*
|
|
* @return The L' flag.
|
|
* @since 1.2.0
|
|
*/
|
|
fcml_uint8_t getLPrim() const {
|
|
return _LPrim;
|
|
}
|
|
|
|
/**
|
|
* Sets L' flag.
|
|
*
|
|
* @param l The L' flag.
|
|
* @since 1.2.0
|
|
*/
|
|
void setLPrim(fcml_uint8_t lPrim) {
|
|
_LPrim = lPrim;
|
|
}
|
|
|
|
/**
|
|
* Gets MMMM field.
|
|
*
|
|
* @return MMMM field.
|
|
* @since 1.1.0
|
|
*/
|
|
fcml_uint8_t getMmmm() const {
|
|
return _mmmm;
|
|
}
|
|
|
|
/**
|
|
* Sets MMMM field.
|
|
*
|
|
* @param mmmm MMMM field.
|
|
* @since 1.1.0
|
|
*/
|
|
void setMmmm(fcml_uint8_t mmmm) {
|
|
_mmmm = mmmm;
|
|
}
|
|
|
|
/**
|
|
* Gets PP field.
|
|
*
|
|
* @return The PP field.
|
|
* @since 1.1.0
|
|
*/
|
|
fcml_uint8_t getPp() const {
|
|
return _pp;
|
|
}
|
|
|
|
/**
|
|
* Sets PP field.
|
|
*
|
|
* @param pp PP field.
|
|
* @since 1.1.0
|
|
*/
|
|
void setPp(fcml_uint8_t pp) {
|
|
_pp = pp;
|
|
}
|
|
|
|
/**
|
|
* Gets a reference to the prefix of the given index.
|
|
*
|
|
* @param index Index for the prefix.
|
|
* @return The prefix at given index.
|
|
* @throw BadArgumentException Array index out of bound.
|
|
* @since 1.1.0
|
|
*/
|
|
const InstructionPrefixDetails& getPrefixes(fcml_usize index) const {
|
|
if (index > FCML_DASM_PREFIXES_COUNT) {
|
|
throw BadArgumentException(FCML_TEXT("Array index out of bound."),
|
|
FCML_CEH_GEC_VALUE_OUT_OF_RANGE);
|
|
}
|
|
return _prefixes[index];
|
|
}
|
|
|
|
/**
|
|
* Gets a reference to the prefix of the given index.
|
|
*
|
|
* @param index Index for the prefix.
|
|
* @return The prefix at given index.
|
|
* @throw BadArgumentException Array index out of bound.
|
|
* @since 1.1.0
|
|
*/
|
|
InstructionPrefixDetails& getPrefixes(fcml_usize index) {
|
|
if (index > FCML_DASM_PREFIXES_COUNT) {
|
|
throw BadArgumentException(FCML_TEXT("Array index out of bound."),
|
|
FCML_CEH_GEC_VALUE_OUT_OF_RANGE);
|
|
}
|
|
return _prefixes[index];
|
|
}
|
|
|
|
/**
|
|
* Gets number of bytes interpreted to be prefixes.
|
|
*
|
|
* @return Number of prefixes bytes.
|
|
* @since 1.1.0
|
|
*/
|
|
fcml_int getPrefixesBytesCount() const {
|
|
return _prefixesBytesCount;
|
|
}
|
|
|
|
/**
|
|
* Sets number of prefixes bytes available for the instruction.
|
|
*
|
|
* @param prefixesBytesCount Number of the prefixes bytes.
|
|
* @since 1.1.0
|
|
*/
|
|
void setPrefixesBytesCount(fcml_int prefixesBytesCount) {
|
|
_prefixesBytesCount = prefixesBytesCount;
|
|
}
|
|
|
|
/**
|
|
* Gets number of prefixes available for the instruction.
|
|
*
|
|
* @return Number of the prefixes for the instruction.
|
|
* @since 1.1.0
|
|
*/
|
|
fcml_int getPrefixesCount() const {
|
|
return _prefixesCount;
|
|
}
|
|
|
|
/**
|
|
* Sets number of prefixes available for the instruction.
|
|
*
|
|
* @param prefixesCount Number of the available prefixes.
|
|
* @since 1.1.0
|
|
*/
|
|
void setPrefixesCount(fcml_int prefixesCount) {
|
|
_prefixesCount = prefixesCount;
|
|
}
|
|
|
|
/**
|
|
* Gets R flag.
|
|
*
|
|
* @return The R flag.
|
|
* @since 1.1.0
|
|
*/
|
|
fcml_uint8_t getR() const {
|
|
return _R;
|
|
}
|
|
|
|
/**
|
|
* Sets R flag.
|
|
*
|
|
* @param r The R flag.
|
|
* @since 1.1.0
|
|
*/
|
|
void setR(fcml_uint8_t r) {
|
|
_R = r;
|
|
}
|
|
|
|
/**
|
|
* Gets R' flag.
|
|
*
|
|
* @return The R' flag.
|
|
* @since 1.2.0
|
|
*/
|
|
fcml_uint8_t getRPrim() const {
|
|
return _RPrim;
|
|
}
|
|
|
|
/**
|
|
* Sets R' flag.
|
|
*
|
|
* @param rPrim The R' flag.
|
|
* @since 1.2.0
|
|
*/
|
|
void setRPrim(fcml_uint8_t rPrim) {
|
|
_RPrim = rPrim;
|
|
}
|
|
|
|
/**
|
|
* Gets the first byte of the AVX prefix.
|
|
*
|
|
* @return The first byte of the AVX prefix.
|
|
* @since 1.2.0
|
|
*/
|
|
fcml_uint8_t getAvxFirstByte() const {
|
|
return _AvxPrefixFirstByte;
|
|
}
|
|
|
|
/**
|
|
* Sets a first byte of the XOP/VEX prefix.
|
|
*
|
|
* @param avxFirstByte The first AVX prefix byte.
|
|
* @since 1.2.0
|
|
*/
|
|
void setAvxFirstByte(fcml_uint8_t avxFirstByte) {
|
|
_AvxPrefixFirstByte = avxFirstByte;
|
|
}
|
|
|
|
/**
|
|
* Gets VVVV field of the XOP/VEX prefix.
|
|
*
|
|
* @return VVVV field of the XOP/VEX prefix.
|
|
* @since 1.1.0
|
|
*/
|
|
fcml_uint8_t getVvvv() const {
|
|
return _vvvv;
|
|
}
|
|
|
|
/**
|
|
* Sets VVVV field of the XOP/VEX prefix.
|
|
*
|
|
* @param vvvv The VVVV field.
|
|
* @since 1.1.0
|
|
*/
|
|
void setVvvv(fcml_uint8_t vvvv) {
|
|
_vvvv = vvvv;
|
|
}
|
|
|
|
/**
|
|
* Gets 'aaa' field of the EVEX prefix.
|
|
*
|
|
* @return aaa field of the EVEX prefix.
|
|
* @since 1.2.0
|
|
*/
|
|
fcml_uint8_t getAaa() const {
|
|
return _aaa;
|
|
}
|
|
|
|
/**
|
|
* Sets 'aaa' field of the EVEX prefix.
|
|
*
|
|
* @param aaa The 'aaa' field.
|
|
* @since 1.1.0
|
|
*/
|
|
void setAaa(fcml_uint8_t aaa) {
|
|
_aaa = aaa;
|
|
}
|
|
|
|
/**
|
|
* Gets V' flag.
|
|
*
|
|
* @return The V' flag.
|
|
* @since 1.2.0
|
|
*/
|
|
fcml_uint8_t getVPrim() const {
|
|
return _VPrim;
|
|
}
|
|
|
|
/**
|
|
* Sets V' flag.
|
|
*
|
|
* @param vPrim The V' flag.
|
|
* @since 1.2.0
|
|
*/
|
|
void setVPrim(fcml_uint8_t vPrim) {
|
|
_VPrim = vPrim;
|
|
}
|
|
|
|
/**
|
|
* Gets W flag.
|
|
*
|
|
* @return The W flag.
|
|
* @since 1.1.0
|
|
*/
|
|
fcml_uint8_t getW() const {
|
|
return _W;
|
|
}
|
|
|
|
/**
|
|
* Sets W flag.
|
|
*
|
|
* @param w The W flag.
|
|
* @since 1.1.0
|
|
*/
|
|
void setW(fcml_uint8_t W) {
|
|
_W = W;
|
|
}
|
|
|
|
/**
|
|
* Gets X flag.
|
|
*
|
|
* @return The X flag.
|
|
* @since 1.1.0
|
|
*/
|
|
fcml_uint8_t getX() const {
|
|
return _X;
|
|
}
|
|
|
|
/**
|
|
* Sets X flag.
|
|
*
|
|
* @param x The X flag.
|
|
* @since 1.1.0
|
|
*/
|
|
void setX(fcml_uint8_t X) {
|
|
_X = X;
|
|
}
|
|
|
|
/**
|
|
* Gets EVEX.b bit.
|
|
*
|
|
* @return The EVEX.b bit.
|
|
* @since 1.2.0
|
|
*/
|
|
bool getBcast() const {
|
|
return _b;
|
|
}
|
|
|
|
/**
|
|
* Sets EVEX.b bit.
|
|
*
|
|
* @param b The EVEX.b bit.
|
|
* @since 1.2.0
|
|
*/
|
|
void setBcast(bool b) {
|
|
_b = b;
|
|
}
|
|
|
|
/**
|
|
* Gets EVEX.z bit.
|
|
*
|
|
* @return The EVEX.z bit.
|
|
* @since 1.2.0
|
|
*/
|
|
bool getZ() const {
|
|
return _z;
|
|
}
|
|
|
|
/**
|
|
* Sets EVEX.z bit.
|
|
*
|
|
* @param z The EVEX.z bit.
|
|
* @since 1.2.0
|
|
*/
|
|
void setZ(bool z) {
|
|
_z = z;
|
|
}
|
|
|
|
private:
|
|
/** Array with decoded prefixes. */
|
|
InstructionPrefixDetails _prefixes[FCML_DASM_PREFIXES_COUNT];
|
|
/** Number of decoded prefixes. */
|
|
fcml_int _prefixesCount;
|
|
/** Number of bytes used by all decoded prefixes. */
|
|
fcml_int _prefixesBytesCount;
|
|
/** FCML_TRUE if branch prefix exists. */
|
|
bool _isBranch;
|
|
/** FCML_TRUE if nobranch prefix exists. */
|
|
bool _isNobranch;
|
|
/** FCML_TRUE if lock explicit prefix exists. */
|
|
bool _isLock;
|
|
/** FCML_TRUE if rep explicit prefix exists. */
|
|
bool _isRep;
|
|
/** FCML_TRUE if repne explicit prefix exists. */
|
|
bool _isRepne;
|
|
/** FCML_TRUE if xrelease explicit prefix exists. */
|
|
bool _isXrelease;
|
|
/** FCML_TRUE if xacquire explicit prefix exists. */
|
|
bool _isXacquire;
|
|
/** FCML_TRUE if VEX prefix exists. */
|
|
bool _isVex;
|
|
/** FCML_TRUE if EVEX prefix exists.
|
|
* since 1.2.0
|
|
*/
|
|
bool _isEvex;
|
|
/** FCML_TRUE if XOP prefix exists. */
|
|
bool _isXop;
|
|
/** FCML_TRUE if any AVX prefix exists.
|
|
* @since 1.2.0
|
|
*/
|
|
bool _isAvx;
|
|
/** FCML_TRUE if REX prefix exists. */
|
|
bool _isRex;
|
|
/** Various fields encoded inside decoded prefixes.
|
|
* since 1.2.0
|
|
*/
|
|
fcml_uint8_t _AvxPrefixFirstByte;
|
|
/** R field of REX,XOP,VEX or EVEX prefix. */
|
|
fcml_uint8_t _R;
|
|
/** R' field of EVEX prefix.
|
|
* since 1.2.0
|
|
*/
|
|
fcml_uint8_t _RPrim;
|
|
/** X field of REX,XOP,VEX or EVEX prefix. */
|
|
fcml_uint8_t _X;
|
|
/** B field of REX,XOP,VEX or EVEX prefix. */
|
|
fcml_uint8_t _B;
|
|
/** W field of REX,XOP,VEX or EVEX prefix. */
|
|
fcml_uint8_t _W;
|
|
/** L field of XOP, VEX or EVEX prefix. */
|
|
fcml_uint8_t _L;
|
|
/** L' field of EVEX prefix.
|
|
* since 1.2.0
|
|
*/
|
|
fcml_uint8_t _LPrim;
|
|
/** m-mmmm field of XOP or VEX prefix. */
|
|
fcml_uint8_t _mmmm;
|
|
/** vvvv field of XOP or VEX prefix. */
|
|
fcml_uint8_t _vvvv;
|
|
/** V' field of EVEX prefix.
|
|
* since 1.2.0
|
|
*/
|
|
fcml_uint8_t _VPrim;
|
|
/** pp field of XOP or VEX prefix. */
|
|
fcml_uint8_t _pp;
|
|
/** aaa field of EVEX prefix.
|
|
* since 1.2.0
|
|
*/
|
|
fcml_uint8_t _aaa;
|
|
/** EVEX.b bit.
|
|
* since 1.2.0
|
|
*/
|
|
bool _b;
|
|
/** EVEX.z bit.
|
|
* since 1.2.0
|
|
*/
|
|
bool _z;
|
|
};
|
|
|
|
/** Operand details.
|
|
* @since 1.1.0
|
|
*/
|
|
class OperandDetails {
|
|
public:
|
|
|
|
/** @since 1.1.0 */
|
|
enum AccessMode {
|
|
/** Undefined mode. */
|
|
AM_ACCESS_MODE_UNDEFINED = FCML_AM_ACCESS_MODE_UNDEFINED,
|
|
/** Operand is read by instruction. */
|
|
AM_READ = FCML_AM_READ,
|
|
/** Operand is set by instruction */
|
|
AM_WRITE = FCML_AM_WRITE,
|
|
/** Operand is read but can be also set. */
|
|
AM_READ_WRITE = AM_READ | AM_WRITE
|
|
};
|
|
|
|
/**
|
|
* Creates default operand details with an undefined access mode.
|
|
* @since 1.1.0
|
|
*/
|
|
OperandDetails() :
|
|
_accessMode(AM_ACCESS_MODE_UNDEFINED) {
|
|
}
|
|
|
|
/**
|
|
* Creates operand details for given access mode.
|
|
*
|
|
* @param accessMode Access mode.
|
|
* @since 1.1.0
|
|
*/
|
|
OperandDetails(AccessMode accessMode) :
|
|
_accessMode(accessMode) {
|
|
}
|
|
|
|
/**
|
|
* Gets access mode for the operand.
|
|
*
|
|
* @return Access mode.
|
|
* @since 1.1.0
|
|
*/
|
|
AccessMode getAccessMode() const {
|
|
return _accessMode;
|
|
}
|
|
|
|
/**
|
|
* Sets an access mode for the operand.
|
|
*
|
|
* @param accessMode The access mode for the operand.
|
|
* @since 1.1.0
|
|
*/
|
|
void setAccessMode(AccessMode accessMode) {
|
|
_accessMode = accessMode;
|
|
}
|
|
|
|
private:
|
|
/** Operan's access mode. */
|
|
AccessMode _accessMode;
|
|
};
|
|
|
|
/** ModRM details.
|
|
* @since 1.1.0
|
|
*/
|
|
class DecodedModRMDetails {
|
|
public:
|
|
|
|
/**
|
|
* Creates an empty ModR/M details.
|
|
* @since 1.1.0
|
|
*/
|
|
DecodedModRMDetails() :
|
|
_isRip(false) {
|
|
}
|
|
|
|
/**
|
|
* Gets true if RIP byte is available.
|
|
*
|
|
* @return True if RIP byte is available.
|
|
* @since 1.1.0
|
|
*/
|
|
bool isRip() const {
|
|
return _isRip;
|
|
}
|
|
|
|
/**
|
|
* Sets RIP byte availability.
|
|
*
|
|
* @param isRip True if RIP byte is available.
|
|
* @since 1.1.0
|
|
*/
|
|
void setRip(bool isRip) {
|
|
_isRip = isRip;
|
|
}
|
|
|
|
/**
|
|
* Gets ModR/M nullable byte.
|
|
*
|
|
* @return ModR/M nullable byte.
|
|
* @since 1.1.0
|
|
*/
|
|
const Nullable<fcml_uint8_t>& getModRM() const {
|
|
return _modRM;
|
|
}
|
|
|
|
/**
|
|
* Gets ModR/M nullable byte.
|
|
*
|
|
* @return ModR/M nullable byte.
|
|
* @since 1.1.0
|
|
*/
|
|
Nullable<fcml_uint8_t>& getModRM() {
|
|
return _modRM;
|
|
}
|
|
|
|
/**
|
|
* Sets ModR/M nullable byte.
|
|
*
|
|
* @param modRM ModR/M nullable byte.
|
|
* @since 1.1.0
|
|
*/
|
|
void setModRM(const Nullable<fcml_uint8_t> &modRM) {
|
|
_modRM = modRM;
|
|
}
|
|
|
|
/**
|
|
* Gets SIB nullable byte.
|
|
*
|
|
* @return SIB nullable byte.
|
|
* @since 1.1.0
|
|
*/
|
|
const Nullable<fcml_uint8_t>& getSib() const {
|
|
return _sib;
|
|
}
|
|
|
|
/**
|
|
* Gets SIB nullable byte.
|
|
*
|
|
* @return SIB nullable byte.
|
|
* @since 1.1.0
|
|
*/
|
|
Nullable<fcml_uint8_t>& getSib() {
|
|
return _sib;
|
|
}
|
|
|
|
/**
|
|
* Sets SIB nullable byte.
|
|
*
|
|
* @param sib The SIB nullable byte.
|
|
* @since 1.1.0
|
|
*/
|
|
void setSib(const Nullable<fcml_uint8_t> &sib) {
|
|
_sib = sib;
|
|
}
|
|
|
|
/**
|
|
* Gets constant N (see AVX-512 compressed disp8).
|
|
*
|
|
* @return N as nullable value.
|
|
* @since 1.2.0
|
|
*/
|
|
const Nullable<fcml_uint32_t>& getN() const {
|
|
return _N;
|
|
}
|
|
|
|
/**
|
|
* Gets N (see compressed AVX-512 disp8).
|
|
*
|
|
* @return N nullable value.
|
|
* @since 1.2.0
|
|
*/
|
|
Nullable<fcml_uint32_t>& getN() {
|
|
return _N;
|
|
}
|
|
|
|
/**
|
|
* Sets N (see compressed AVX-512 disp8).
|
|
*
|
|
* @param N N nullable value.
|
|
* @since 1.2.0
|
|
*/
|
|
void setN(const Nullable<fcml_uint32_t> &N) {
|
|
_N = N;
|
|
}
|
|
|
|
/**
|
|
* Gets constant raw displacement.
|
|
*
|
|
* @return Displacement.
|
|
* @since 1.2.0
|
|
*/
|
|
const Integer& getDisplacement() const {
|
|
return _displacement;
|
|
}
|
|
|
|
/**
|
|
* Gets raw displacement.
|
|
*
|
|
* @return Displacement.
|
|
* @since 1.2.0
|
|
*/
|
|
Integer& getDisplacement() {
|
|
return _displacement;
|
|
}
|
|
|
|
/**
|
|
* Sets displacement.
|
|
*
|
|
* @param displacement Displacement.
|
|
* @since 1.2.0
|
|
*/
|
|
void setDisplacement(const Integer &displacement) {
|
|
_displacement = displacement;
|
|
}
|
|
|
|
private:
|
|
/** ModR/M byte if exists.*/
|
|
Nullable<fcml_uint8_t> _modRM;
|
|
/** SIB byte if exists.*/
|
|
Nullable<fcml_uint8_t> _sib;
|
|
/** True if RIP encoding is used by decoded instruction. This flag is
|
|
* used only in 64 bit mode. */
|
|
bool _isRip;
|
|
/** Raw displacement.
|
|
* since 1.2.0
|
|
*/
|
|
Integer _displacement;
|
|
/* N from AVX-512 compressed disp8.
|
|
* since 1.2.0
|
|
*/
|
|
Nullable<fcml_uint32_t> _N;
|
|
};
|
|
|
|
/** Additional details about an instruction.
|
|
* @since 1.1.0
|
|
*/
|
|
class InstructionDetails {
|
|
public:
|
|
|
|
/**
|
|
* Gets address mode/instruction form. This information is used
|
|
* internally and is rather useless in day to day usage, but if
|
|
* you are interested in it do not hesitate to take a look at
|
|
* the manual.
|
|
*
|
|
* @return Instruction form.
|
|
* @since 1.1.0
|
|
*/
|
|
fcml_uint16_t getAddrMode() const {
|
|
return _addrMode;
|
|
}
|
|
|
|
/**
|
|
* Sets instruction form.
|
|
*
|
|
* @param addrMode Addressing mode.
|
|
* @since 1.1.0
|
|
*/
|
|
void setAddrMode(fcml_uint16_t addrMode) {
|
|
_addrMode = addrMode;
|
|
}
|
|
|
|
/**
|
|
* Gets instruction code. See fcml_en_instruction for more details.
|
|
*
|
|
* @return Instruction code.
|
|
* @since 1.1.0
|
|
*/
|
|
fcml_en_instruction getInstruction() const {
|
|
return _instruction;
|
|
}
|
|
|
|
/**
|
|
* Gets a new instruction code for the instruction.
|
|
*
|
|
* @param instruction The new instruction code.
|
|
* @since 1.1.0
|
|
*/
|
|
void setInstruction(fcml_en_instruction instruction) {
|
|
_instruction = instruction;
|
|
}
|
|
|
|
/**
|
|
* Gets a pointer to the instruction code. See fcml_en_instruction
|
|
* for more details.
|
|
*
|
|
* @return The pointer to the instruction code.
|
|
* @since 1.1.0
|
|
*/
|
|
const fcml_uint8_t* getInstructionCode() const {
|
|
return _instructionCode;
|
|
}
|
|
|
|
/**
|
|
* Gets a pointer to the instruction code. See fcml_en_instruction
|
|
* for more details.
|
|
*
|
|
* @return The pointer to the instruction code.
|
|
* @since 1.1.0
|
|
*/
|
|
fcml_uint8_t* getInstructionCode() {
|
|
return _instructionCode;
|
|
}
|
|
|
|
/**
|
|
* Gets instruction group. See fcml_instructions.h for all
|
|
* available groups.
|
|
*
|
|
* @return The instruction group.
|
|
* @since 1.1.0
|
|
*/
|
|
fcml_uint64_t getInstructionGroup() const {
|
|
return _instructionGroup;
|
|
}
|
|
|
|
/**
|
|
* Sets an instruction group. See fcml_instructions.h for all
|
|
* available groups.
|
|
*
|
|
* @param instructionGroup The instruction group.
|
|
* @since 1.1.0
|
|
*/
|
|
void setInstructionGroup(fcml_uint64_t instructionGroup) {
|
|
_instructionGroup = instructionGroup;
|
|
}
|
|
|
|
/**
|
|
* Instruction size in bytes.
|
|
*
|
|
* @return Size of the instruction in bytes.
|
|
* @since 1.1.0
|
|
*/
|
|
fcml_usize getInstructionSize() const {
|
|
return _instructionSize;
|
|
}
|
|
|
|
/**
|
|
* Sets the instruction size in bytes.
|
|
*
|
|
* @param instructionSize The instruction size.
|
|
* @since 1.1.0
|
|
*/
|
|
void setInstructionSize(fcml_usize instructionSize) {
|
|
_instructionSize = instructionSize;
|
|
}
|
|
|
|
/**
|
|
* Gets true if it's a shortcut instruction.
|
|
*
|
|
* @return True if it's a shortcut instruction.
|
|
* @since 1.1.0
|
|
*/
|
|
bool isShortcut() const {
|
|
return _isShortcut;
|
|
}
|
|
|
|
/**
|
|
* Marks the instruction as a shortcut.
|
|
*
|
|
* @param isShortcut True if it's a shortcut instruction.
|
|
* @since 1.1.0
|
|
*/
|
|
void setShortcut(bool isShortcut) {
|
|
_isShortcut = isShortcut;
|
|
}
|
|
|
|
/**
|
|
* Gets ModR/M instruction details.
|
|
*
|
|
* @return ModR/M details.
|
|
* @since 1.1.0
|
|
*/
|
|
const DecodedModRMDetails& getModRmDetails() const {
|
|
return _modRMDetails;
|
|
}
|
|
|
|
/**
|
|
* Gets ModR/M instruction details.
|
|
*
|
|
* @return ModR/M details.
|
|
* @since 1.1.0
|
|
*/
|
|
DecodedModRMDetails& getModRmDetails() {
|
|
return _modRMDetails;
|
|
}
|
|
|
|
/**
|
|
* Sets a new instruction details for the instruction.
|
|
*
|
|
* @param modRmDetails The new instruction details.
|
|
* @since 1.1.0
|
|
*/
|
|
void setModRmDetails(const DecodedModRMDetails &modRmDetails) {
|
|
_modRMDetails = modRmDetails;
|
|
}
|
|
|
|
/**
|
|
* Gets opcode field 'S'.
|
|
*
|
|
* @return 'S' opcode field.
|
|
* @since 1.1.0
|
|
*/
|
|
bool isOpcodeFieldSBit() const {
|
|
return _opcodeFieldSBit;
|
|
}
|
|
|
|
/**
|
|
* Sets 'S' field of the opcode byte.
|
|
*
|
|
* @param opcodeFieldSBit 'S' opcode byte field.
|
|
* @since 1.1.0
|
|
*/
|
|
void setOpcodeFieldSBit(bool opcodeFieldSBit) {
|
|
_opcodeFieldSBit = opcodeFieldSBit;
|
|
}
|
|
|
|
/**
|
|
* Gets opcode field 'W'.
|
|
*
|
|
* @return 'W' opcode field.
|
|
* @since 1.1.0
|
|
*/
|
|
bool isOpcodeFieldWBit() const {
|
|
return _opcodeFieldWBit;
|
|
}
|
|
|
|
/**
|
|
* Sets 'W' field of the opcode byte.
|
|
*
|
|
* @param opcodeFieldWBit 'W' opcode byte field.
|
|
* @since 1.1.0
|
|
*/
|
|
void setOpcodeFieldWBit(bool opcodeFieldWBit) {
|
|
_opcodeFieldWBit = opcodeFieldWBit;
|
|
}
|
|
|
|
/**
|
|
* Gets the operand details for given index.
|
|
*
|
|
* @param index Index of the instruction details.
|
|
* @return The operand details for the given index.
|
|
* @throw BadArgumentException Array index out of bound.
|
|
* @since 1.1.0
|
|
*/
|
|
const OperandDetails& getOperandDetails(fcml_usize index) const {
|
|
if (index > FCML_OPERANDS_COUNT) {
|
|
throw BadArgumentException(FCML_TEXT("Array index out of bound."),
|
|
FCML_CEH_GEC_VALUE_OUT_OF_RANGE);
|
|
}
|
|
return _operandDetails[index];
|
|
}
|
|
|
|
/**
|
|
* Gets the operand details for given index.
|
|
*
|
|
* @param index Index of the instruction details.
|
|
* @return The operand details for the given index.
|
|
* @throw BadArgumentException Array index out of bound.
|
|
* @since 1.1.0
|
|
*/
|
|
OperandDetails& getOperandDetails(fcml_usize index) {
|
|
if (index > FCML_OPERANDS_COUNT) {
|
|
throw BadArgumentException(FCML_TEXT("Array index out of bound."),
|
|
FCML_CEH_GEC_VALUE_OUT_OF_RANGE);
|
|
}
|
|
return _operandDetails[index];
|
|
}
|
|
|
|
/**
|
|
* Gets instruction prefixes details.
|
|
*
|
|
* @return The instruction prefix details.
|
|
* @since 1.1.0
|
|
*/
|
|
const PrefixesDetails& getPrefixesDetails() const {
|
|
return _prefixesDetails;
|
|
}
|
|
|
|
/**
|
|
* Gets instruction prefixes details.
|
|
*
|
|
* @return The instruction prefix details.
|
|
* @since 1.1.0
|
|
*/
|
|
PrefixesDetails& getPrefixesDetails() {
|
|
return _prefixesDetails;
|
|
}
|
|
|
|
/**
|
|
* Sets a new instruction prefixes details.
|
|
*
|
|
* @param prefixesDetails The new prefixes details.
|
|
* @since 1.1.0
|
|
*/
|
|
void setPrefixesDetails(const PrefixesDetails &prefixesDetails) {
|
|
_prefixesDetails = prefixesDetails;
|
|
}
|
|
|
|
/**
|
|
* Gets pseudo operation code.
|
|
*
|
|
* @return The pseudo operation associated with the instruction.
|
|
* @since 1.1.0
|
|
*/
|
|
fcml_en_pseudo_operations getPseudoOp() const {
|
|
return _pseudoOp;
|
|
}
|
|
|
|
/**
|
|
* Sets pseudo operation for the instruction.
|
|
*
|
|
* @param pseudoOp The pseudo operation.
|
|
* @since 1.1.0
|
|
*/
|
|
void setPseudoOp(fcml_en_pseudo_operations pseudoOp) {
|
|
_pseudoOp = pseudoOp;
|
|
}
|
|
|
|
/**
|
|
* Gets true is it's a pseudo operation.
|
|
*
|
|
* @return True if the instruction is a pseudo operation.
|
|
* @since 1.1.0
|
|
*/
|
|
bool isPseudoOp() const {
|
|
return _isPseudoOp;
|
|
}
|
|
|
|
/**
|
|
* Sets pseudo operation flag.
|
|
*
|
|
* @param isPseudoOp True if the instruction is a pseudo operation.
|
|
* @since 1.1.0
|
|
*/
|
|
void setIsPseudoOp(bool isPseudoOp) {
|
|
_isPseudoOp = isPseudoOp;
|
|
}
|
|
|
|
/**
|
|
* Gets avx-512 tuple type.
|
|
* @since 1.2.0
|
|
*/
|
|
fcml_uint8_t getTupleType() const {
|
|
return _tupleType;
|
|
}
|
|
|
|
/**
|
|
* Sets avx-512 tuple type.
|
|
*
|
|
* @param isPseudoOp True if the instruction is a pseudo operation.
|
|
* @since 1.2.0
|
|
*/
|
|
void setTupleType(fcml_uint8_t tupleType) {
|
|
_tupleType = tupleType;
|
|
}
|
|
|
|
private:
|
|
|
|
/**
|
|
* True if this is a shortcut.
|
|
* A good example of such instruction is 'cmpsb' as opposed to 'cmps
|
|
* byte ptr [si],byte ptr [di]'. It is very important to take this
|
|
* information into consideration when instruction models are analyzed
|
|
* because there is no operands in the GIM for shortcuts.
|
|
*/
|
|
bool _isShortcut;
|
|
/**
|
|
* True if given instruction is a short form of pseudo-ops instructions.
|
|
* See 'vcmpunordsd' for instance.
|
|
*/
|
|
bool _isPseudoOp;
|
|
/**
|
|
* Code of the disassembled instruction.
|
|
*/
|
|
fcml_uint8_t _instructionCode[FCML_INSTRUCTION_SIZE];
|
|
/**
|
|
* Instruction size in bytes.
|
|
*/
|
|
fcml_usize _instructionSize;
|
|
/**
|
|
* Some additional information about decoded instruction prefixes.
|
|
*/
|
|
PrefixesDetails _prefixesDetails;
|
|
/**
|
|
* All disassembler specific information about operands going there.
|
|
*/
|
|
OperandDetails _operandDetails[FCML_OPERANDS_COUNT];
|
|
/**
|
|
* Details about decoded ModR/M and SIB bytes.
|
|
*/
|
|
DecodedModRMDetails _modRMDetails;
|
|
/** Opcode field 's'.
|
|
* This is set only for informational purpose only and you should not use
|
|
* it for any critical functionality.
|
|
*/
|
|
bool _opcodeFieldSBit;
|
|
/** Opcode field 'w'.
|
|
* This is set only for informational purpose only and you should not
|
|
* use it for any critical functionality.
|
|
*/
|
|
bool _opcodeFieldWBit;
|
|
/**
|
|
* Instruction code/number. @see fcml_instructions.h header file.
|
|
*/
|
|
fcml_en_instruction _instruction;
|
|
/**
|
|
* Pseudo operation code.
|
|
*/
|
|
fcml_en_pseudo_operations _pseudoOp;
|
|
/**
|
|
* Code of the instruction form/addressing mode of the instruction above.
|
|
*/
|
|
fcml_uint16_t _addrMode;
|
|
/**
|
|
* Instruction group.
|
|
*/
|
|
fcml_uint64_t _instructionGroup;
|
|
/**
|
|
* Tuple type used by avx-512 instructions to calculate disp8.
|
|
*/
|
|
fcml_uint8_t _tupleType;
|
|
};
|
|
|
|
/** Disassembler result.
|
|
*
|
|
* It's a counterpart to the fcml_st_disassembler_result structure.
|
|
* @since 1.1.0
|
|
*/
|
|
class DisassemblerResult {
|
|
|
|
public:
|
|
|
|
/**
|
|
* Gets errors container with errors related to the failed
|
|
* disassembling process.
|
|
*
|
|
* @return The error container.
|
|
* @since 1.1.0
|
|
*/
|
|
const ErrorContainer& getErrorContainer() const {
|
|
return _errorContainer;
|
|
}
|
|
|
|
/**
|
|
* Gets errors container with errors related to the failed
|
|
* disassembling process.
|
|
*
|
|
* @return The error container.
|
|
* @since 1.1.0
|
|
*/
|
|
const Instruction& getInstruction() const {
|
|
return _instruction;
|
|
}
|
|
|
|
/**
|
|
* Gets instruction details associated with the instruction.
|
|
*
|
|
* @return The instruction details.
|
|
* @since 1.1.0
|
|
*/
|
|
const InstructionDetails& getInstructionDetails() const {
|
|
return _instructionDetails;
|
|
}
|
|
|
|
/**
|
|
* Cleans the disassembling result.
|
|
* @since 1.1.0
|
|
*/
|
|
void clean() {
|
|
_errorContainer.clean();
|
|
_instructionDetails = InstructionDetails();
|
|
_instruction = Instruction();
|
|
}
|
|
|
|
protected:
|
|
|
|
friend class Disassembler;
|
|
friend class DisassemblerTypeConverter;
|
|
|
|
/**
|
|
* Gets mutable instruction details.
|
|
* @return Instruction details.
|
|
* @since 1.1.0
|
|
*/
|
|
InstructionDetails& getInstructionDetailsInternal() {
|
|
return _instructionDetails;
|
|
}
|
|
|
|
/**
|
|
* Sets new instruction details for the disassembler.
|
|
* @param instructionDetails The instruction details.
|
|
* @since 1.1.0
|
|
*/
|
|
void setInstructionDetails(const InstructionDetails &instructionDetails) {
|
|
_instructionDetails = instructionDetails;
|
|
}
|
|
|
|
/**
|
|
* Gets mutable instruction.
|
|
* @return The mutable instruction.
|
|
* @since 1.1.0
|
|
*/
|
|
Instruction& getInstructionInternal() {
|
|
return _instruction;
|
|
}
|
|
|
|
/**
|
|
* Sets a new instruction for the result.
|
|
* @param instruction The instruction to be copied to the result.
|
|
* @since 1.1.0
|
|
*/
|
|
void setInstruction(const Instruction &instruction) {
|
|
_instruction = instruction;
|
|
}
|
|
|
|
/**
|
|
* Sets error container.
|
|
* @param errorContainer The error container.
|
|
* @since 1.1.0
|
|
*/
|
|
void setErrorContainer(const ErrorContainer &errorContainer) {
|
|
_errorContainer = errorContainer;
|
|
}
|
|
|
|
private:
|
|
|
|
/** Errors container */
|
|
ErrorContainer _errorContainer;
|
|
/** Instruction details. */
|
|
InstructionDetails _instructionDetails;
|
|
/** The disassembled instruction. */
|
|
Instruction _instruction;
|
|
|
|
};
|
|
|
|
/**
|
|
* Converts objects to their structures counterparts.
|
|
* @since 1.1.0
|
|
* @remarks Internal API, not intended to be used outside.
|
|
*/
|
|
class DisassemblerTypeConverter {
|
|
|
|
public:
|
|
|
|
static void convert(const DisassemblerContext &src,
|
|
fcml_st_disassembler_context &dest) {
|
|
dest.code = src.getCode();
|
|
dest.code_length = src.getCodeLength();
|
|
TypeConverter::convert(src.getEntryPoint(), dest.entry_point);
|
|
convert(src.getDisassemblerConf(), dest.configuration);
|
|
}
|
|
|
|
static void convert(const DisassemblerConf &src,
|
|
fcml_st_disassembler_conf &dest) {
|
|
dest.conditional_group = src.getConditionalGroup();
|
|
dest.carry_flag_conditional_suffix = src.isCarryFlagConditionalSuffix();
|
|
dest.enable_error_messages = src.isEnableErrorMessages();
|
|
dest.extend_disp_to_asa = src.isExtendDispToAsa();
|
|
dest.fail_if_unknown_instruction = src.isFailIfUnknownInstruction();
|
|
dest.increment_ip = src.isIncrementIp();
|
|
dest.short_forms = src.isShortForms();
|
|
}
|
|
|
|
static void convert(const fcml_st_decoded_modrm_details &src,
|
|
DecodedModRMDetails &dest) {
|
|
dest.setRip(FCML_TO_CPP_BOOL(src.is_rip));
|
|
Nullable<fcml_uint8_t> &modRM = dest.getModRM();
|
|
modRM.setNotNull(FCML_TO_CPP_BOOL(src.is_modrm));
|
|
modRM.setValue(src.modrm);
|
|
Nullable<fcml_uint8_t> &sib = dest.getSib();
|
|
sib.setNotNull(FCML_TO_CPP_BOOL(src.sib.is_not_null));
|
|
sib.setValue(src.sib.value);
|
|
TypeConverter::convert(src.displacement.displacement,
|
|
dest.getDisplacement());
|
|
Nullable<fcml_uint32_t> N;
|
|
N.setNotNull(FCML_TO_CPP_BOOL(src.displacement.N.is_not_null));
|
|
N.setValue(src.displacement.N.value);
|
|
dest.setN(N);
|
|
}
|
|
|
|
static void convert(const DecodedModRMDetails &src,
|
|
fcml_st_decoded_modrm_details &dest) {
|
|
dest.is_modrm = src.getModRM().isNotNull();
|
|
dest.is_rip = src.isRip();
|
|
dest.modrm = src.getModRM().getValue();
|
|
fcml_nuint8_t &sib = dest.sib;
|
|
sib.is_not_null = src.getSib().isNotNull();
|
|
sib.value = src.getSib().getValue();
|
|
TypeConverter::convert(src.getDisplacement(),
|
|
dest.displacement.displacement);
|
|
dest.displacement.N.is_not_null = src.getN().isNotNull();
|
|
dest.displacement.N.value = src.getN().getValue();
|
|
}
|
|
|
|
static void convert(const fcml_st_operand_details &src,
|
|
OperandDetails &dest) {
|
|
dest.setAccessMode(
|
|
static_cast<OperandDetails::AccessMode>(src.access_mode));
|
|
}
|
|
|
|
static void convert(const OperandDetails &src,
|
|
fcml_st_operand_details &dest) {
|
|
dest.access_mode =
|
|
static_cast<fcml_en_access_mode>(src.getAccessMode());
|
|
}
|
|
|
|
static void convert(const fcml_st_instruction_prefix &src,
|
|
InstructionPrefixDetails &dest) {
|
|
dest.setMandatoryPrefix(FCML_TO_CPP_BOOL(src.mandatory_prefix));
|
|
dest.setPrefix(src.prefix);
|
|
dest.setPrefixType(
|
|
static_cast<InstructionPrefixDetails::PrefixType>(src.prefix_type));
|
|
::memcpy(dest.getAvxBytes(), src.avx_bytes, sizeof(src.avx_bytes));
|
|
}
|
|
|
|
static void convert(const InstructionPrefixDetails &src,
|
|
fcml_st_instruction_prefix &dest) {
|
|
dest.mandatory_prefix = src.isMandatoryPrefix();
|
|
dest.prefix = src.getPrefix();
|
|
dest.prefix_type =
|
|
static_cast<fcml_en_prefix_types>(src.getPrefixType());
|
|
::memcpy(dest.avx_bytes, src.getAvxBytes(), sizeof(dest.avx_bytes));
|
|
}
|
|
|
|
static void convert(const fcml_st_prefixes_details src,
|
|
PrefixesDetails &dest) {
|
|
for (int i = 0; i < FCML_DASM_PREFIXES_COUNT; i++) {
|
|
convert(src.prefixes[i], dest.getPrefixes(i));
|
|
}
|
|
dest.setPrefixesCount(src.prefixes_count);
|
|
dest.setPrefixesBytesCount(src.prefixes_bytes_count);
|
|
dest.setBranch(FCML_TO_CPP_BOOL(src.is_branch));
|
|
dest.setNobranch(FCML_TO_CPP_BOOL(src.is_nobranch));
|
|
dest.setLock(FCML_TO_CPP_BOOL(src.is_lock));
|
|
dest.setRep(FCML_TO_CPP_BOOL(src.is_rep));
|
|
dest.setRepne(FCML_TO_CPP_BOOL(src.is_repne));
|
|
dest.setXrelease(FCML_TO_CPP_BOOL(src.is_xrelease));
|
|
dest.setXacquire(FCML_TO_CPP_BOOL(src.is_xacquire));
|
|
dest.setVex(FCML_TO_CPP_BOOL(src.is_vex));
|
|
dest.setEvex(FCML_TO_CPP_BOOL(src.is_evex));
|
|
dest.setXop(FCML_TO_CPP_BOOL(src.is_xop));
|
|
dest.setAvx(FCML_TO_CPP_BOOL(src.is_avx));
|
|
dest.setRex(FCML_TO_CPP_BOOL(src.is_rex));
|
|
dest.setAvxFirstByte(src.avx_first_byte);
|
|
dest.setR(src.R);
|
|
dest.setRPrim(src.R_prim);
|
|
dest.setX(src.X);
|
|
dest.setB(src.B);
|
|
dest.setW(src.W);
|
|
dest.setL(src.L);
|
|
dest.setLPrim(src.L_prim);
|
|
dest.setMmmm(src.mmmm);
|
|
dest.setVvvv(src.vvvv);
|
|
dest.setVPrim(src.V_prim);
|
|
dest.setPp(src.pp);
|
|
dest.setAaa(src.aaa);
|
|
dest.setBcast(src.b);
|
|
dest.setZ(src.z);
|
|
}
|
|
|
|
static void convert(const PrefixesDetails src,
|
|
fcml_st_prefixes_details &dest) {
|
|
for (int i = 0; i < FCML_DASM_PREFIXES_COUNT; i++) {
|
|
convert(src.getPrefixes(i), dest.prefixes[i]);
|
|
}
|
|
dest.prefixes_count = src.getPrefixesCount();
|
|
dest.prefixes_bytes_count = src.getPrefixesBytesCount();
|
|
dest.is_branch = src.isBranch();
|
|
dest.is_nobranch = src.isNobranch();
|
|
dest.is_lock = src.isLock();
|
|
dest.is_rep = src.isRep();
|
|
dest.is_repne = src.isRepne();
|
|
dest.is_xrelease = src.isXrelease();
|
|
dest.is_xacquire = src.isXacquire();
|
|
dest.is_vex = src.isVex();
|
|
dest.is_xop = src.isXop();
|
|
dest.is_avx = src.isAvx();
|
|
dest.is_evex = src.isEvex();
|
|
dest.is_rex = src.isRex();
|
|
dest.avx_first_byte = src.getAvxFirstByte();
|
|
dest.R = src.getR();
|
|
dest.R_prim = src.getRPrim();
|
|
dest.X = src.getX();
|
|
dest.B = src.getB();
|
|
dest.W = src.getW();
|
|
dest.L = src.getL();
|
|
dest.L_prim = src.getLPrim();
|
|
dest.mmmm = src.getMmmm();
|
|
dest.vvvv = src.getVvvv();
|
|
dest.V_prim = src.getVPrim();
|
|
dest.pp = src.getPp();
|
|
dest.aaa = src.getAaa();
|
|
dest.b = src.getBcast();
|
|
dest.z = src.getZ() ? 1 : 0;
|
|
}
|
|
|
|
static void convert(const fcml_st_instruction_details &src,
|
|
InstructionDetails &dest) {
|
|
dest.setTupleType(src.tuple_type);
|
|
dest.setAddrMode(src.addr_mode);
|
|
dest.setInstruction(src.instruction);
|
|
dest.setInstructionGroup(src.instruction_group);
|
|
dest.setInstructionSize(src.instruction_size);
|
|
dest.setOpcodeFieldSBit(FCML_TO_CPP_BOOL(src.opcode_field_s_bit));
|
|
dest.setOpcodeFieldWBit(FCML_TO_CPP_BOOL(src.opcode_field_w_bit));
|
|
dest.setIsPseudoOp(FCML_TO_CPP_BOOL(src.is_pseudo_op));
|
|
dest.setPseudoOp(src.pseudo_op);
|
|
dest.setShortcut(FCML_TO_CPP_BOOL(src.is_shortcut));
|
|
convert(src.modrm_details, dest.getModRmDetails());
|
|
for (int i = 0; i < FCML_OPERANDS_COUNT; i++) {
|
|
convert(src.operand_details[i], dest.getOperandDetails(i));
|
|
}
|
|
fcml_uint8_t *code = dest.getInstructionCode();
|
|
for (int i = 0; i < FCML_INSTRUCTION_SIZE; i++) {
|
|
code[i] = src.instruction_code[i];
|
|
}
|
|
convert(src.prefixes_details, dest.getPrefixesDetails());
|
|
}
|
|
|
|
static void convert(const InstructionDetails &src,
|
|
fcml_st_instruction_details &dest) {
|
|
dest.tuple_type = src.getTupleType();
|
|
dest.addr_mode = src.getAddrMode();
|
|
dest.instruction = src.getInstruction();
|
|
dest.instruction_group = src.getInstructionGroup();
|
|
dest.instruction_size = src.getInstructionSize();
|
|
dest.opcode_field_s_bit = src.isOpcodeFieldSBit();
|
|
dest.opcode_field_w_bit = src.isOpcodeFieldWBit();
|
|
dest.is_pseudo_op = src.isPseudoOp();
|
|
dest.pseudo_op = src.getPseudoOp();
|
|
dest.is_shortcut = src.isShortcut();
|
|
convert(src.getModRmDetails(), dest.modrm_details);
|
|
for (int i = 0; i < FCML_OPERANDS_COUNT; i++) {
|
|
convert(src.getOperandDetails(i), dest.operand_details[i]);
|
|
}
|
|
for (int i = 0; i < FCML_INSTRUCTION_SIZE; i++) {
|
|
dest.instruction_code[i] = src.getInstructionCode()[i];
|
|
}
|
|
convert(src.getPrefixesDetails(), dest.prefixes_details);
|
|
}
|
|
|
|
static void convert(const fcml_st_disassembler_result &src,
|
|
DisassemblerResult &dest) {
|
|
TypeConverter::convert(src.instruction, dest.getInstructionInternal());
|
|
convert(src.instruction_details, dest.getInstructionDetailsInternal());
|
|
}
|
|
|
|
static void convert(const DisassemblerResult &src,
|
|
fcml_st_disassembler_result &dest) {
|
|
TypeConverter::convert(src.getInstruction(), dest.instruction);
|
|
convert(src.getInstructionDetails(), dest.instruction_details);
|
|
}
|
|
|
|
static void free(fcml_st_disassembler_result &src) {
|
|
TypeConverter::free(src.instruction);
|
|
}
|
|
|
|
};
|
|
|
|
/** Disassembler wrapper.
|
|
* @since 1.1.0
|
|
*/
|
|
class Disassembler: public NonCopyable, protected DialectAware {
|
|
public:
|
|
|
|
/**
|
|
* Creates a disassembler instance for the given dialect.
|
|
*
|
|
* @param dialect The dialect for the disassembler.
|
|
* @throw InitException Cannot initialize the disassembler.
|
|
* @since 1.1.0
|
|
*/
|
|
Disassembler(Dialect &dialect) :
|
|
_dialect(dialect) {
|
|
fcml_ceh_error error = ::fcml_fn_disassembler_init(
|
|
extractDialect(dialect), &_disassembler);
|
|
if (error) {
|
|
throw InitException(
|
|
FCML_TEXT("Cannot initialize the disassembler."), error);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Destructor.
|
|
* @since 1.1.0
|
|
*/
|
|
virtual ~Disassembler() {
|
|
if (_disassembler) {
|
|
::fcml_fn_disassembler_free(_disassembler);
|
|
_disassembler = NULL;
|
|
}
|
|
}
|
|
|
|
public:
|
|
|
|
/**
|
|
* Disassembled the next instruction from the context.
|
|
*
|
|
* @param ctx Context describing the next instruction to disassemble.
|
|
* @param[out] disassemblerResult Disassembler result.
|
|
* @throw DisassemblingFailedException Disassemblation failed.
|
|
* @return Error code.
|
|
* @since 1.1.0
|
|
*/
|
|
fcml_ceh_error disassemble(DisassemblerContext &ctx,
|
|
DisassemblerResult &disassemblerResult) {
|
|
|
|
fcml_ceh_error error = FCML_CEH_GEC_NO_ERROR;
|
|
|
|
fcml_st_disassembler_context context;
|
|
DisassemblerTypeConverter::convert(ctx, context);
|
|
|
|
context.disassembler = _disassembler;
|
|
|
|
/* Prepare assembler result. */
|
|
fcml_st_disassembler_result disassembler_result;
|
|
::fcml_fn_disassembler_result_prepare(&disassembler_result);
|
|
|
|
try {
|
|
|
|
disassemblerResult.clean();
|
|
|
|
error = ::fcml_fn_disassemble(&context, &disassembler_result);
|
|
|
|
ErrorContainer errorContainer;
|
|
ErrorTypeConverter::convert(disassembler_result.errors,
|
|
errorContainer);
|
|
|
|
disassemblerResult.setErrorContainer(errorContainer);
|
|
|
|
if (error && ctx.getDisassemblerConf().isThrowExceptionOnError()) {
|
|
::fcml_fn_disassembler_result_free(&disassembler_result);
|
|
throw DisassemblingFailedException(
|
|
FCML_TEXT("Assembling failed."), errorContainer, error);
|
|
}
|
|
|
|
if (!error) {
|
|
|
|
// Convert result.
|
|
DisassemblerTypeConverter::convert(disassembler_result,
|
|
disassemblerResult);
|
|
|
|
ctx.getEntryPoint().setIP(context.entry_point.ip);
|
|
ctx.setCode(context.code);
|
|
ctx.setCodeLength(context.code_length);
|
|
|
|
}
|
|
|
|
::fcml_fn_disassembler_result_free(&disassembler_result);
|
|
|
|
} catch (std::exception &exc) {
|
|
// If anything failed, free assembler results.
|
|
::fcml_fn_disassembler_result_free(&disassembler_result);
|
|
throw exc;
|
|
}
|
|
|
|
return error;
|
|
}
|
|
|
|
/**
|
|
* Gets dialect associated with the disassembler.
|
|
* @return The dialect instance associated with the disassembler.
|
|
* @since 1.1.0
|
|
*/
|
|
Dialect& getDialect() const {
|
|
return _dialect;
|
|
}
|
|
|
|
private:
|
|
|
|
/** The dialect associated with the disassembler. */
|
|
Dialect &_dialect;
|
|
/** The disassembler instance. */
|
|
fcml_st_disassembler *_disassembler;
|
|
|
|
};
|
|
|
|
}
|
|
|
|
#endif //FCML_DISASSEMBLER_HPP_
|
|
|