asmrepl 1.0.0
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 +7 -0
- data/CODE_OF_CONDUCT.md +78 -0
- data/Gemfile +3 -0
- data/LICENSE +201 -0
- data/README.md +83 -0
- data/Rakefile +23 -0
- data/asmrepl.gemspec +24 -0
- data/bin/asmrepl +5 -0
- data/lib/asmrepl/assembler.rb +49 -0
- data/lib/asmrepl/linux.rb +186 -0
- data/lib/asmrepl/macos.rb +205 -0
- data/lib/asmrepl/parser.rb +101 -0
- data/lib/asmrepl/parser.tab.rb +297 -0
- data/lib/asmrepl/parser.y +44 -0
- data/lib/asmrepl/repl.rb +105 -0
- data/lib/asmrepl/version.rb +3 -0
- data/lib/asmrepl.rb +3 -0
- data/test/asmrepl_test.rb +116 -0
- data/test/helper.rb +20 -0
- metadata +120 -0
@@ -0,0 +1,205 @@
|
|
1
|
+
require "fisk/helpers"
|
2
|
+
|
3
|
+
module ASMREPL
|
4
|
+
module MacOS
|
5
|
+
include Fiddle
|
6
|
+
|
7
|
+
def self.make_function name, args, ret
|
8
|
+
ptr = Handle::DEFAULT[name]
|
9
|
+
func = Function.new ptr, args, ret, name: name
|
10
|
+
define_singleton_method name, &func.to_proc
|
11
|
+
end
|
12
|
+
|
13
|
+
# from sys/mman.h on macOS
|
14
|
+
PROT_READ = 0x01
|
15
|
+
PROT_WRITE = 0x02
|
16
|
+
PROT_EXEC = 0x04
|
17
|
+
MAP_PRIVATE = 0x0002
|
18
|
+
MAP_SHARED = 0x0001
|
19
|
+
MAP_ANON = 0x1000
|
20
|
+
|
21
|
+
make_function "ptrace", [TYPE_INT, TYPE_INT, TYPE_VOIDP, TYPE_INT], TYPE_INT
|
22
|
+
make_function "memset", [TYPE_VOIDP, TYPE_INT, TYPE_SIZE_T], TYPE_VOID
|
23
|
+
make_function "strerror", [TYPE_INT], TYPE_CONST_STRING
|
24
|
+
make_function "mach_task_self", [], TYPE_VOIDP
|
25
|
+
make_function "task_threads", [TYPE_VOIDP, TYPE_VOIDP, TYPE_VOIDP], TYPE_VOIDP
|
26
|
+
make_function "task_for_pid", [TYPE_VOIDP, TYPE_INT, TYPE_VOIDP], TYPE_INT
|
27
|
+
make_function "task_threads", [TYPE_VOIDP, TYPE_VOIDP, TYPE_VOIDP], TYPE_INT
|
28
|
+
make_function "thread_get_state", [TYPE_VOIDP, TYPE_INT, TYPE_VOIDP, TYPE_VOIDP], TYPE_INT
|
29
|
+
make_function "mmap", [TYPE_VOIDP,
|
30
|
+
TYPE_SIZE_T,
|
31
|
+
TYPE_INT,
|
32
|
+
TYPE_INT,
|
33
|
+
TYPE_INT,
|
34
|
+
TYPE_INT], TYPE_VOIDP
|
35
|
+
|
36
|
+
def self.mmap_jit size
|
37
|
+
ptr = mmap 0, size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_SHARED | MAP_ANON, -1, 0
|
38
|
+
ptr.size = size
|
39
|
+
ptr
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.jitbuffer size
|
43
|
+
Fisk::Helpers::JITBuffer.new mmap_jit(size), size
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.traceme
|
47
|
+
raise unless ptrace(PT_TRACE_ME, 0, 0, 0).zero?
|
48
|
+
end
|
49
|
+
|
50
|
+
class ThreadState
|
51
|
+
fields = (<<-eostruct).scan(/uint64_t ([^;]*);/).flatten
|
52
|
+
struct x86_thread_state64_t {
|
53
|
+
uint64_t rax;
|
54
|
+
uint64_t rbx;
|
55
|
+
uint64_t rcx;
|
56
|
+
uint64_t rdx;
|
57
|
+
uint64_t rdi;
|
58
|
+
uint64_t rsi;
|
59
|
+
uint64_t rbp;
|
60
|
+
uint64_t rsp;
|
61
|
+
uint64_t r8;
|
62
|
+
uint64_t r9;
|
63
|
+
uint64_t r10;
|
64
|
+
uint64_t r11;
|
65
|
+
uint64_t r12;
|
66
|
+
uint64_t r13;
|
67
|
+
uint64_t r14;
|
68
|
+
uint64_t r15;
|
69
|
+
uint64_t rip;
|
70
|
+
uint64_t rflags;
|
71
|
+
uint64_t cs;
|
72
|
+
uint64_t fs;
|
73
|
+
uint64_t gs;
|
74
|
+
}
|
75
|
+
eostruct
|
76
|
+
fields.each_with_index do |field, i|
|
77
|
+
define_method(field) do
|
78
|
+
to_ptr[Fiddle::SIZEOF_INT64_T * i, Fiddle::SIZEOF_INT64_T].unpack1("l!")
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
define_singleton_method(:sizeof) do
|
83
|
+
fields.length * Fiddle::SIZEOF_INT64_T
|
84
|
+
end
|
85
|
+
|
86
|
+
def [] name
|
87
|
+
idx = fields.index(name)
|
88
|
+
return unless idx
|
89
|
+
to_ptr[Fiddle::SIZEOF_INT64_T * idx, Fiddle::SIZEOF_INT64_T].unpack1("l!")
|
90
|
+
end
|
91
|
+
|
92
|
+
def self.malloc
|
93
|
+
new Fiddle::Pointer.malloc sizeof
|
94
|
+
end
|
95
|
+
|
96
|
+
attr_reader :to_ptr
|
97
|
+
|
98
|
+
def initialize buffer
|
99
|
+
@to_ptr = buffer
|
100
|
+
end
|
101
|
+
|
102
|
+
define_method(:fields) do
|
103
|
+
fields
|
104
|
+
end
|
105
|
+
|
106
|
+
def to_s
|
107
|
+
buf = ""
|
108
|
+
fields.first(8).zip(fields.drop(8).first(8)).each do |l, r|
|
109
|
+
buf << "#{l.ljust(3)} #{sprintf("%#018x", send(l))}"
|
110
|
+
buf << " "
|
111
|
+
buf << "#{r.ljust(3)} #{sprintf("%#018x", send(r))}\n"
|
112
|
+
end
|
113
|
+
|
114
|
+
buf << "\n"
|
115
|
+
|
116
|
+
fields.drop(16).each do |reg|
|
117
|
+
buf << "#{reg.ljust(6)} #{sprintf("%#018x", send(reg))}\n"
|
118
|
+
end
|
119
|
+
buf
|
120
|
+
end
|
121
|
+
|
122
|
+
FLAGS = [
|
123
|
+
['CF', 'Carry Flag'],
|
124
|
+
[nil, 'Reserved'],
|
125
|
+
['PF', 'Parity Flag'],
|
126
|
+
[nil, 'Reserved'],
|
127
|
+
['AF', 'Adjust Flag'],
|
128
|
+
[nil, 'Reserved'],
|
129
|
+
['ZF', 'Zero Flag'],
|
130
|
+
['SF', 'Sign Flag'],
|
131
|
+
['TF', 'Trap Flag'],
|
132
|
+
['IF', 'Interrupt Enable Flag'],
|
133
|
+
['DF', 'Direction Flag'],
|
134
|
+
['OF', 'Overflow Flag'],
|
135
|
+
['IOPL_H', 'I/O privilege level High bit'],
|
136
|
+
['IOPL_L', 'I/O privilege level Low bit'],
|
137
|
+
['NT', 'Nested Task Flag'],
|
138
|
+
[nil, 'Reserved'],
|
139
|
+
]
|
140
|
+
|
141
|
+
def flags
|
142
|
+
flags = rflags
|
143
|
+
f = []
|
144
|
+
FLAGS.each do |abbrv, _|
|
145
|
+
if abbrv && flags & 1 == 1
|
146
|
+
f << abbrv
|
147
|
+
end
|
148
|
+
flags >>= 1
|
149
|
+
end
|
150
|
+
f
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
PT_TRACE_ME = 0
|
155
|
+
PT_CONTINUE = 7
|
156
|
+
|
157
|
+
class Tracer
|
158
|
+
def initialize pid
|
159
|
+
@pid = pid
|
160
|
+
@target = Fiddle::Pointer.malloc(Fiddle::SIZEOF_VOIDP)
|
161
|
+
|
162
|
+
unless MacOS.task_for_pid(MacOS.mach_task_self, pid, @target.ref).zero?
|
163
|
+
raise "Couldn't get task pid. Did you run with sudo?"
|
164
|
+
end
|
165
|
+
|
166
|
+
@thread_list = Fiddle::Pointer.malloc(Fiddle::SIZEOF_VOIDP)
|
167
|
+
thread_count = Fiddle::Pointer.malloc(Fiddle::SIZEOF_VOIDP)
|
168
|
+
|
169
|
+
raise unless MacOS.task_threads(@target, @thread_list.ref, thread_count).zero?
|
170
|
+
|
171
|
+
@thread = Fiddle::Pointer.new(@thread_list[0, Fiddle::SIZEOF_VOIDP].unpack1("l!"))
|
172
|
+
end
|
173
|
+
|
174
|
+
def wait
|
175
|
+
Process.waitpid @pid
|
176
|
+
end
|
177
|
+
|
178
|
+
def state
|
179
|
+
# Probably should use this for something
|
180
|
+
# count = thread_count[0]
|
181
|
+
|
182
|
+
# I can't remember what header I found this in, but it's from a macOS header
|
183
|
+
# :sweat-smile:
|
184
|
+
x86_THREAD_STATE64_COUNT = ThreadState.sizeof / Fiddle::SIZEOF_INT
|
185
|
+
|
186
|
+
# Same here
|
187
|
+
x86_THREAD_STATE64 = 4
|
188
|
+
|
189
|
+
state_count = Fiddle::Pointer.malloc(Fiddle::SIZEOF_INT64_T)
|
190
|
+
state_count[0, Fiddle::SIZEOF_INT64_T] = [x86_THREAD_STATE64_COUNT].pack("l!")
|
191
|
+
|
192
|
+
state = ThreadState.malloc
|
193
|
+
raise unless MacOS.thread_get_state(@thread, x86_THREAD_STATE64, state, state_count).zero?
|
194
|
+
|
195
|
+
state
|
196
|
+
end
|
197
|
+
|
198
|
+
def continue
|
199
|
+
unless MacOS.ptrace(MacOS::PT_CONTINUE, @pid, 1, 0).zero?
|
200
|
+
raise
|
201
|
+
end
|
202
|
+
end
|
203
|
+
end
|
204
|
+
end
|
205
|
+
end
|
@@ -0,0 +1,101 @@
|
|
1
|
+
require "racc/parser"
|
2
|
+
require "ripper"
|
3
|
+
require "fisk"
|
4
|
+
require "set"
|
5
|
+
require "strscan"
|
6
|
+
|
7
|
+
module ASMREPL
|
8
|
+
class Lexer
|
9
|
+
INTEGER = /(?:[-+]?0b[0-1_,]+ (?# base 2)
|
10
|
+
|[-+]?(?:0(?!x)|[1-9][0-9_,]*) (?# base 10)
|
11
|
+
|[-+]?0x[0-9a-fA-F_,]+ (?# base 16))/x
|
12
|
+
|
13
|
+
def initialize input
|
14
|
+
@input = input
|
15
|
+
@scanner = StringScanner.new input
|
16
|
+
end
|
17
|
+
|
18
|
+
REGISTERS = Set.new Fisk::Registers.constants.map(&:to_s)
|
19
|
+
INSTRUCTIONS = Set.new Fisk::Instructions.constants.map(&:to_s)
|
20
|
+
|
21
|
+
def next_token
|
22
|
+
return if @scanner.eos?
|
23
|
+
|
24
|
+
if @scanner.scan(INTEGER)
|
25
|
+
[:on_int, @scanner.matched]
|
26
|
+
elsif @scanner.scan(/\[/)
|
27
|
+
[:on_lbracket, @scanner.matched]
|
28
|
+
elsif @scanner.scan(/\]/)
|
29
|
+
[:on_rbracket, @scanner.matched]
|
30
|
+
elsif @scanner.scan(/,/)
|
31
|
+
[:on_comma, @scanner.matched]
|
32
|
+
elsif @scanner.scan(/qword/)
|
33
|
+
[:qword, @scanner.matched]
|
34
|
+
elsif @scanner.scan(/dword/)
|
35
|
+
[:dword, @scanner.matched]
|
36
|
+
elsif @scanner.scan(/word/)
|
37
|
+
[:word, @scanner.matched]
|
38
|
+
elsif @scanner.scan(/byte/)
|
39
|
+
[:byte, @scanner.matched]
|
40
|
+
elsif @scanner.scan(/ptr/)
|
41
|
+
[:ptr, @scanner.matched]
|
42
|
+
elsif @scanner.scan(/rip/i)
|
43
|
+
[:on_rip, @scanner.matched]
|
44
|
+
elsif @scanner.scan(/int/i)
|
45
|
+
[:on_instruction, Fisk::Instructions::INT]
|
46
|
+
elsif @scanner.scan(/movabs/i)
|
47
|
+
[:on_instruction, Fisk::Instructions::MOV]
|
48
|
+
elsif @scanner.scan(/\w+/)
|
49
|
+
ident = @scanner.matched
|
50
|
+
if INSTRUCTIONS.include?(ident.upcase)
|
51
|
+
[:on_instruction, Fisk::Instructions.const_get(ident.upcase)]
|
52
|
+
elsif REGISTERS.include?(ident.upcase)
|
53
|
+
[:on_register, Fisk::Registers.const_get(ident.upcase)]
|
54
|
+
else
|
55
|
+
[:on_ident, @scanner.matched]
|
56
|
+
end
|
57
|
+
elsif @scanner.scan(/\s+/)
|
58
|
+
[:on_sp, @scanner.matched]
|
59
|
+
elsif @scanner.scan(/\+/)
|
60
|
+
[:plus, @scanner.matched]
|
61
|
+
elsif @scanner.scan(/-/)
|
62
|
+
[:minus, @scanner.matched]
|
63
|
+
else
|
64
|
+
raise
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
class Parser < Racc::Parser
|
70
|
+
def initialize
|
71
|
+
@registers = Set.new Fisk::Registers.constants.map(&:to_s)
|
72
|
+
@instructions = Set.new Fisk::Instructions.constants.map(&:to_s)
|
73
|
+
end
|
74
|
+
|
75
|
+
def parse input
|
76
|
+
@lexer = Lexer.new input
|
77
|
+
do_parse
|
78
|
+
end
|
79
|
+
|
80
|
+
def new_command mnemonic, arg1, arg2
|
81
|
+
[:command, mnemonic, arg1, arg2]
|
82
|
+
end
|
83
|
+
|
84
|
+
def new_tuple mnemonic, arg1
|
85
|
+
[:command, mnemonic, arg1]
|
86
|
+
end
|
87
|
+
|
88
|
+
def new_single mnemonic
|
89
|
+
[:command, mnemonic]
|
90
|
+
end
|
91
|
+
|
92
|
+
def next_token
|
93
|
+
while tok = @lexer.next_token
|
94
|
+
next if tok.first == :on_sp
|
95
|
+
return tok
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
require "asmrepl/parser.tab"
|
@@ -0,0 +1,297 @@
|
|
1
|
+
#
|
2
|
+
# DO NOT MODIFY!!!!
|
3
|
+
# This file is automatically generated by Racc 1.5.1
|
4
|
+
# from Racc grammar file "".
|
5
|
+
#
|
6
|
+
|
7
|
+
require 'racc/parser.rb'
|
8
|
+
module ASMREPL
|
9
|
+
class Parser < Racc::Parser
|
10
|
+
##### State transition tables begin ###
|
11
|
+
|
12
|
+
racc_action_table = [
|
13
|
+
12, 3, 9, 4, 14, 18, 16, 15, 17, 10,
|
14
|
+
11, 12, 8, 9, 19, 14, 20, 16, 15, 17,
|
15
|
+
10, 11, 9, 8, 21, 35, 9, 37, 9, 10,
|
16
|
+
11, 22, 8, 10, 11, 10, 11, 43, 9, 45,
|
17
|
+
9, 8, 24, 8, 39, 10, 11, 10, 11, 25,
|
18
|
+
26, 27, 28, 29, 41, 42, 47, 48 ]
|
19
|
+
|
20
|
+
racc_action_check = [
|
21
|
+
2, 0, 2, 1, 2, 4, 2, 2, 2, 2,
|
22
|
+
2, 19, 2, 19, 5, 19, 6, 19, 19, 19,
|
23
|
+
19, 19, 20, 19, 10, 23, 23, 24, 24, 20,
|
24
|
+
20, 11, 20, 23, 23, 24, 24, 39, 39, 40,
|
25
|
+
40, 12, 12, 25, 25, 39, 39, 40, 40, 13,
|
26
|
+
14, 15, 16, 17, 36, 38, 44, 46 ]
|
27
|
+
|
28
|
+
racc_action_pointer = [
|
29
|
+
-12, 3, -2, nil, 5, 9, 11, nil, nil, nil,
|
30
|
+
20, 27, 27, 47, 43, 44, 45, 46, nil, 9,
|
31
|
+
18, nil, nil, 22, 24, 29, nil, nil, nil, nil,
|
32
|
+
nil, nil, nil, nil, nil, nil, 51, nil, 52, 34,
|
33
|
+
36, nil, nil, nil, 53, nil, 54, nil, nil ]
|
34
|
+
|
35
|
+
racc_action_default = [
|
36
|
+
-27, -27, -9, -10, -27, -6, -7, -8, -11, -12,
|
37
|
+
-27, -27, -27, -27, -27, -27, -27, -27, 49, -27,
|
38
|
+
-27, -13, -14, -27, -27, -27, -23, -24, -25, -26,
|
39
|
+
-1, -2, -3, -4, -5, -15, -27, -16, -27, -27,
|
40
|
+
-27, -20, -17, -18, -27, -21, -27, -19, -22 ]
|
41
|
+
|
42
|
+
racc_goto_table = [
|
43
|
+
7, 1, 5, 2, nil, nil, 6, nil, nil, nil,
|
44
|
+
nil, nil, 23, nil, nil, nil, nil, 30, 34, 31,
|
45
|
+
33, 36, 38, 32, nil, 40, nil, nil, nil, nil,
|
46
|
+
nil, nil, nil, nil, nil, nil, nil, 44, 46 ]
|
47
|
+
|
48
|
+
racc_goto_check = [
|
49
|
+
4, 1, 3, 2, nil, nil, 5, nil, nil, nil,
|
50
|
+
nil, nil, 3, nil, nil, nil, nil, 4, 4, 3,
|
51
|
+
3, 4, 4, 5, nil, 3, nil, nil, nil, nil,
|
52
|
+
nil, nil, nil, nil, nil, nil, nil, 4, 4 ]
|
53
|
+
|
54
|
+
racc_goto_pointer = [
|
55
|
+
nil, 1, 3, 0, -2, 4, nil ]
|
56
|
+
|
57
|
+
racc_goto_default = [
|
58
|
+
nil, nil, nil, nil, nil, nil, 13 ]
|
59
|
+
|
60
|
+
racc_reduce_table = [
|
61
|
+
0, 0, :racc_error,
|
62
|
+
4, 17, :_reduce_1,
|
63
|
+
4, 17, :_reduce_2,
|
64
|
+
4, 17, :_reduce_3,
|
65
|
+
4, 17, :_reduce_4,
|
66
|
+
4, 17, :_reduce_5,
|
67
|
+
2, 17, :_reduce_6,
|
68
|
+
2, 17, :_reduce_7,
|
69
|
+
2, 17, :_reduce_8,
|
70
|
+
1, 17, :_reduce_9,
|
71
|
+
1, 18, :_reduce_10,
|
72
|
+
1, 19, :_reduce_11,
|
73
|
+
1, 20, :_reduce_12,
|
74
|
+
2, 20, :_reduce_13,
|
75
|
+
2, 20, :_reduce_14,
|
76
|
+
3, 21, :_reduce_15,
|
77
|
+
3, 21, :_reduce_16,
|
78
|
+
4, 21, :_reduce_17,
|
79
|
+
4, 21, :_reduce_18,
|
80
|
+
5, 21, :_reduce_19,
|
81
|
+
4, 21, :_reduce_20,
|
82
|
+
4, 21, :_reduce_21,
|
83
|
+
5, 21, :_reduce_22,
|
84
|
+
2, 22, :_reduce_23,
|
85
|
+
2, 22, :_reduce_24,
|
86
|
+
2, 22, :_reduce_25,
|
87
|
+
2, 22, :_reduce_26 ]
|
88
|
+
|
89
|
+
racc_reduce_n = 27
|
90
|
+
|
91
|
+
racc_shift_n = 49
|
92
|
+
|
93
|
+
racc_token_table = {
|
94
|
+
false => 0,
|
95
|
+
:error => 1,
|
96
|
+
:on_lbracket => 2,
|
97
|
+
:on_rbracket => 3,
|
98
|
+
:on_int => 4,
|
99
|
+
:on_comma => 5,
|
100
|
+
:qword => 6,
|
101
|
+
:ptr => 7,
|
102
|
+
:word => 8,
|
103
|
+
:dword => 9,
|
104
|
+
:byte => 10,
|
105
|
+
:plus => 11,
|
106
|
+
:minus => 12,
|
107
|
+
:on_instruction => 13,
|
108
|
+
:on_register => 14,
|
109
|
+
:on_rip => 15 }
|
110
|
+
|
111
|
+
racc_nt_base = 16
|
112
|
+
|
113
|
+
racc_use_result_var = true
|
114
|
+
|
115
|
+
Racc_arg = [
|
116
|
+
racc_action_table,
|
117
|
+
racc_action_check,
|
118
|
+
racc_action_default,
|
119
|
+
racc_action_pointer,
|
120
|
+
racc_goto_table,
|
121
|
+
racc_goto_check,
|
122
|
+
racc_goto_default,
|
123
|
+
racc_goto_pointer,
|
124
|
+
racc_nt_base,
|
125
|
+
racc_reduce_table,
|
126
|
+
racc_token_table,
|
127
|
+
racc_shift_n,
|
128
|
+
racc_reduce_n,
|
129
|
+
racc_use_result_var ]
|
130
|
+
|
131
|
+
Racc_token_to_s_table = [
|
132
|
+
"$end",
|
133
|
+
"error",
|
134
|
+
"on_lbracket",
|
135
|
+
"on_rbracket",
|
136
|
+
"on_int",
|
137
|
+
"on_comma",
|
138
|
+
"qword",
|
139
|
+
"ptr",
|
140
|
+
"word",
|
141
|
+
"dword",
|
142
|
+
"byte",
|
143
|
+
"plus",
|
144
|
+
"minus",
|
145
|
+
"on_instruction",
|
146
|
+
"on_register",
|
147
|
+
"on_rip",
|
148
|
+
"$start",
|
149
|
+
"command",
|
150
|
+
"instruction",
|
151
|
+
"register",
|
152
|
+
"int",
|
153
|
+
"memory",
|
154
|
+
"memsize" ]
|
155
|
+
|
156
|
+
Racc_debug_parser = false
|
157
|
+
|
158
|
+
##### State transition tables end #####
|
159
|
+
|
160
|
+
# reduce 0 omitted
|
161
|
+
|
162
|
+
def _reduce_1(val, _values, result)
|
163
|
+
result = new_command(val[0], val[1], val[3])
|
164
|
+
result
|
165
|
+
end
|
166
|
+
|
167
|
+
def _reduce_2(val, _values, result)
|
168
|
+
result = new_command(val[0], val[1], val[3])
|
169
|
+
result
|
170
|
+
end
|
171
|
+
|
172
|
+
def _reduce_3(val, _values, result)
|
173
|
+
result = new_command(val[0], val[1], val[3])
|
174
|
+
result
|
175
|
+
end
|
176
|
+
|
177
|
+
def _reduce_4(val, _values, result)
|
178
|
+
result = new_command(val[0], val[1], val[3])
|
179
|
+
result
|
180
|
+
end
|
181
|
+
|
182
|
+
def _reduce_5(val, _values, result)
|
183
|
+
result = new_command(val[0], val[1], val[3])
|
184
|
+
result
|
185
|
+
end
|
186
|
+
|
187
|
+
def _reduce_6(val, _values, result)
|
188
|
+
result = new_tuple(val[0], val[1])
|
189
|
+
result
|
190
|
+
end
|
191
|
+
|
192
|
+
def _reduce_7(val, _values, result)
|
193
|
+
result = new_tuple(val[0], val[1])
|
194
|
+
result
|
195
|
+
end
|
196
|
+
|
197
|
+
def _reduce_8(val, _values, result)
|
198
|
+
result = new_tuple(val[0], val[1])
|
199
|
+
result
|
200
|
+
end
|
201
|
+
|
202
|
+
def _reduce_9(val, _values, result)
|
203
|
+
result = new_single(val[0])
|
204
|
+
result
|
205
|
+
end
|
206
|
+
|
207
|
+
def _reduce_10(val, _values, result)
|
208
|
+
result = [:instruction, val[0]]
|
209
|
+
result
|
210
|
+
end
|
211
|
+
|
212
|
+
def _reduce_11(val, _values, result)
|
213
|
+
result = [:register, val[0]]
|
214
|
+
result
|
215
|
+
end
|
216
|
+
|
217
|
+
def _reduce_12(val, _values, result)
|
218
|
+
result = [:int, Integer(val[0])]
|
219
|
+
result
|
220
|
+
end
|
221
|
+
|
222
|
+
def _reduce_13(val, _values, result)
|
223
|
+
result = [:int, Integer(val[1])]
|
224
|
+
result
|
225
|
+
end
|
226
|
+
|
227
|
+
def _reduce_14(val, _values, result)
|
228
|
+
result = [:int, -Integer(val[1])]
|
229
|
+
result
|
230
|
+
end
|
231
|
+
|
232
|
+
def _reduce_15(val, _values, result)
|
233
|
+
result = [:memory, Fisk::M64.new(val[1].last, 0)]
|
234
|
+
result
|
235
|
+
end
|
236
|
+
|
237
|
+
def _reduce_16(val, _values, result)
|
238
|
+
result = [:memory, Fisk::Registers::Rip.new(0)]
|
239
|
+
result
|
240
|
+
end
|
241
|
+
|
242
|
+
def _reduce_17(val, _values, result)
|
243
|
+
result = [:memory, Fisk::Registers::Rip.new(val[2].last)]
|
244
|
+
result
|
245
|
+
end
|
246
|
+
|
247
|
+
def _reduce_18(val, _values, result)
|
248
|
+
result = [:memory, Fisk::Registers::Rip.new(0)]
|
249
|
+
result
|
250
|
+
end
|
251
|
+
|
252
|
+
def _reduce_19(val, _values, result)
|
253
|
+
result = [:memory, Fisk::Registers::Rip.new(val[3].last)]
|
254
|
+
result
|
255
|
+
end
|
256
|
+
|
257
|
+
def _reduce_20(val, _values, result)
|
258
|
+
result = [:memory, Fisk::M64.new(val[1].last, val[2].last)]
|
259
|
+
result
|
260
|
+
end
|
261
|
+
|
262
|
+
def _reduce_21(val, _values, result)
|
263
|
+
result = [:memory, val[0].new(val[2].last, 0)]
|
264
|
+
result
|
265
|
+
end
|
266
|
+
|
267
|
+
def _reduce_22(val, _values, result)
|
268
|
+
result = [:memory, val[0].new(val[2].last, val[3].last)]
|
269
|
+
result
|
270
|
+
end
|
271
|
+
|
272
|
+
def _reduce_23(val, _values, result)
|
273
|
+
result = Fisk::M64
|
274
|
+
result
|
275
|
+
end
|
276
|
+
|
277
|
+
def _reduce_24(val, _values, result)
|
278
|
+
result = Fisk::M32
|
279
|
+
result
|
280
|
+
end
|
281
|
+
|
282
|
+
def _reduce_25(val, _values, result)
|
283
|
+
result = Fisk::M16
|
284
|
+
result
|
285
|
+
end
|
286
|
+
|
287
|
+
def _reduce_26(val, _values, result)
|
288
|
+
result = Fisk::M8
|
289
|
+
result
|
290
|
+
end
|
291
|
+
|
292
|
+
def _reduce_none(val, _values, result)
|
293
|
+
val[0]
|
294
|
+
end
|
295
|
+
|
296
|
+
end # class Parser
|
297
|
+
end # module ASMREPL
|
@@ -0,0 +1,44 @@
|
|
1
|
+
class ASMREPL::Parser
|
2
|
+
token on_lbracket on_rbracket on_int on_comma qword ptr word dword byte
|
3
|
+
token plus minus on_instruction on_register on_rip
|
4
|
+
|
5
|
+
rule
|
6
|
+
|
7
|
+
command: instruction register on_comma int { result = new_command(val[0], val[1], val[3]) }
|
8
|
+
| instruction register on_comma register { result = new_command(val[0], val[1], val[3]) }
|
9
|
+
| instruction register on_comma memory { result = new_command(val[0], val[1], val[3]) }
|
10
|
+
| instruction memory on_comma register { result = new_command(val[0], val[1], val[3]) }
|
11
|
+
| instruction memory on_comma int { result = new_command(val[0], val[1], val[3]) }
|
12
|
+
| instruction register { result = new_tuple(val[0], val[1]) }
|
13
|
+
| instruction memory { result = new_tuple(val[0], val[1]) }
|
14
|
+
| instruction int { result = new_tuple(val[0], val[1]) }
|
15
|
+
| instruction { result = new_single(val[0]) }
|
16
|
+
;
|
17
|
+
|
18
|
+
instruction: on_instruction { result = [:instruction, val[0]] }
|
19
|
+
;
|
20
|
+
|
21
|
+
register: on_register { result = [:register, val[0]] }
|
22
|
+
;
|
23
|
+
|
24
|
+
int: on_int { result = [:int, Integer(val[0])] }
|
25
|
+
| plus on_int { result = [:int, Integer(val[1])] }
|
26
|
+
| minus on_int { result = [:int, -Integer(val[1])] }
|
27
|
+
;
|
28
|
+
|
29
|
+
memory: on_lbracket register on_rbracket { result = [:memory, Fisk::M64.new(val[1].last, 0)] }
|
30
|
+
| on_lbracket on_rip on_rbracket { result = [:memory, Fisk::Registers::Rip.new(0)] }
|
31
|
+
| on_lbracket on_rip int on_rbracket { result = [:memory, Fisk::Registers::Rip.new(val[2].last)] }
|
32
|
+
| memsize on_lbracket on_rip on_rbracket { result = [:memory, Fisk::Registers::Rip.new(0)] }
|
33
|
+
| memsize on_lbracket on_rip int on_rbracket { result = [:memory, Fisk::Registers::Rip.new(val[3].last)] }
|
34
|
+
| on_lbracket register int on_rbracket { result = [:memory, Fisk::M64.new(val[1].last, val[2].last)] }
|
35
|
+
| memsize on_lbracket register on_rbracket { result = [:memory, val[0].new(val[2].last, 0)] }
|
36
|
+
| memsize on_lbracket register int on_rbracket { result = [:memory, val[0].new(val[2].last, val[3].last)] }
|
37
|
+
;
|
38
|
+
|
39
|
+
memsize: qword ptr { result = Fisk::M64 }
|
40
|
+
| dword ptr { result = Fisk::M32 }
|
41
|
+
| word ptr { result = Fisk::M16 }
|
42
|
+
| byte ptr { result = Fisk::M8 }
|
43
|
+
;
|
44
|
+
end
|