mirror of
https://github.com/AssetRipper/Capstone.NET.git
synced 2026-11-13 18:06:54 -10:00
1179 lines
50 KiB
C#
1179 lines
50 KiB
C#
using Gee.External.Capstone.Arm;
|
|
using Gee.External.Capstone.Arm64;
|
|
using Gee.External.Capstone.M68K;
|
|
using Gee.External.Capstone.Mips;
|
|
using Gee.External.Capstone.PowerPc;
|
|
using Gee.External.Capstone.X86;
|
|
using Gee.External.Capstone.XCore;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
|
|
namespace Gee.External.Capstone {
|
|
/// <summary>
|
|
/// Capstone Disassembler.
|
|
/// </summary>
|
|
public abstract class CapstoneDisassembler : IDisposable {
|
|
/// <summary>
|
|
/// Determine if the ARM64 Architecture is Supported.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Indicates if the ARM64 architecture is supported. A boolean true indicates it is supported. A boolean
|
|
/// false otherwise.
|
|
/// </remarks>
|
|
public static bool IsArm64Supported {
|
|
get {
|
|
var value = NativeCapstone.Query(NativeQueryOption.QueryArm64Architecture);
|
|
return value;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Determine if the ARM Architecture is Supported.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Indicates if the ARM architecture is supported. A boolean true indicates it is supported. A boolean
|
|
/// false otherwise.
|
|
/// </remarks>
|
|
public static bool IsArmSupported {
|
|
get {
|
|
var value = NativeCapstone.Query(NativeQueryOption.QueryArmArchitecture);
|
|
return value;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Determine if Diet Mode is Enabled.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Indicates if Diet Mode is enabled. A boolean true indicates it is enabled. A boolean false otherwise.
|
|
/// </remarks>
|
|
public static bool IsDietModeEnabled {
|
|
get {
|
|
var value = NativeCapstone.Query(NativeQueryOption.QueryDietMode);
|
|
return value;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Determine if the Ethereum EVM Architecture is Supported.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Indicates if the Ethereum EVM architecture is supported. A boolean true indicates it is supported. A
|
|
/// boolean false otherwise.
|
|
/// </remarks>
|
|
internal static bool IsEvmSupported {
|
|
get {
|
|
var value = NativeCapstone.Query(NativeQueryOption.QueryEvmArchitecture);
|
|
return value;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Determine if the M680X Architecture is Supported.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Indicates if the M680X architecture is supported. A boolean true indicates it is supported. A boolean
|
|
/// false otherwise.
|
|
/// </remarks>
|
|
internal static bool IsM680XSupported {
|
|
get {
|
|
var value = NativeCapstone.Query(NativeQueryOption.QueryM680XArchitecture);
|
|
return value;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Determine if the M68K Architecture is Supported.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Indicates if the M68K architecture is supported. A boolean true indicates it is supported. A boolean
|
|
/// false otherwise.
|
|
/// </remarks>
|
|
public static bool IsM68KSupported {
|
|
get {
|
|
var value = NativeCapstone.Query(NativeQueryOption.QueryM68KArchitecture);
|
|
return value;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Determine if the MIPS Architecture is Supported.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Indicates if the MIPS architecture is supported. A boolean true indicates it is supported. A boolean
|
|
/// false otherwise.
|
|
/// </remarks>
|
|
public static bool IsMipsSupported {
|
|
get {
|
|
var value = NativeCapstone.Query(NativeQueryOption.QueryMipsArchitecture);
|
|
return value;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Determine if the PowerPC Architecture is Supported.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Indicates if the PowerPC architecture is supported. A boolean true indicates it is supported. A
|
|
/// boolean false otherwise.
|
|
/// </remarks>
|
|
public static bool IsPowerPcSupported {
|
|
get {
|
|
var value = NativeCapstone.Query(NativeQueryOption.QueryPowerPcArchitecture);
|
|
return value;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Determine if the SPARC Architecture is Supported.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Indicates if the SPARC architecture is supported. A boolean true indicates it is supported. A boolean
|
|
/// false otherwise.
|
|
/// </remarks>
|
|
internal static bool IsSparcSupported {
|
|
get {
|
|
var value = NativeCapstone.Query(NativeQueryOption.QuerySparcArchitecture);
|
|
return value;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Determine if the SystemZ Architecture is Supported.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Indicates if the SystemZ architecture is supported. A boolean true indicates it is supported. A
|
|
/// boolean false otherwise.
|
|
/// </remarks>
|
|
internal static bool IsSystemZSupported {
|
|
get {
|
|
var value = NativeCapstone.Query(NativeQueryOption.QuerySystemZArchitecture);
|
|
return value;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Determine if the TMS320C64X Architecture is Supported.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Indicates if the TMS320C64X architecture is supported. A boolean true indicates it is supported. A
|
|
/// boolean false otherwise.
|
|
/// </remarks>
|
|
internal static bool IsTms320C64XSupported {
|
|
get {
|
|
var value = NativeCapstone.Query(NativeQueryOption.QueryTms320C64XArchitecture);
|
|
return value;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Determine if X86 Reduce Mode is Enabled.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Indicates if X86 Reduce Mode is enabled. A boolean true indicates it is enabled. A boolean false
|
|
/// otherwise.
|
|
/// </remarks>
|
|
public static bool IsX86ReduceModeEnabled {
|
|
get {
|
|
var value = NativeCapstone.Query(NativeQueryOption.QueryX86ReduceMode);
|
|
return value;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Determine if the X86 Architecture is Supported.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Indicates if the X86 architecture is supported. A boolean true indicates it is supported. A boolean
|
|
/// false otherwise.
|
|
/// </remarks>
|
|
public static bool IsX86Supported {
|
|
get {
|
|
var value = NativeCapstone.Query(NativeQueryOption.QueryX86Architecture);
|
|
return value;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Determine if the XCore Architecture is Supported.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Indicates if the XCore architecture is supported. A boolean true indicates it is supported. A boolean
|
|
/// false otherwise.
|
|
/// </remarks>
|
|
public static bool IsXCoreSupported {
|
|
get {
|
|
var value = NativeCapstone.Query(NativeQueryOption.QueryXCoreArchitecture);
|
|
return value;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get Capstone Library's Version.
|
|
/// </summary>
|
|
/// <value>
|
|
/// The Capstone library's version.
|
|
/// </value>
|
|
public static Version Version {
|
|
get {
|
|
var value = NativeCapstone.GetVersion();
|
|
return value;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get Disassemble Architecture.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Represents the disassembler's hardware architecture.
|
|
/// </remarks>
|
|
public abstract DisassembleArchitecture DisassembleArchitecture { get; }
|
|
|
|
/// <summary>
|
|
/// Enable or Disable Instruction Details.
|
|
/// </summary>
|
|
/// <exception cref="Gee.External.Capstone.CapstoneException">
|
|
/// Thrown if the instruction details option could not be set.
|
|
/// </exception>
|
|
/// <exception cref="System.ObjectDisposedException">
|
|
/// Thrown if the disassembler is disposed.
|
|
/// </exception>
|
|
public abstract bool EnableInstructionDetails { get; set; }
|
|
|
|
/// <summary>
|
|
/// Enable or Disable Skip Data Mode.
|
|
/// </summary>
|
|
/// <exception cref="Gee.External.Capstone.CapstoneException">
|
|
/// Thrown if the Skip Data Mode option could not be set.
|
|
/// </exception>
|
|
/// <exception cref="System.ObjectDisposedException">
|
|
/// Thrown if the disassembler is disposed.
|
|
/// </exception>
|
|
public abstract bool EnableSkipDataMode { get; set; }
|
|
|
|
/// <summary>
|
|
/// Get Disassembler's Handle.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Represents the disassembler's native handle.
|
|
/// </remarks>
|
|
internal abstract NativeDisassemblerHandle Handle { get; }
|
|
|
|
/// <summary>
|
|
/// Get Native Disassemble Mode.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Represents the disassembler's native hardware mode.
|
|
/// </remarks>
|
|
internal abstract NativeDisassembleMode NativeDisassembleMode { get; }
|
|
|
|
/// <summary>
|
|
/// Get and Set Skip Data Instruction Mnemonic.
|
|
/// </summary>
|
|
/// <exception cref="System.ArgumentNullException">
|
|
/// Thrown if the value is a null reference.
|
|
/// </exception>
|
|
/// <exception cref="System.ObjectDisposedException">
|
|
/// Thrown if the disassembler is disposed.
|
|
/// </exception>
|
|
public abstract string SkipDataInstructionMnemonic { get; set; }
|
|
|
|
/// <summary>
|
|
/// Create an ARM64 Disassembler.
|
|
/// </summary>
|
|
/// <param name="disassembleMode">
|
|
/// The hardware mode for the disassembler to use.
|
|
/// </param>
|
|
/// <returns>
|
|
/// An ARM64 disassembler.
|
|
/// </returns>
|
|
/// <exception cref="Gee.External.Capstone.CapstoneException">
|
|
/// Thrown if a disassembler could not be created.
|
|
/// </exception>
|
|
/// <exception cref="System.OutOfMemoryException">
|
|
/// Thrown if sufficient memory cannot be allocated to perform the operation as a rare indication that the
|
|
/// system is under heavy load.
|
|
/// </exception>
|
|
public static CapstoneArm64Disassembler CreateArm64Disassembler(Arm64DisassembleMode disassembleMode) {
|
|
return new CapstoneArm64Disassembler(disassembleMode);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Create an ARM Disassembler.
|
|
/// </summary>
|
|
/// <param name="disassembleMode">
|
|
/// The hardware mode for the disassembler to use.
|
|
/// </param>
|
|
/// <returns>
|
|
/// An ARM disassembler.
|
|
/// </returns>
|
|
/// <exception cref="Gee.External.Capstone.CapstoneException">
|
|
/// Thrown if a disassembler could not be created.
|
|
/// </exception>
|
|
/// <exception cref="System.OutOfMemoryException">
|
|
/// Thrown if sufficient memory cannot be allocated to perform the operation as a rare indication that the
|
|
/// system is under heavy load.
|
|
/// </exception>
|
|
public static CapstoneArmDisassembler CreateArmDisassembler(ArmDisassembleMode disassembleMode) {
|
|
return new CapstoneArmDisassembler(disassembleMode);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Create an M68K Disassembler.
|
|
/// </summary>
|
|
/// <param name="disassembleMode">
|
|
/// The hardware mode for the disassembler to use.
|
|
/// </param>
|
|
/// <returns>
|
|
/// An M68K disassembler.
|
|
/// </returns>
|
|
/// <exception cref="Gee.External.Capstone.CapstoneException">
|
|
/// Thrown if a disassembler could not be created.
|
|
/// </exception>
|
|
/// <exception cref="System.OutOfMemoryException">
|
|
/// Thrown if sufficient memory cannot be allocated to perform the operation as a rare indication that the
|
|
/// system is under heavy load.
|
|
/// </exception>
|
|
public static CapstoneM68KDisassembler CreateM68KDisassembler(M68KDisassembleMode disassembleMode) {
|
|
return new CapstoneM68KDisassembler(disassembleMode);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Create a MIPS Disassembler.
|
|
/// </summary>
|
|
/// <param name="disassembleMode">
|
|
/// The hardware mode for the disassembler to use.
|
|
/// </param>
|
|
/// <returns>
|
|
/// A MIPS disassembler.
|
|
/// </returns>
|
|
/// <exception cref="Gee.External.Capstone.CapstoneException">
|
|
/// Thrown if a disassembler could not be created.
|
|
/// </exception>
|
|
/// <exception cref="System.OutOfMemoryException">
|
|
/// Thrown if sufficient memory cannot be allocated to perform the operation as a rare indication that the
|
|
/// system is under heavy load.
|
|
/// </exception>
|
|
public static CapstoneMipsDisassembler CreateMipsDisassembler(MipsDisassembleMode disassembleMode) {
|
|
return new CapstoneMipsDisassembler(disassembleMode);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Create a PowerPC Disassembler.
|
|
/// </summary>
|
|
/// <param name="disassembleMode">
|
|
/// The hardware mode for the disassembler to use.
|
|
/// </param>
|
|
/// <returns>
|
|
/// A PowerPC disassembler.
|
|
/// </returns>
|
|
/// <exception cref="Gee.External.Capstone.CapstoneException">
|
|
/// Thrown if a disassembler could not be created.
|
|
/// </exception>
|
|
/// <exception cref="System.OutOfMemoryException">
|
|
/// Thrown if sufficient memory cannot be allocated to perform the operation as a rare indication that the
|
|
/// system is under heavy load.
|
|
/// </exception>
|
|
public static CapstonePowerPcDisassembler CreatePowerPcDisassembler(PowerPcDisassembleMode disassembleMode) {
|
|
return new CapstonePowerPcDisassembler(disassembleMode);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Create an X86 Disassembler.
|
|
/// </summary>
|
|
/// <param name="disassembleMode">
|
|
/// The hardware mode for the disassembler to use.
|
|
/// </param>
|
|
/// <returns>
|
|
/// An X86 disassembler.
|
|
/// </returns>
|
|
/// <exception cref="Gee.External.Capstone.CapstoneException">
|
|
/// Thrown if a disassembler could not be created.
|
|
/// </exception>
|
|
/// <exception cref="System.OutOfMemoryException">
|
|
/// Thrown if sufficient memory cannot be allocated to perform the operation as a rare indication that the
|
|
/// system is under heavy load.
|
|
/// </exception>
|
|
public static CapstoneX86Disassembler CreateX86Disassembler(X86DisassembleMode disassembleMode) {
|
|
return new CapstoneX86Disassembler(disassembleMode);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Create an XCore Disassembler.
|
|
/// </summary>
|
|
/// <param name="disassembleMode">
|
|
/// The hardware mode for the disassembler to use.
|
|
/// </param>
|
|
/// <returns>
|
|
/// An XCore disassembler.
|
|
/// </returns>
|
|
/// <exception cref="Gee.External.Capstone.CapstoneException">
|
|
/// Thrown if a disassembler could not be created.
|
|
/// </exception>
|
|
/// <exception cref="System.OutOfMemoryException">
|
|
/// Thrown if sufficient memory cannot be allocated to perform the operation as a rare indication that the
|
|
/// system is under heavy load.
|
|
/// </exception>
|
|
public static CapstoneXCoreDisassembler CreateXCoreDisassembler(XCoreDisassembleMode disassembleMode) {
|
|
return new CapstoneXCoreDisassembler(disassembleMode);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Throw an Exception if Diet Mode is Enabled.
|
|
/// </summary>
|
|
/// <exception cref="System.NotSupportedException">
|
|
/// Thrown if Diet Mode is enabled.
|
|
/// </exception>
|
|
internal static void ThrowIfDietModeIsEnabled() {
|
|
if (CapstoneDisassembler.IsDietModeEnabled) {
|
|
const string detailMessage = "An operation is not supported when Diet Mode is enabled.";
|
|
throw new NotSupportedException(detailMessage);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Throw an Exception if a Value is a Null Reference.
|
|
/// </summary>
|
|
/// <typeparam name="T">
|
|
/// The type of the value.
|
|
/// </typeparam>
|
|
/// <param name="name">
|
|
/// The name of the parameter the value was passed as an argument to.
|
|
/// </param>
|
|
/// <param name="value">
|
|
/// The value.
|
|
/// </param>
|
|
/// <exception cref="System.ArgumentNullException">
|
|
/// Thrown if the value is a null reference.
|
|
/// </exception>
|
|
internal static void ThrowIfValueIsNullReference<T>(string name, T value) where T : class {
|
|
if (value == null) {
|
|
const string detailMessage = "A value cannot be a null reference.";
|
|
throw new ArgumentNullException(name, detailMessage);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Dispose Object.
|
|
/// </summary>
|
|
public abstract void Dispose();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Capstone Disassembler.
|
|
/// </summary>
|
|
/// <typeparam name="TDisassembleMode">
|
|
/// The type of the hardware mode for the disassembler to use.
|
|
/// </typeparam>
|
|
/// <typeparam name="TInstruction">
|
|
/// The type of the disassembled instructions.
|
|
/// </typeparam>
|
|
/// <typeparam name="TInstructionDetail">
|
|
/// The type of the instructions' details.
|
|
/// </typeparam>
|
|
/// <typeparam name="TInstructionGroup">
|
|
/// The type of the instructions' architecture specific instruction groups.
|
|
/// </typeparam>
|
|
/// <typeparam name="TInstructionGroupId">
|
|
/// The type of the instructions' architecture specific instruction group unique identifiers.
|
|
/// </typeparam>
|
|
/// <typeparam name="TInstructionId">
|
|
/// The type of the instructions' unique identifiers.
|
|
/// </typeparam>
|
|
/// <typeparam name="TRegister">
|
|
/// The type of the instructions' architecture specific registers.
|
|
/// </typeparam>
|
|
/// <typeparam name="TRegisterId">
|
|
/// The type of the instructions' architecture specific register unique identifiers.
|
|
/// </typeparam>
|
|
public abstract class CapstoneDisassembler<TDisassembleMode, TInstruction, TInstructionDetail, TInstructionGroup, TInstructionGroupId, TInstructionId, TRegister, TRegisterId> : CapstoneDisassembler
|
|
where TDisassembleMode : Enum
|
|
where TInstruction : Instruction<TInstruction, TInstructionDetail, TDisassembleMode, TInstructionGroup, TInstructionGroupId, TInstructionId, TRegister, TRegisterId>
|
|
where TInstructionDetail : InstructionDetail<TInstructionDetail, TDisassembleMode, TInstructionGroup, TInstructionGroupId, TInstruction, TInstructionId, TRegister, TRegisterId>
|
|
where TInstructionGroup : InstructionGroup<TInstructionGroupId>
|
|
where TInstructionGroupId : Enum
|
|
where TInstructionId : Enum
|
|
where TRegister : Register<TRegisterId>
|
|
where TRegisterId : Enum {
|
|
/// <summary>
|
|
/// Disassemble Architecture.
|
|
/// </summary>
|
|
private readonly DisassembleArchitecture _disassembleArchitecture;
|
|
|
|
/// <summary>
|
|
/// Disassemble Mode.
|
|
/// </summary>
|
|
private TDisassembleMode _disassembleMode;
|
|
|
|
/// <summary>
|
|
/// Disassemble Syntax.
|
|
/// </summary>
|
|
private DisassembleSyntax _disassembleSyntax;
|
|
|
|
/// <summary>
|
|
/// Enable Instruction Details Flag.
|
|
/// </summary>
|
|
private bool _enableInstructionDetails;
|
|
|
|
/// <summary>
|
|
/// Enable Skip Data Mode Flag.
|
|
/// </summary>
|
|
private bool _enableSkipDataMode;
|
|
|
|
/// <summary>
|
|
/// Disassembler's Handle.
|
|
/// </summary>
|
|
private readonly NativeDisassemblerHandle _handle;
|
|
|
|
/// <summary>
|
|
/// Native Disassemble Mode.
|
|
/// </summary>
|
|
private NativeDisassembleMode _nativeDisassembleMode;
|
|
|
|
/// <summary>
|
|
/// Skip Data Callback.
|
|
/// </summary>
|
|
private Func<byte[], long, long> _skipDataCallback;
|
|
|
|
/// <summary>
|
|
/// Skip Data Instruction Mnemonic.
|
|
/// </summary>
|
|
private string _skipDataInstructionMnemonic;
|
|
|
|
/// <summary>
|
|
/// Get Disassemble Architecture.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Represents the disassembler's hardware architecture.
|
|
/// </remarks>
|
|
public override DisassembleArchitecture DisassembleArchitecture => this._disassembleArchitecture;
|
|
|
|
/// <summary>
|
|
/// Get and Set Disassemble Mode.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Represents the disassembler's hardware mode.
|
|
/// </remarks>
|
|
/// <exception cref="Gee.External.Capstone.CapstoneException">
|
|
/// Thrown if the disassemble mode option could not be set.
|
|
/// </exception>
|
|
/// <exception cref="System.ObjectDisposedException">
|
|
/// Thrown if the disassembler handle is disposed.
|
|
/// </exception>
|
|
public TDisassembleMode DisassembleMode {
|
|
get => this._disassembleMode;
|
|
set {
|
|
// ...
|
|
//
|
|
// This is an ugly operation but it is the only way I am familiar with to convert a <c>System.Enum</c>
|
|
// to a 32-bit integer to pass to the Capstone API. It should be relatively quick since
|
|
// <c>System.Enum</c> implements <c>System.IConvertible</c>.
|
|
var iDisassembleMode = Convert.ToInt32(value);
|
|
var disassembleMode = (NativeDisassembleMode) iDisassembleMode;
|
|
|
|
// ..
|
|
//
|
|
// Throws an exception if the operation fails.
|
|
NativeCapstone.SetDisassembleModeOption(this._handle, disassembleMode);
|
|
|
|
this._disassembleMode = value;
|
|
this._nativeDisassembleMode = disassembleMode;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get and Set Disassemble Syntax.
|
|
/// </summary>
|
|
/// <exception cref="Gee.External.Capstone.CapstoneException">
|
|
/// Thrown if the disassemble syntax option could not be set.
|
|
/// </exception>
|
|
/// <exception cref="System.ObjectDisposedException">
|
|
/// Thrown if the disassembler is disposed.
|
|
/// </exception>
|
|
public DisassembleSyntax DisassembleSyntax {
|
|
get => this._disassembleSyntax;
|
|
set {
|
|
// ..
|
|
//
|
|
// Throws an exception if the operation fails.
|
|
const NativeDisassemblerOptionType optionType = NativeDisassemblerOptionType.SetSyntax;
|
|
var optionValue = (NativeDisassemblerOptionValue) value;
|
|
NativeCapstone.SetDisassemblerOption(this._handle, optionType, optionValue);
|
|
|
|
this._disassembleSyntax = value;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Enable or Disable Instruction Details.
|
|
/// </summary>
|
|
/// <exception cref="Gee.External.Capstone.CapstoneException">
|
|
/// Thrown if the instruction details option could not be set.
|
|
/// </exception>
|
|
/// <exception cref="System.ObjectDisposedException">
|
|
/// Thrown if the disassembler is disposed.
|
|
/// </exception>
|
|
public override bool EnableInstructionDetails {
|
|
get => this._enableInstructionDetails;
|
|
set {
|
|
// ..
|
|
//
|
|
// Throws an exception if the operation fails.
|
|
const NativeDisassemblerOptionType optionType = NativeDisassemblerOptionType.SetInstructionDetails;
|
|
var optionValue = value ? NativeDisassemblerOptionValue.Enable : NativeDisassemblerOptionValue.Disable;
|
|
NativeCapstone.SetDisassemblerOption(this._handle, optionType, optionValue);
|
|
|
|
this._enableInstructionDetails = value;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Enable or Disable Skip Data Mode.
|
|
/// </summary>
|
|
/// <exception cref="Gee.External.Capstone.CapstoneException">
|
|
/// Thrown if the Skip Data Mode option could not be set.
|
|
/// </exception>
|
|
/// <exception cref="System.ObjectDisposedException">
|
|
/// Thrown if the disassembler is disposed.
|
|
/// </exception>
|
|
public override bool EnableSkipDataMode {
|
|
get => this._enableSkipDataMode;
|
|
set {
|
|
// ..
|
|
//
|
|
// Throws an exception if the operation fails.
|
|
const NativeDisassemblerOptionType optionType = NativeDisassemblerOptionType.SetSkipData;
|
|
var optionValue = value ? NativeDisassemblerOptionValue.Enable : NativeDisassemblerOptionValue.Disable;
|
|
NativeCapstone.SetDisassemblerOption(this._handle, optionType, optionValue);
|
|
|
|
this._enableSkipDataMode = value;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get Disassembler's Handle.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Represents the disassembler's native handle.
|
|
/// </remarks>
|
|
internal override NativeDisassemblerHandle Handle => this._handle;
|
|
|
|
/// <summary>
|
|
/// Get Native Disassemble Mode.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Represents the disassembler's native hardware mode.
|
|
/// </remarks>
|
|
internal override NativeDisassembleMode NativeDisassembleMode => this._nativeDisassembleMode;
|
|
|
|
/// <summary>
|
|
/// Get and Set Skip Data Callback.
|
|
/// </summary>
|
|
/// <exception cref="System.ObjectDisposedException">
|
|
/// Thrown if the disassembler is disposed.
|
|
/// </exception>
|
|
public Func<byte[], long, long> SkipDataCallback {
|
|
get => this._skipDataCallback;
|
|
set {
|
|
this.ThrowIfDisassemblerIsDisposed();
|
|
this._skipDataCallback = value;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get and Set Skip Data Instruction Mnemonic.
|
|
/// </summary>
|
|
/// <exception cref="System.ArgumentNullException">
|
|
/// Thrown if the value is a null reference.
|
|
/// </exception>
|
|
/// <exception cref="System.ObjectDisposedException">
|
|
/// Thrown if the disassembler is disposed.
|
|
/// </exception>
|
|
public override string SkipDataInstructionMnemonic {
|
|
get => this._skipDataInstructionMnemonic;
|
|
set {
|
|
this.ThrowIfDisassemblerIsDisposed();
|
|
CapstoneDisassembler.ThrowIfValueIsNullReference(nameof(this.SkipDataInstructionMnemonic), value);
|
|
|
|
this._skipDataInstructionMnemonic = value;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Create a Disassembler.
|
|
/// </summary>
|
|
/// <param name="disassembleArchitecture">
|
|
/// The hardware architecture for the disassembler to use.
|
|
/// </param>
|
|
/// <param name="disassembleMode">
|
|
/// The hardware mode for the disassembler to use.
|
|
/// </param>
|
|
/// <exception cref="Gee.External.Capstone.CapstoneException">
|
|
/// Thrown if a disassembler could not be created.
|
|
/// </exception>
|
|
/// <exception cref="System.ArgumentException">
|
|
/// Thrown if the disassemble architecture is invalid, or if the disassemble mode is invalid or
|
|
/// unsupported by the disassemble architecture.
|
|
/// </exception>
|
|
/// <exception cref="System.OutOfMemoryException">
|
|
/// Thrown if sufficient memory cannot be allocated to perform the operation as a rare indication that the
|
|
/// system is under heavy load.
|
|
/// </exception>
|
|
private protected CapstoneDisassembler(DisassembleArchitecture disassembleArchitecture, TDisassembleMode disassembleMode) {
|
|
this._disassembleArchitecture = disassembleArchitecture;
|
|
this._disassembleMode = disassembleMode;
|
|
this._disassembleSyntax = DisassembleSyntax.Intel;
|
|
this._skipDataInstructionMnemonic = ".byte";
|
|
// ...
|
|
//
|
|
// ...
|
|
this._nativeDisassembleMode = CreateNativeDisassembleMode(this);
|
|
// ...
|
|
//
|
|
// ...
|
|
this._handle = NativeCapstone.CreateDisassembler(this._disassembleArchitecture, this._nativeDisassembleMode);
|
|
|
|
// <summary>
|
|
// Create Native Disassemble Mode.
|
|
// </summary>
|
|
NativeDisassembleMode CreateNativeDisassembleMode(CapstoneDisassembler<TDisassembleMode, TInstruction, TInstructionDetail, TInstructionGroup, TInstructionGroupId, TInstructionId, TRegister, TRegisterId> @this) {
|
|
// ...
|
|
//
|
|
// This is an ugly operation but it is the only way I am familiar with to convert a <c>System.Enum</c> to
|
|
// a 32-bit integer to pass to the Capstone API. It should be relatively quick since <c>System.Enum</c>
|
|
// implements <c>System.IConvertible</c>.
|
|
var cIDisassembleMode = Convert.ToInt32(@this._disassembleMode);
|
|
return (NativeDisassembleMode) cIDisassembleMode;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Create an Instruction.
|
|
/// </summary>
|
|
/// <param name="hInstruction">
|
|
/// An instruction handle.
|
|
/// </param>
|
|
/// <returns>
|
|
/// An instruction.
|
|
/// </returns>
|
|
private protected abstract TInstruction CreateInstruction(NativeInstructionHandle hInstruction);
|
|
|
|
/// <summary>
|
|
/// Disassemble Binary Code.
|
|
/// </summary>
|
|
/// <param name="binaryCode">
|
|
/// An array of bytes representing the binary code to disassemble.
|
|
/// </param>
|
|
/// <returns>
|
|
/// An array of disassembled instructions.
|
|
/// </returns>
|
|
/// <exception cref="System.ArgumentNullException">
|
|
/// Thrown if the binary code array is a null reference.
|
|
/// </exception>
|
|
/// <exception cref="System.ObjectDisposedException">
|
|
/// Thrown if the disassembler is disposed.
|
|
/// </exception>
|
|
public TInstruction[] Disassemble(byte[] binaryCode) {
|
|
// ...
|
|
//
|
|
// Throws an exception if the operation fails.
|
|
var instructions = this.Disassemble(binaryCode, 0X1000);
|
|
return instructions;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Disassemble Binary Code.
|
|
/// </summary>
|
|
/// <param name="binaryCode">
|
|
/// An array of bytes representing the binary code to disassemble.
|
|
/// </param>
|
|
/// <param name="startingAddress">
|
|
/// The address of the first instruction in the binary code array.
|
|
/// </param>
|
|
/// <returns>
|
|
/// An array of disassembled instructions.
|
|
/// </returns>
|
|
/// <exception cref="System.ArgumentNullException">
|
|
/// Thrown if the binary code array is a null reference.
|
|
/// </exception>
|
|
/// <exception cref="System.ObjectDisposedException">
|
|
/// Thrown if the disassembler is disposed.
|
|
/// </exception>
|
|
public TInstruction[] Disassemble(byte[] binaryCode, long startingAddress) {
|
|
// ...
|
|
//
|
|
// Throws an exception if the operation fails.
|
|
var instructions = this.Disassemble(binaryCode, startingAddress, 0);
|
|
return instructions;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Disassemble Binary Code.
|
|
/// </summary>
|
|
/// <param name="binaryCode">
|
|
/// An array of bytes representing the binary code to disassemble.
|
|
/// </param>
|
|
/// <param name="startingAddress">
|
|
/// The address of the first instruction in the binary code array.
|
|
/// </param>
|
|
/// <param name="count">
|
|
/// The maximum number of instructions to disassemble.
|
|
/// </param>
|
|
/// <returns>
|
|
/// An array of disassembled instructions.
|
|
/// </returns>
|
|
/// <exception cref="System.ArgumentNullException">
|
|
/// Thrown if the binary code array is a null reference.
|
|
/// </exception>
|
|
/// <exception cref="System.ObjectDisposedException">
|
|
/// Thrown if the disassembler is disposed.
|
|
/// </exception>
|
|
public TInstruction[] Disassemble(byte[] binaryCode, long startingAddress, int count) {
|
|
// ...
|
|
//
|
|
// Throws an exception if the operation fails.
|
|
var instructionIterator = this.Iterate(binaryCode, startingAddress);
|
|
|
|
// ...
|
|
//
|
|
// We want to emulate the Capstone API by treating a <c>0</c> as an indication that all instructions
|
|
// should be disassembled.
|
|
if (count != 0) {
|
|
// ...
|
|
//
|
|
// If there are less instructions than indicated, all the instructions will be returned.
|
|
instructionIterator = instructionIterator.Skip(0).Take(count);
|
|
}
|
|
|
|
var instructions = instructionIterator.ToArray();
|
|
return instructions;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Dispose Object.
|
|
/// </summary>
|
|
public override void Dispose() {
|
|
// ...
|
|
//
|
|
// This operation is safe, even if it is invoked multiple times and the handle is already disposed.
|
|
this._handle.Dispose();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get an Instruction Group's Name.
|
|
/// </summary>
|
|
/// <param name="instructionGroupId">
|
|
/// An instruction group's unique identifier.
|
|
/// </param>
|
|
/// <returns>
|
|
/// The instruction group's name.
|
|
/// </returns>
|
|
/// <exception cref="System.ArgumentException">
|
|
/// Thrown if the instruction group's unique identifier is invalid.
|
|
/// </exception>
|
|
/// <exception cref="System.ObjectDisposedException">
|
|
/// Thrown if the disassembler is disposed.
|
|
/// </exception>
|
|
/// <exception cref="System.NotSupportedException">
|
|
/// Thrown if Diet Mode is enabled.
|
|
/// </exception>
|
|
public string GetInstructionGroupName(TInstructionGroupId instructionGroupId) {
|
|
this.ThrowIfDisassemblerIsDisposed();
|
|
CapstoneDisassembler.ThrowIfDietModeIsEnabled();
|
|
|
|
// ...
|
|
//
|
|
// This is an ugly operation but it is the only way I am familiar with to convert a <c>System.Enum</c> to
|
|
// a 32-bit integer to pass to the Capstone API. It should be relatively quick since <c>System.Enum</c>
|
|
// implements <c>System.IConvertible</c>.
|
|
var iInstructionGroupId = Convert.ToInt32(instructionGroupId);
|
|
|
|
// ...
|
|
//
|
|
// This operation will return a null reference if 1) the handle is disposed, 2) if diet mode is enabled,
|
|
// or 3) if the register unique identifier is invalid. Unfortunately it does not differentiate between the
|
|
// 3 conditions. However, because we already guarded against conditions 1 and 2, if it does return a null
|
|
// reference, it must be because of condition 3.
|
|
var instructionGroupName = NativeCapstone.GetInstructionGroupName(this._handle, iInstructionGroupId);
|
|
if (instructionGroupName == null) {
|
|
const string detailMessage = "An instruction group unique identifier is invalid.";
|
|
throw new ArgumentException(detailMessage, nameof(instructionGroupId));
|
|
}
|
|
|
|
return instructionGroupName;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get a Register's Name.
|
|
/// </summary>
|
|
/// <param name="registerId">
|
|
/// A register's unique identifier.
|
|
/// </param>
|
|
/// <returns>
|
|
/// The register's name.
|
|
/// </returns>
|
|
/// <exception cref="System.ArgumentException">
|
|
/// Thrown if the register's unique identifier is invalid.
|
|
/// </exception>
|
|
/// <exception cref="System.ObjectDisposedException">
|
|
/// Thrown if the disassembler is disposed.
|
|
/// </exception>
|
|
/// <exception cref="System.NotSupportedException">
|
|
/// Thrown if diet mode is enabled.
|
|
/// </exception>
|
|
public string GetRegisterName(TRegisterId registerId) {
|
|
this.ThrowIfDisassemblerIsDisposed();
|
|
CapstoneDisassembler.ThrowIfDietModeIsEnabled();
|
|
|
|
// ...
|
|
//
|
|
// This is an ugly operation but it is the only way I am familiar with to convert a <c>System.Enum</c> to
|
|
// a 32-bit integer to pass to the Capstone API. It should be relatively quick since <c>System.Enum</c>
|
|
// implements <c>System.IConvertible</c>.
|
|
var iRegisterId = Convert.ToInt32(registerId);
|
|
|
|
// ...
|
|
//
|
|
// This operation will return a null reference if 1) the handle is disposed, 2) if diet mode is enabled,
|
|
// or 3) if the register unique identifier is invalid. Unfortunately it does not differentiate between the
|
|
// 3 conditions. However, because we already guarded against conditions 1 and 2, if it does return a null
|
|
// reference, it must be because of condition 3.
|
|
var registerName = NativeCapstone.GetRegisterName(this._handle, iRegisterId);
|
|
if (registerName == null) {
|
|
const string detailMessage = "A register unique identifier is invalid.";
|
|
throw new ArgumentException(detailMessage, nameof(registerId));
|
|
}
|
|
|
|
return registerName;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Disassemble Binary Code Iteratively.
|
|
/// </summary>
|
|
/// <param name="binaryCode">
|
|
/// An array of bytes representing the binary code to disassemble.
|
|
/// </param>
|
|
/// <returns>
|
|
/// A deferred collection of disassembled instructions.
|
|
/// </returns>
|
|
/// <exception cref="System.ArgumentNullException">
|
|
/// Thrown if the binary code array is a null reference.
|
|
/// </exception>
|
|
/// <exception cref="System.ObjectDisposedException">
|
|
/// Thrown if the disassembler is disposed.
|
|
/// </exception>
|
|
public IEnumerable<TInstruction> Iterate(byte[] binaryCode) {
|
|
// ...
|
|
//
|
|
// Throws an exception if the operation fails.
|
|
return this.Iterate(binaryCode, 0x1000);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Disassemble Binary Code Iteratively.
|
|
/// </summary>
|
|
/// <param name="binaryCode">
|
|
/// An array of bytes representing the binary code to disassemble.
|
|
/// </param>
|
|
/// <param name="startingAddress">
|
|
/// The address of the first instruction in the binary code array.
|
|
/// </param>
|
|
/// <returns>
|
|
/// A deferred collection of disassembled instructions.
|
|
/// </returns>
|
|
/// <exception cref="System.ArgumentNullException">
|
|
/// Thrown if the binary code array is a null reference.
|
|
/// </exception>
|
|
/// <exception cref="System.ObjectDisposedException">
|
|
/// Thrown if the disassembler is disposed.
|
|
/// </exception>
|
|
public IEnumerable<TInstruction> Iterate(byte[] binaryCode, long startingAddress) {
|
|
CapstoneDisassembler.ThrowIfValueIsNullReference(nameof(binaryCode), binaryCode);
|
|
|
|
var binaryCodeOffset = 0;
|
|
|
|
// ...
|
|
//
|
|
// The Capstone API's iterative disassemble function has an interesting challenge when it is invoked with
|
|
// Skip Data Mode enabled. Because it disassembles one instruction at a time, the binary code buffer that
|
|
// it passes to the Skip Data Mode Callback is not the entire binary code buffer passed by the caller, but
|
|
// rather only the slice that contains the identified invalid instruction. This makes it difficult for the
|
|
// caller to perform any analysis in the Skip Data Mode Callback that might depend on inspecting the
|
|
// entire binary code buffer. This isn't necessarily a deal breaker since a caller can work around this in
|
|
// multiple ways.
|
|
//
|
|
// However, we'll do the hard work for the caller here and define the Skip Data Mode Callback as a proxy
|
|
// closure that encloses over the entire binary code buffer and pass it to the actual callback defined
|
|
// by the caller.
|
|
NativeCapstone.SkipDataCallback callback = null;
|
|
if (this.EnableSkipDataMode) {
|
|
// ...
|
|
//
|
|
// Normally, delegates that are created for the purpose of being passed as function pointers to
|
|
// unmanaged code, such as this Skip Data Mode Callback, need to be allocated using a method that
|
|
// prevents them from being garbage collected. A delegate created as a local variable typically would
|
|
// be a problem because it would go out of scope as soon as the function returns and thus be eligible
|
|
// for garbage collection. A process crash is guaranteed if that happens while it is still referenced
|
|
// by unmanaged code.
|
|
//
|
|
// However, because this method is an iterator method, when the compiler compiles it it will actually
|
|
// create a new class for the iterator's state machine and every local variable defined will become a
|
|
// private field defined by this new class, whose lifetime is actually tied to the lifetime of the
|
|
// class. So the problem of garbage collection is actually avoided for the lifetime of the iterator.
|
|
//
|
|
// To make this work though, we MUST define a local variable for the delegate!
|
|
if (this._skipDataCallback != null) {
|
|
callback = OnNativeSkipDataCallback;
|
|
}
|
|
|
|
// ...
|
|
//
|
|
// Throws an exception if the operation fails.
|
|
var optionValue = new NativeSkipDataOptionValue();
|
|
optionValue.Callback = callback;
|
|
optionValue.InstructionMnemonic = this._skipDataInstructionMnemonic;
|
|
optionValue.State = IntPtr.Zero;
|
|
NativeCapstone.SetSkipDataOption(this._handle, ref optionValue);
|
|
}
|
|
|
|
try {
|
|
// ...
|
|
//
|
|
// We allocate memory for one instruction and reuse it for every instruction in the binary code
|
|
// buffer. Throws an exception if the operation fails.
|
|
using (var hInstruction = NativeCapstone.CreateInstruction(this._handle)) {
|
|
while (!(binaryCodeOffset >= binaryCode.Length)) {
|
|
// ...
|
|
//
|
|
// Throws an exception if the operation fails.
|
|
var isDisassembled = NativeCapstone.Iterate(this._handle, binaryCode, ref binaryCodeOffset, ref startingAddress, hInstruction);
|
|
if (!isDisassembled) {
|
|
yield break;
|
|
}
|
|
|
|
var instruction = this.CreateInstruction(hInstruction);
|
|
yield return instruction;
|
|
}
|
|
}
|
|
}
|
|
finally {
|
|
if (callback != null) {
|
|
// ...
|
|
//
|
|
// Throws an exception if the operation fails. If the operation fails here, it could only be
|
|
// because the disassembler is disposed, which will have no side effects if it happens here.
|
|
var optionValue = new NativeSkipDataOptionValue();
|
|
optionValue.Callback = null;
|
|
optionValue.InstructionMnemonic = this._skipDataInstructionMnemonic;
|
|
optionValue.State = IntPtr.Zero;
|
|
NativeCapstone.SetSkipDataOption(this._handle, ref optionValue);
|
|
}
|
|
}
|
|
|
|
// <summary>
|
|
// Native Skip Data Mode Callback.
|
|
// </summary>
|
|
IntPtr OnNativeSkipDataCallback(IntPtr cPBinaryCode, IntPtr cBinaryCodeSize, IntPtr cDataOffset, IntPtr pState) {
|
|
// ...
|
|
//
|
|
// Normally, a closure enclosing over a variable modified from a loop, such as this method, is a
|
|
// problem because the value of the variable is resolved at the time the closure is invoked and not
|
|
// when the variable is captured. This can lead to unexpected behavior if the closure is invoked
|
|
// outside the loop since the value of the captured variable will always be resolved to the last value
|
|
// it was set to inside the loop.
|
|
//
|
|
// However, because this closure will always be invoked from inside a disassemble loop, and never from
|
|
// outside of one, the variable value resolution behavior is exactly what we are looking for. We want
|
|
// the Capstone API to invoke this callback with an updated value for the captured variable every
|
|
// time!
|
|
var cBytesToSkip = this.SkipDataCallback(binaryCode, binaryCodeOffset);
|
|
return new IntPtr(cBytesToSkip);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Reset an Instruction's Mnemonic.
|
|
/// </summary>
|
|
/// <param name="instructionId">
|
|
/// An instruction unique identifier.
|
|
/// </param>
|
|
/// <exception cref="Gee.External.Capstone.CapstoneException">
|
|
/// Thrown if the instruction mnemonic could not be reset.
|
|
/// </exception>
|
|
/// <exception cref="System.ObjectDisposedException">
|
|
/// Thrown if the disassembler is disposed.
|
|
/// </exception>
|
|
public void ResetInstructionMnemonic(TInstructionId instructionId) {
|
|
// ...
|
|
//
|
|
// This is an ugly operation but it is the only way I am familiar with to convert a <c>System.Enum</c> to
|
|
// a 32-bit integer to pass to the Capstone API. It should be relatively quick since <c>System.Enum</c>
|
|
// implements <c>System.IConvertible</c>.
|
|
var iInstructionId = Convert.ToInt32(instructionId);
|
|
|
|
var optionValue = new NativeInstructionMnemonicOptionValue {
|
|
InstructionId = iInstructionId,
|
|
InstructionMnemonic = null
|
|
};
|
|
|
|
// ...
|
|
//
|
|
// Throws an exception if the operation fails.
|
|
NativeCapstone.SetInstructionMnemonicOption(this._handle, ref optionValue);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Set an Instruction's Mnemonic.
|
|
/// </summary>
|
|
/// <param name="instructionId">
|
|
/// An instruction's unique identifier.
|
|
/// </param>
|
|
/// <param name="instructionMnemonic">
|
|
/// A mnemonic to associate with the instruction.
|
|
/// </param>
|
|
/// <exception cref="Gee.External.Capstone.CapstoneException">
|
|
/// Thrown if the instruction mnemonic could not be set.
|
|
/// </exception>
|
|
/// <exception cref="System.ArgumentNullException">
|
|
/// Thrown if the instruction mnemonic is a null reference.
|
|
/// </exception>
|
|
/// <exception cref="System.ObjectDisposedException">
|
|
/// Thrown if the disassembler is disposed.
|
|
/// </exception>
|
|
public void SetInstructionMnemonic(TInstructionId instructionId, string instructionMnemonic) {
|
|
CapstoneDisassembler.ThrowIfValueIsNullReference(nameof(instructionMnemonic), instructionMnemonic);
|
|
|
|
// ...
|
|
//
|
|
// This is an ugly operation but it is the only way I am familiar with to convert a <c>System.Enum</c> to
|
|
// a 32-bit integer to pass to the Capstone API. It should be relatively quick since <c>System.Enum</c>
|
|
// implements <c>System.IConvertible</c>.
|
|
var iInstructionId = Convert.ToInt32(instructionId);
|
|
|
|
var optionValue = new NativeInstructionMnemonicOptionValue {
|
|
InstructionId = iInstructionId,
|
|
InstructionMnemonic = instructionMnemonic
|
|
};
|
|
|
|
// ...
|
|
//
|
|
// Throws an exception if the operation fails.
|
|
NativeCapstone.SetInstructionMnemonicOption(this._handle, ref optionValue);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Throw an Exception if Disassembler is Disposed.
|
|
/// </summary>
|
|
/// <exception cref="System.ObjectDisposedException">
|
|
/// Thrown if the disassembler is disposed.
|
|
/// </exception>
|
|
private void ThrowIfDisassemblerIsDisposed() {
|
|
if (this._handle.IsClosed) {
|
|
const string detailMessage = "A disassembler is disposed.";
|
|
throw new ObjectDisposedException(nameof(CapstoneDisassembler), detailMessage);
|
|
}
|
|
}
|
|
}
|
|
}
|