evoasm 0.0.2.pre7 → 0.1.0.pre2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gdbinit +41 -0
- data/.gitignore +1 -2
- data/.gitmodules +3 -0
- data/.rubocop.yml +8 -0
- data/Gemfile +4 -0
- data/LICENSE.md +660 -0
- data/Makefile +1 -1
- data/README.md +17 -9
- data/Rakefile +39 -107
- data/bin/gdb +1 -1
- data/bin/gdb_loop +4 -0
- data/docs/FindingInstructions.md +17 -0
- data/docs/JIT.md +14 -0
- data/docs/SymbolicRegression.md +102 -0
- data/docs/Visualization.md +29 -0
- data/docs/examples/bit_insts.rb +44 -0
- data/docs/examples/jit.rb +26 -0
- data/docs/examples/loss.gif +0 -0
- data/docs/examples/program.png +0 -0
- data/docs/examples/sym_reg.rb +64 -0
- data/docs/examples/vis.rb +38 -0
- data/evoasm.gemspec +21 -15
- data/ext/evoasm_ext/Rakefile +3 -0
- data/ext/evoasm_ext/compile.rake +35 -0
- data/ext/evoasm_ext/libevoasm/src/evoasm-alloc.c +226 -0
- data/ext/evoasm_ext/libevoasm/src/evoasm-alloc.h +84 -0
- data/ext/evoasm_ext/libevoasm/src/evoasm-arch.c +52 -0
- data/ext/evoasm_ext/libevoasm/src/evoasm-arch.h +101 -0
- data/ext/evoasm_ext/libevoasm/src/evoasm-bitmap.h +158 -0
- data/ext/evoasm_ext/libevoasm/src/evoasm-buf.c +204 -0
- data/ext/evoasm_ext/libevoasm/src/evoasm-buf.h +109 -0
- data/ext/evoasm_ext/libevoasm/src/evoasm-domain.c +124 -0
- data/ext/evoasm_ext/libevoasm/src/evoasm-domain.h +279 -0
- data/ext/evoasm_ext/libevoasm/src/evoasm-error.c +65 -0
- data/ext/evoasm_ext/libevoasm/src/evoasm-error.h +108 -0
- data/ext/evoasm_ext/{evoasm-log.c → libevoasm/src/evoasm-log.c} +36 -18
- data/ext/evoasm_ext/libevoasm/src/evoasm-log.h +93 -0
- data/ext/evoasm_ext/libevoasm/src/evoasm-param.c +22 -0
- data/ext/evoasm_ext/libevoasm/src/evoasm-param.h +33 -0
- data/ext/evoasm_ext/libevoasm/src/evoasm-pop-params.c +192 -0
- data/ext/evoasm_ext/libevoasm/src/evoasm-pop-params.h +60 -0
- data/ext/evoasm_ext/libevoasm/src/evoasm-pop.c +1323 -0
- data/ext/evoasm_ext/libevoasm/src/evoasm-pop.h +107 -0
- data/ext/evoasm_ext/libevoasm/src/evoasm-program-io.c +116 -0
- data/ext/evoasm_ext/libevoasm/src/evoasm-program-io.h +60 -0
- data/ext/evoasm_ext/libevoasm/src/evoasm-program.c +1827 -0
- data/ext/evoasm_ext/libevoasm/src/evoasm-program.h +167 -0
- data/ext/evoasm_ext/libevoasm/src/evoasm-rand.c +65 -0
- data/ext/evoasm_ext/libevoasm/src/evoasm-rand.h +76 -0
- data/ext/evoasm_ext/libevoasm/src/evoasm-signal.c +106 -0
- data/ext/evoasm_ext/libevoasm/src/evoasm-signal.h +58 -0
- data/ext/evoasm_ext/libevoasm/src/evoasm-util.h +112 -0
- data/ext/evoasm_ext/libevoasm/src/evoasm-x64.c +925 -0
- data/ext/evoasm_ext/libevoasm/src/evoasm-x64.h +277 -0
- data/ext/evoasm_ext/libevoasm/src/evoasm.c +28 -0
- data/ext/evoasm_ext/libevoasm/src/evoasm.h +35 -0
- data/ext/evoasm_ext/libevoasm/src/gen/evoasm-x64-enums.h +2077 -0
- data/ext/evoasm_ext/libevoasm/src/gen/evoasm-x64-insts.c +191203 -0
- data/ext/evoasm_ext/libevoasm/src/gen/evoasm-x64-insts.h +1713 -0
- data/ext/evoasm_ext/libevoasm/src/gen/evoasm-x64-misc.c +348 -0
- data/ext/evoasm_ext/libevoasm/src/gen/evoasm-x64-misc.h +93 -0
- data/ext/evoasm_ext/libevoasm/src/gen/evoasm-x64-params.c +51 -0
- data/ext/evoasm_ext/libevoasm/src/gen/evoasm-x64-params.h +509 -0
- data/lib/evoasm.rb +28 -11
- data/lib/evoasm/buffer.rb +105 -0
- data/lib/evoasm/capstone.rb +100 -0
- data/lib/evoasm/domain.rb +116 -0
- data/lib/evoasm/error.rb +37 -16
- data/lib/evoasm/exception_error.rb +19 -0
- data/lib/evoasm/ffi_ext.rb +53 -0
- data/lib/evoasm/libevoasm.rb +286 -0
- data/lib/evoasm/libevoasm/x64_enums.rb +1967 -0
- data/lib/evoasm/parameter.rb +20 -0
- data/lib/evoasm/population.rb +145 -0
- data/lib/evoasm/population/parameters.rb +227 -0
- data/lib/evoasm/population/plotter.rb +89 -0
- data/lib/evoasm/prng.rb +64 -0
- data/lib/evoasm/program.rb +195 -12
- data/lib/evoasm/program/io.rb +144 -0
- data/lib/evoasm/test.rb +8 -0
- data/lib/evoasm/version.rb +1 -1
- data/lib/evoasm/x64.rb +115 -0
- data/lib/evoasm/x64/cpu_state.rb +95 -0
- data/lib/evoasm/x64/instruction.rb +109 -0
- data/lib/evoasm/x64/operand.rb +156 -0
- data/lib/evoasm/x64/parameters.rb +211 -0
- data/test/helpers/population_helper.rb +128 -0
- data/test/helpers/test_helper.rb +1 -0
- data/test/helpers/x64_helper.rb +24 -0
- data/test/integration/bitwise_reverse_test.rb +41 -0
- data/test/integration/gcd_test.rb +52 -0
- data/test/integration/popcnt_test.rb +46 -0
- data/test/integration/sym_reg_test.rb +68 -0
- data/test/unit/evoasm/buffer_test.rb +48 -0
- data/test/unit/evoasm/capstone_test.rb +18 -0
- data/test/unit/evoasm/domain_test.rb +55 -0
- data/test/unit/evoasm/population/parameters_test.rb +106 -0
- data/test/unit/evoasm/population_test.rb +96 -0
- data/test/unit/evoasm/prng_test.rb +47 -0
- data/test/unit/evoasm/x64/cpu_state_test.rb +73 -0
- data/test/unit/evoasm/x64/encoding_test.rb +320 -0
- data/test/unit/evoasm/x64/instruction_access_test.rb +177 -0
- data/test/unit/evoasm/x64/instruction_encoding_test.rb +780 -0
- data/test/unit/evoasm/x64/instruction_test.rb +62 -0
- data/test/unit/evoasm/x64/parameters_test.rb +65 -0
- data/test/unit/evoasm/x64_test.rb +52 -0
- metadata +195 -89
- data/Gemfile.rake +0 -8
- data/Gemfile.rake.lock +0 -51
- data/LICENSE.txt +0 -373
- data/data/tables/README.md +0 -19
- data/data/tables/x64.csv +0 -1684
- data/data/templates/evoasm-x64.c.erb +0 -319
- data/data/templates/evoasm-x64.h.erb +0 -126
- data/examples/abs.yml +0 -20
- data/examples/popcnt.yml +0 -17
- data/examples/sym_reg.yml +0 -26
- data/exe/evoasm-search +0 -13
- data/ext/evoasm_ext/evoasm-alloc.c +0 -145
- data/ext/evoasm_ext/evoasm-alloc.h +0 -59
- data/ext/evoasm_ext/evoasm-arch.c +0 -44
- data/ext/evoasm_ext/evoasm-arch.h +0 -161
- data/ext/evoasm_ext/evoasm-bitmap.h +0 -114
- data/ext/evoasm_ext/evoasm-buf.c +0 -130
- data/ext/evoasm_ext/evoasm-buf.h +0 -47
- data/ext/evoasm_ext/evoasm-error.c +0 -31
- data/ext/evoasm_ext/evoasm-error.h +0 -75
- data/ext/evoasm_ext/evoasm-free-list.c.tmpl +0 -121
- data/ext/evoasm_ext/evoasm-free-list.h.tmpl +0 -86
- data/ext/evoasm_ext/evoasm-log.h +0 -69
- data/ext/evoasm_ext/evoasm-misc.c +0 -23
- data/ext/evoasm_ext/evoasm-misc.h +0 -282
- data/ext/evoasm_ext/evoasm-param.h +0 -37
- data/ext/evoasm_ext/evoasm-search.c +0 -2145
- data/ext/evoasm_ext/evoasm-search.h +0 -214
- data/ext/evoasm_ext/evoasm-util.h +0 -40
- data/ext/evoasm_ext/evoasm-x64.c +0 -275624
- data/ext/evoasm_ext/evoasm-x64.h +0 -5436
- data/ext/evoasm_ext/evoasm.c +0 -7
- data/ext/evoasm_ext/evoasm.h +0 -23
- data/ext/evoasm_ext/evoasm_ext.c +0 -1757
- data/ext/evoasm_ext/extconf.rb +0 -31
- data/lib/evoasm/cli.rb +0 -6
- data/lib/evoasm/cli/search.rb +0 -127
- data/lib/evoasm/core_ext.rb +0 -1
- data/lib/evoasm/core_ext/array.rb +0 -9
- data/lib/evoasm/core_ext/integer.rb +0 -10
- data/lib/evoasm/core_ext/kwstruct.rb +0 -13
- data/lib/evoasm/core_ext/range.rb +0 -5
- data/lib/evoasm/examples.rb +0 -27
- data/lib/evoasm/gen.rb +0 -8
- data/lib/evoasm/gen/enum.rb +0 -169
- data/lib/evoasm/gen/name_util.rb +0 -80
- data/lib/evoasm/gen/state.rb +0 -176
- data/lib/evoasm/gen/state_dsl.rb +0 -152
- data/lib/evoasm/gen/strio.rb +0 -27
- data/lib/evoasm/gen/translator.rb +0 -1102
- data/lib/evoasm/gen/version.rb +0 -5
- data/lib/evoasm/gen/x64.rb +0 -237
- data/lib/evoasm/gen/x64/funcs.rb +0 -495
- data/lib/evoasm/gen/x64/inst.rb +0 -781
- data/lib/evoasm/search.rb +0 -40
- data/lib/evoasm/tasks/gen_task.rb +0 -86
- data/lib/evoasm/tasks/template_task.rb +0 -52
- data/test/test_helper.rb +0 -1
- data/test/x64/test_helper.rb +0 -19
- data/test/x64/x64_test.rb +0 -87
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
require 'evoasm/x64'
|
|
2
|
+
|
|
3
|
+
module Evoasm
|
|
4
|
+
module X64
|
|
5
|
+
# Represents the CPU state (i.e. a snapshot of all registers)
|
|
6
|
+
# at a specific moment in time.
|
|
7
|
+
class CPUState < FFI::AutoPointer
|
|
8
|
+
|
|
9
|
+
# @!visibility private
|
|
10
|
+
def self.release(ptr)
|
|
11
|
+
Libevoasm.x64_cpu_state_destroy(ptr)
|
|
12
|
+
Libevoasm.x64_cpu_state_free(ptr)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# @param flags [Array<Symbol>]
|
|
16
|
+
def initialize(flags = [:rflags])
|
|
17
|
+
ptr = Libevoasm.x64_cpu_state_alloc
|
|
18
|
+
Libevoasm.x64_cpu_state_init ptr, Libevoasm.enum_type(:x64_cpu_state_flags).flags(flags, shift: false)
|
|
19
|
+
super(ptr)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Sets the value of a register
|
|
23
|
+
# @param register [Symbol] register to set
|
|
24
|
+
# @param data [Array<Integer>, Integer] value as a single 64-bit integer or an array of multiple
|
|
25
|
+
# 64-bit integers (e.g. for vector registers)
|
|
26
|
+
# @return [void]
|
|
27
|
+
def []=(register, data)
|
|
28
|
+
data = Array(data)
|
|
29
|
+
ptr = FFI::MemoryPointer.new :uint64, data.size
|
|
30
|
+
ptr.write_array_of_uint64 data
|
|
31
|
+
Libevoasm.x64_cpu_state_set self, register, ptr, data.size
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Obtain the value of a register
|
|
35
|
+
# @param register [Symbol] the register
|
|
36
|
+
# @param word [Symbol] an optional word to mask the value (e.g. to obtain a subregister value)
|
|
37
|
+
# @return [Array<Integer>] the register's value as an array of 64-bit integers
|
|
38
|
+
def [](register, word = :none)
|
|
39
|
+
data_ptr = FFI::MemoryPointer.new :uint64, 16
|
|
40
|
+
data_len = Libevoasm.x64_cpu_state_get self, register, word, data_ptr, 16
|
|
41
|
+
data_ptr.read_array_of_uint64 data_len
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# Clone this CPU state object
|
|
45
|
+
# @return [CPUState] the cloned object
|
|
46
|
+
def clone
|
|
47
|
+
cloned_cpu_state = self.class.new
|
|
48
|
+
Libevoasm.x64_cpu_state_clone self, cloned_cpu_state
|
|
49
|
+
|
|
50
|
+
cloned_cpu_state
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# @!visibility private
|
|
54
|
+
def xor(other)
|
|
55
|
+
xored = self.class.new
|
|
56
|
+
Libevoasm.x64_cpu_state_xor self, other, xored
|
|
57
|
+
xored
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# Converts this object into a hash
|
|
61
|
+
# @return [Hash] the hash
|
|
62
|
+
def to_h
|
|
63
|
+
X64.registers.each_with_object({}) do |register, hash|
|
|
64
|
+
hash[register] = self[register]
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def get_rflags_flag(flag)
|
|
69
|
+
Libevoasm.x64_cpu_state_get_rflags_flag self, flag
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# Emits machine code to store (save) the current CPU state
|
|
73
|
+
# into this object
|
|
74
|
+
# @param buffer [Buffer] the buffer to emit to
|
|
75
|
+
# @return [void]
|
|
76
|
+
# @raise [Error] if an error occurres
|
|
77
|
+
def emit_store(buffer)
|
|
78
|
+
unless Libevoasm.x64_cpu_state_emit_store self, buffer
|
|
79
|
+
raise Error.last
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# Emits machine code to load (set) the current CPU state to
|
|
84
|
+
# the state of this object
|
|
85
|
+
# @param buffer [Buffer] the buffer to emit to
|
|
86
|
+
# @return [void]
|
|
87
|
+
# @raise [Error] if an error occurres
|
|
88
|
+
def emit_load(buffer)
|
|
89
|
+
unless Libevoasm.x64_cpu_state_emit_load self, buffer
|
|
90
|
+
raise Error.last
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
require 'evoasm/parameter'
|
|
2
|
+
|
|
3
|
+
module Evoasm
|
|
4
|
+
module X64
|
|
5
|
+
# Represents an x86-64 instruction
|
|
6
|
+
class Instruction < FFI::Pointer
|
|
7
|
+
class Parameter < Evoasm::Parameter
|
|
8
|
+
# Returns the parameter's name
|
|
9
|
+
# @return [Symbol] the parameter name
|
|
10
|
+
def name
|
|
11
|
+
Libevoasm.enum_type(:x64_param_id).find id
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# @return [Symbol] the instruction's name
|
|
16
|
+
attr_reader :name
|
|
17
|
+
|
|
18
|
+
# @!visibility private
|
|
19
|
+
def initialize(ptr, name)
|
|
20
|
+
super(ptr)
|
|
21
|
+
@name = name
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# Gives a list of instruction mnemonics
|
|
25
|
+
# @return [Array<String>] mnemonics
|
|
26
|
+
def mnemonics
|
|
27
|
+
Libevoasm.x64_inst_get_mnem(self).split('/')
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Gives the preferred instruction mnemonic
|
|
31
|
+
# @return [String] the mnemonics
|
|
32
|
+
# @see #mnemonics
|
|
33
|
+
def mnemonic
|
|
34
|
+
mnemonics.first
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Gives the operand at the specified index
|
|
38
|
+
# @return [Operand] the operand
|
|
39
|
+
def operand(index)
|
|
40
|
+
Operand.new Libevoasm.x64_inst_get_operand(self, index), self
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# Gives the instruction's operands
|
|
44
|
+
# @return [Array<Operand>] the operands
|
|
45
|
+
def operands
|
|
46
|
+
n_operands = Libevoasm.x64_inst_get_n_operands self
|
|
47
|
+
Array.new(n_operands) do |index|
|
|
48
|
+
operand index
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# Gives this instruction's parameters
|
|
53
|
+
# @return [Array<Instruction::Parameter>] the parameters
|
|
54
|
+
def parameters
|
|
55
|
+
n_params = Libevoasm.x64_inst_get_n_params self
|
|
56
|
+
Array.new(n_params) do |param_index|
|
|
57
|
+
Parameter.new Libevoasm.x64_inst_get_param(self, param_index)
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# Returns whether this instruction is encodable with the basic encoder
|
|
62
|
+
# @return [Bool]
|
|
63
|
+
def basic?
|
|
64
|
+
Libevoasm.x64_inst_is_basic(self)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# Encodes the instruciton with the given parameters
|
|
68
|
+
# @param parameters [X64::Parameters] parameters
|
|
69
|
+
# @param buffer [Buffer] the buffer to emit to
|
|
70
|
+
# @param basic [Bool] whether the basic encoder should be used
|
|
71
|
+
# @return [void]
|
|
72
|
+
def encode(parameters, buffer = nil, basic: false)
|
|
73
|
+
if basic && !basic?
|
|
74
|
+
raise ArgumentError, 'instruction does not support basic mode'
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
buf_ref = Libevoasm.buf_ref_alloc
|
|
78
|
+
|
|
79
|
+
if buffer
|
|
80
|
+
Libevoasm.buf_to_buf_ref buffer, buf_ref
|
|
81
|
+
else
|
|
82
|
+
data = FFI::MemoryPointer.new :uint8, 32
|
|
83
|
+
len_ptr = FFI::MemoryPointer.new :size_t, 1
|
|
84
|
+
Libevoasm.buf_ref_init buf_ref, data, len_ptr
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
parameters = Parameters.for(parameters, basic: basic)
|
|
88
|
+
|
|
89
|
+
success =
|
|
90
|
+
if basic
|
|
91
|
+
Libevoasm.x64_inst_enc_basic self, parameters, buf_ref
|
|
92
|
+
else
|
|
93
|
+
Libevoasm.x64_inst_enc self, parameters, buf_ref
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
Libevoasm.buf_ref_free buf_ref
|
|
97
|
+
|
|
98
|
+
if success
|
|
99
|
+
unless buffer
|
|
100
|
+
len = len_ptr.read_size_t
|
|
101
|
+
data.read_string len
|
|
102
|
+
end
|
|
103
|
+
else
|
|
104
|
+
raise Error.last
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
end
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
module Evoasm
|
|
2
|
+
module X64
|
|
3
|
+
# Represents a formal instruction operand
|
|
4
|
+
class Operand < FFI::Pointer
|
|
5
|
+
|
|
6
|
+
# @return [X64::Instruction] the instruction this operand belongs to
|
|
7
|
+
attr_reader :instruction
|
|
8
|
+
|
|
9
|
+
# @!visibility private
|
|
10
|
+
def initialize(ptr, instruction)
|
|
11
|
+
super(ptr)
|
|
12
|
+
@instruction = instruction
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# Gives the parameter affecting this operand
|
|
16
|
+
# @return [X64::Parameter] the parameter
|
|
17
|
+
def parameter
|
|
18
|
+
@instruction.parameters[Libevoasm.x64_operand_get_param_idx self]
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# Returns whether this operand is read
|
|
22
|
+
def read?
|
|
23
|
+
Libevoasm.x64_operand_is_read self
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Returns whether this operand is written
|
|
27
|
+
def written?
|
|
28
|
+
Libevoasm.x64_operand_is_written self
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# Returns whether this operand is possibliy written (e.g. in a conditional move instruction)
|
|
32
|
+
def maybe_written?
|
|
33
|
+
Libevoasm.x64_operand_is_maybe_written self
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# Returns whether this operand is part of the instruction mnemonic
|
|
37
|
+
def mnemonic?
|
|
38
|
+
Libevoasm.x64_operand_is_mnem self
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Returns whether this operand is implicit
|
|
42
|
+
def implicit?
|
|
43
|
+
Libevoasm.x64_operand_is_implicit self
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Returns whether this operand is explicit
|
|
47
|
+
def explicit?
|
|
48
|
+
!implicit?
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# Returns the operand type
|
|
52
|
+
# @return [:rm, :imm, :reg] the operand type
|
|
53
|
+
def type
|
|
54
|
+
Libevoasm.x64_operand_get_type self
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# Returns the operand's register (e.g. if implicit) if available
|
|
58
|
+
# @return [Symbol, nil] the operand's register or nil if there is none
|
|
59
|
+
def register
|
|
60
|
+
if type == :rm || type == :reg
|
|
61
|
+
reg_id = Libevoasm.x64_operand_get_reg_id self
|
|
62
|
+
reg_id == :none ? nil : reg_id
|
|
63
|
+
else
|
|
64
|
+
nil
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
INVALID_IMMEDIATE = -1
|
|
69
|
+
|
|
70
|
+
# Returns the operand's immediate (e.g. if implicit) if available
|
|
71
|
+
# @return [Integer, nil] the operand's immediate or nil if there is none
|
|
72
|
+
def immediate
|
|
73
|
+
if type == :imm
|
|
74
|
+
imm = Libevoasm.x64_operand_get_imm self
|
|
75
|
+
imm == INVALID_IMMEDIATE ? nil : imm
|
|
76
|
+
else
|
|
77
|
+
nil
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# Returns the operand's register type (e.g. if implicit) if available
|
|
82
|
+
# @return [Symbol, nil] the operand's register type or nil if there is none
|
|
83
|
+
def register_type
|
|
84
|
+
reg_type = Libevoasm.x64_operand_get_reg_type self
|
|
85
|
+
reg_type == :none ? nil : reg_type
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
# Gives the operand's size
|
|
89
|
+
# @return [Integer] the operand size in bits
|
|
90
|
+
def size
|
|
91
|
+
convert_size Libevoasm.x64_operand_get_size(self)
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
# Gives the operand's word
|
|
95
|
+
# @return [Symbol] the operand word
|
|
96
|
+
def word
|
|
97
|
+
Libevoasm.x64_operand_get_word(self)
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
# Returns the operand's register size
|
|
101
|
+
# @return [Integer, nil] the operand's registert size or nil if this operand does not hold a register
|
|
102
|
+
def register_size
|
|
103
|
+
if type == :rm || type == :reg
|
|
104
|
+
convert_size Libevoasm.x64_operand_get_reg_size(self)
|
|
105
|
+
else
|
|
106
|
+
nil
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
# Returns the operand's index register size (e.g. in VSIB instructions)
|
|
111
|
+
# @return [Integer, nil] the operand's index registert size or nil if this operand does not hold a index register
|
|
112
|
+
def index_register_size
|
|
113
|
+
if type == :vsib
|
|
114
|
+
convert_size Libevoasm.x64_operand_get_index_reg_size(self)
|
|
115
|
+
else
|
|
116
|
+
nil
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
# Returns the operand's memory size (e.g. in R/M instructions)
|
|
121
|
+
# @return [Integer, nil] the operand's memory size or nil if this operand is not a memory operand
|
|
122
|
+
def memory_size
|
|
123
|
+
if type == :rm || type == :mem || type == :vsib
|
|
124
|
+
convert_size Libevoasm.x64_operand_get_mem_size(self)
|
|
125
|
+
else
|
|
126
|
+
nil
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
private
|
|
131
|
+
|
|
132
|
+
def convert_size(size)
|
|
133
|
+
case size
|
|
134
|
+
when :'1' then
|
|
135
|
+
1
|
|
136
|
+
when :'8' then
|
|
137
|
+
8
|
|
138
|
+
when :'16' then
|
|
139
|
+
16
|
|
140
|
+
when :'32' then
|
|
141
|
+
32
|
|
142
|
+
when :'64' then
|
|
143
|
+
64
|
|
144
|
+
when :'128' then
|
|
145
|
+
128
|
|
146
|
+
when :'256' then
|
|
147
|
+
256
|
|
148
|
+
when :'512' then
|
|
149
|
+
512
|
|
150
|
+
else
|
|
151
|
+
nil
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
end
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
module Evoasm
|
|
2
|
+
module X64
|
|
3
|
+
# Represents x86-64 instruction parameters.
|
|
4
|
+
class Parameters < FFI::AutoPointer
|
|
5
|
+
|
|
6
|
+
# @!visibility private
|
|
7
|
+
def self.release(ptr)
|
|
8
|
+
if ptr.basic?
|
|
9
|
+
Libevoasm.x64_basic_params_free ptr
|
|
10
|
+
else
|
|
11
|
+
Libevoasm.x64_params_free ptr
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# @!visibility private
|
|
16
|
+
def self.for(parameters, basic: false)
|
|
17
|
+
case parameters
|
|
18
|
+
when self
|
|
19
|
+
if basic && !parameters.basic?
|
|
20
|
+
raise ArgumentError, 'cannot convert non-basic parameters '\
|
|
21
|
+
'to basic parameters'
|
|
22
|
+
end
|
|
23
|
+
parameters
|
|
24
|
+
when Hash
|
|
25
|
+
new parameters, basic: basic
|
|
26
|
+
else
|
|
27
|
+
raise ArgumentError, "cannot convert #{parameters.class} into parameter"
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def inspect
|
|
32
|
+
fields = @param_id_enum_type.symbols[0..-2].map { |s| "#{s}:#{self[s]}" }.join(' ')
|
|
33
|
+
"#<#{self.class.inspect} #{fields}>"
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# @param hash [Hash] a
|
|
37
|
+
# @param basic [Bool] whether to use the basic encoder
|
|
38
|
+
def initialize(hash = {}, basic: false)
|
|
39
|
+
if basic
|
|
40
|
+
ptr = Libevoasm.x64_basic_params_alloc
|
|
41
|
+
Libevoasm.x64_basic_params_init ptr
|
|
42
|
+
else
|
|
43
|
+
ptr = Libevoasm.x64_params_alloc
|
|
44
|
+
Libevoasm.x64_params_init ptr
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
@param_id_enum_type =
|
|
48
|
+
if basic
|
|
49
|
+
Libevoasm.enum_type(:x64_basic_param_id)
|
|
50
|
+
else
|
|
51
|
+
Libevoasm.enum_type(:x64_param_id)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
@basic = basic
|
|
55
|
+
@disp_size_enum_type = Libevoasm.enum_type :x64_disp_size
|
|
56
|
+
@addr_size_enum_type = Libevoasm.enum_type :x64_addr_size
|
|
57
|
+
@scale_enum_type = Libevoasm.enum_type :x64_scale
|
|
58
|
+
@reg_id_enum_type = Libevoasm.enum_type :x64_reg_id
|
|
59
|
+
|
|
60
|
+
@type_map_enum_types = {
|
|
61
|
+
scale: @scale_enum_type,
|
|
62
|
+
addr_size: @addr_size_enum_type,
|
|
63
|
+
reg: @reg_id_enum_type
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
@type_map = {
|
|
67
|
+
scale: {
|
|
68
|
+
1 => :scale1,
|
|
69
|
+
2 => :scale2,
|
|
70
|
+
4 => :scale4,
|
|
71
|
+
8 => :scale8
|
|
72
|
+
},
|
|
73
|
+
|
|
74
|
+
addr_size: {
|
|
75
|
+
32 => :addr_size32,
|
|
76
|
+
64 => :addr_size64,
|
|
77
|
+
},
|
|
78
|
+
|
|
79
|
+
bool: {
|
|
80
|
+
true => 1,
|
|
81
|
+
false => 0
|
|
82
|
+
},
|
|
83
|
+
|
|
84
|
+
uint1: proc { |v| check_uint_range v, 1 },
|
|
85
|
+
int3: proc { |v| check_int_range v, 3 },
|
|
86
|
+
int4: proc { |v| check_int_range v, 4 },
|
|
87
|
+
int8: proc { |v| check_int_range v, 8 },
|
|
88
|
+
int32: proc { |v| check_int_range v, 32 },
|
|
89
|
+
int64: proc { |v| check_int_range v, 64 },
|
|
90
|
+
reg: proc { |v| @reg_id_enum_type[v] }
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
@inv_type_map = @type_map.map do |k, v|
|
|
94
|
+
if v.is_a? Hash
|
|
95
|
+
[k, v.invert]
|
|
96
|
+
else
|
|
97
|
+
[k, v]
|
|
98
|
+
end
|
|
99
|
+
end.to_h
|
|
100
|
+
|
|
101
|
+
@inv_type_map[:reg] = proc { |v| v }
|
|
102
|
+
|
|
103
|
+
super(ptr)
|
|
104
|
+
|
|
105
|
+
hash.each do |k, v|
|
|
106
|
+
self[k] = v
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
# Returns whether this parameters are for basic encodning
|
|
111
|
+
# @return [Bool]
|
|
112
|
+
def basic?
|
|
113
|
+
@basic
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
# @param parameter_name [Symbol] the parameter's name
|
|
117
|
+
# @return [Symbol, Integer] the parameter value
|
|
118
|
+
def [](parameter_name)
|
|
119
|
+
ffi_value =
|
|
120
|
+
if basic?
|
|
121
|
+
Libevoasm.x64_basic_params_get self, parameter_name_to_id(parameter_name)
|
|
122
|
+
else
|
|
123
|
+
Libevoasm.x64_params_get self, parameter_name_to_id(parameter_name)
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
ffi_value_to_value parameter_name, ffi_value
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
# Checks the existence of a parameter
|
|
130
|
+
# @param parameter_name [Symbol] the parameter name
|
|
131
|
+
# @return [Bool] whether the parameter exists or nor
|
|
132
|
+
def parameter?(parameter_name)
|
|
133
|
+
!@param_id_enum_type[parameter_name].nil?
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
# Set a parameter
|
|
137
|
+
# @param parameter_name [Symbol] the parameter's name
|
|
138
|
+
# @param value [Symbol, Integer] the parameter's value
|
|
139
|
+
# @return [void]
|
|
140
|
+
def []=(parameter_name, value)
|
|
141
|
+
ffi_value = value_to_ffi_value parameter_name, value
|
|
142
|
+
parameter_id = parameter_name_to_id(parameter_name)
|
|
143
|
+
|
|
144
|
+
if basic?
|
|
145
|
+
Libevoasm.x64_basic_params_set self, parameter_id, ffi_value
|
|
146
|
+
else
|
|
147
|
+
Libevoasm.x64_params_set self, parameter_id, ffi_value
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
private
|
|
152
|
+
|
|
153
|
+
def check_uint_range(value, bitsize)
|
|
154
|
+
min = 0
|
|
155
|
+
max = 2**bitsize - 1
|
|
156
|
+
raise ArgumentError, "#{value} exceeds value range #{min}..#{max}" if value < min || value > max
|
|
157
|
+
|
|
158
|
+
value
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
def check_int_range(value, bitsize)
|
|
162
|
+
min = -2**bitsize
|
|
163
|
+
max = -min - 1
|
|
164
|
+
raise ArgumentError, "#{value} exceeds value range #{min}..#{max}" if value < min || value > max
|
|
165
|
+
|
|
166
|
+
value
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
def parameter_type(parameter_name)
|
|
170
|
+
if basic?
|
|
171
|
+
Libevoasm.x64_basic_params_get_type(parameter_name)
|
|
172
|
+
else
|
|
173
|
+
Libevoasm.x64_params_get_type(parameter_name)
|
|
174
|
+
end
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
def value_to_ffi_value(parameter_name, parameter_value)
|
|
178
|
+
raise ArgumentError, 'value cannot be nil' if parameter_value.nil?
|
|
179
|
+
|
|
180
|
+
parameter_type = parameter_type parameter_name
|
|
181
|
+
ffi_value = @type_map[parameter_type][parameter_value]
|
|
182
|
+
|
|
183
|
+
if ffi_value.nil?
|
|
184
|
+
raise ArgumentError, "value #{parameter_value} is invalid for #{parameter_name}"
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
ffi_value
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
def ffi_value_to_value(parameter_name, ffi_value)
|
|
191
|
+
parameter_type = parameter_type parameter_name
|
|
192
|
+
|
|
193
|
+
if @type_map_enum_types.key? parameter_type
|
|
194
|
+
ffi_value = @type_map_enum_types[parameter_type][ffi_value]
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
@inv_type_map[parameter_type][ffi_value]
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
def parameter_name_to_id(symbol)
|
|
201
|
+
id = @param_id_enum_type[symbol]
|
|
202
|
+
|
|
203
|
+
if id.nil?
|
|
204
|
+
raise ArgumentError, "unknown parameter '#{symbol}'"
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
id
|
|
208
|
+
end
|
|
209
|
+
end
|
|
210
|
+
end
|
|
211
|
+
end
|