evoasm 0.0.2.pre7 → 0.1.0.pre2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|