asmrepl 1.0.0 → 1.1.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d89ea7a3b6af16e72444221e66fa9c2af2ceaebaae8c4e48d7a30d4b419283f5
4
- data.tar.gz: 7b9e86750882fe36a9fdf5ee311e7cdb483c19faf3ffa8a46bdb85808a93e455
3
+ metadata.gz: 7045e3fe0facfdc15e21bb3dfebcaf5232eb68c144ac07e6bf61588979ca3c7f
4
+ data.tar.gz: 158f3aea1088ae25397dccfc6bf593449df3482f031c025c6dbf33ce372f6a53
5
5
  SHA512:
6
- metadata.gz: c583255650ca956401117259c068faa6cae8f8df435b88d447186a883a8c32b45a6e6e8d16aae0fc082f4b6b979156ee88aeea6c27bf4296f73fe0c15b7b85f0
7
- data.tar.gz: 349bcb373b93a9dec96421be445005dba162325acea07eb3e20850fd7078550d67576059ea81c33be9d99fe9f6147e8e3bde1d2945989372671e1d5418b3b141
6
+ metadata.gz: d039b567f9cb938f56f86c1ea02a9c16a3c266748fb16d37b5c710c66618010dba32b13755d778c9dded6a56bb521fb61198281297543aad9f3f6c39028510b4
7
+ data.tar.gz: 7f37562a9568489d61d9eb3144310d3c372fd5fe7ab07b3b0786c268bc8a2b20077a52736723d0f684930924614083cc4df2a817e6f91f8f6b7afae438aeb0fc
data/README.md CHANGED
@@ -4,27 +4,34 @@ This is a REPL for assembly language.
4
4
 
5
5
  ## Usage
6
6
 
7
- I haven't made a gem yet, so use it like this:
7
+ Install the gem:
8
8
 
9
9
  ```
10
- $ bundle install
11
- $ sudo ruby -I lib:test bin/asmrepl
10
+ $ gem install asmrepl
12
11
  ```
13
12
 
13
+ Then start the repl like this:
14
+
15
+ ```
16
+ $ asmrepl
17
+ ```
18
+
19
+ If you're on macOS, you'll need to start the repl with `sudo`.
20
+
14
21
  When the REPL starts, it will display all register values and flags:
15
22
 
16
23
  ```
17
24
  ================== CPU STATE ===================
18
- rax 000000000000000000 r8 0x0000600001782be0
19
- rbx 000000000000000000 r9 0x00007fbf9b0068c0
20
- rcx 0x0000000109dae951 r10 000000000000000000
21
- rdx 0x000000000000000c r11 0x000000010999c000
22
- rdi 0x00007ff7b6b2bbf0 r12 000000000000000000
23
- rsi 0x00000001096315fd r13 0x00007ff7b6b2bdc0
24
- rbp 0x00007ff7b6b2bc40 r14 000000000000000000
25
- rsp 0x00007ff7b6b2bc38 r15 000000000000000000
26
-
27
- rip 0x000000010999c001
25
+ rax 000000000000000000 r8 0x00007f89d0f04640
26
+ rbx 000000000000000000 r9 0x0000000000000004
27
+ rcx 0x00007f89d0f04a50 r10 000000000000000000
28
+ rdx 0x..fc611d3f0aa2900d4 r11 0x00000001033a4000
29
+ rdi 0x00007ff7bd126148 r12 000000000000000000
30
+ rsi 000000000000000000 r13 0x00007ff7bd125dc0
31
+ rbp 0x00007ff7bd125c40 r14 000000000000000000
32
+ rsp 0x00007ff7bd125c38 r15 000000000000000000
33
+
34
+ rip 0x00000001033a4001
28
35
  rflags 0x0000000000000246
29
36
  cs 0x000000000000002b
30
37
  fs 000000000000000000
@@ -32,46 +39,58 @@ gs 000000000000000000
32
39
 
33
40
  FLAGS: ["PF", "ZF", "IF"]
34
41
 
35
- >>
42
+ (rip 0x00000001033a4001)>
36
43
  ```
37
44
 
38
45
  Then you can issue commands and inspect register values. Let's write to the
39
46
  `rax` register and inspect its value:
40
47
 
41
48
  ```
42
- >> mov rax, 5
43
- >> rax
49
+ (rip 0x00000001033a4001)> mov rax, 5
50
+ =============== REGISTER CHANGES ===============
51
+ rax 000000000000000000 => 0x0000000000000005
52
+
53
+ (rip 0x00000001033a4009)> rax
44
54
  0x0000000000000005
45
- >>
55
+ (rip 0x00000001033a4009)>
46
56
  ```
47
57
 
48
58
  Now let's write to the `rbx` register and add the two values:
49
59
 
50
60
  ```
51
- >> mov rbx, 3
52
- >> add rax, rbx
53
- >> rax
61
+ (rip 0x00000001033a4009)> mov rbx, 3
62
+ =============== REGISTER CHANGES ===============
63
+ rbx 000000000000000000 => 0x0000000000000003
64
+
65
+ (rip 0x00000001033a4011)> add rax, rbx
66
+ =============== REGISTER CHANGES ===============
67
+ rax 0x0000000000000005 => 0x0000000000000008
68
+ rflags 0x0000000000000246 => 0x0000000000000202
69
+
70
+ FLAGS: ["IF"]
71
+
72
+ (rip 0x00000001033a4015)> rax
54
73
  0x0000000000000008
55
- >> rbx
74
+ (rip 0x00000001033a4015)> rbx
56
75
  0x0000000000000003
57
- >>
76
+ (rip 0x00000001033a4015)>
58
77
  ```
59
78
 
60
79
  Finally, lets check all values in the CPU:
61
80
 
62
81
  ```
63
- >> cpu
82
+ (rip 0x00000001033a4015)> cpu
64
83
  ================== CPU STATE ===================
65
- rax 0x0000000000000008 r8 0x0000600001d848a0
66
- rbx 0x0000000000000003 r9 0x00007fced316f850
67
- rcx 0x00000001017da951 r10 000000000000000000
68
- rdx 0x000000000000000c r11 0x00000001013cc000
69
- rdi 0x00007ff7bf0fdbf0 r12 000000000000000000
70
- rsi 0x000000010105f5fd r13 0x00007ff7bf0fddc0
71
- rbp 0x00007ff7bf0fdc40 r14 000000000000000000
72
- rsp 0x00007ff7bf0fdc38 r15 000000000000000000
73
-
74
- rip 0x00000001013cc029
84
+ rax 0x0000000000000008 r8 0x00007f89d0f04640
85
+ rbx 0x0000000000000003 r9 0x0000000000000004
86
+ rcx 0x00007f89d0f04a50 r10 000000000000000000
87
+ rdx 0x..fc611d3f0aa2900d4 r11 0x00000001033a4000
88
+ rdi 0x00007ff7bd126148 r12 000000000000000000
89
+ rsi 000000000000000000 r13 0x00007ff7bd125dc0
90
+ rbp 0x00007ff7bd125c40 r14 000000000000000000
91
+ rsp 0x00007ff7bd125c38 r15 000000000000000000
92
+
93
+ rip 0x00000001033a4015
75
94
  rflags 0x0000000000000202
76
95
  cs 0x000000000000002b
77
96
  fs 000000000000000000
@@ -79,5 +98,5 @@ gs 000000000000000000
79
98
 
80
99
  FLAGS: ["IF"]
81
100
 
82
- >>
101
+ (rip 0x00000001033a4015)>
83
102
  ```
data/asmrepl.gemspec CHANGED
@@ -20,5 +20,5 @@ Gem::Specification.new do |s|
20
20
  s.add_development_dependency 'minitest', '~> 5.14'
21
21
  s.add_development_dependency 'crabstone', '~> 4.0'
22
22
  s.add_development_dependency 'rake', '~> 13.0'
23
- s.add_dependency 'fisk', '~> 2'
23
+ s.add_dependency 'fisk', '~> 2.3.1'
24
24
  end
data/lib/asmrepl/repl.rb CHANGED
@@ -1,6 +1,5 @@
1
1
  require "fiddle"
2
2
  require "fisk/helpers"
3
- require "crabstone"
4
3
  require "reline"
5
4
 
6
5
  if RUBY_PLATFORM =~ /darwin/
@@ -9,17 +8,6 @@ else
9
8
  require "asmrepl/linux"
10
9
  end
11
10
 
12
- class Crabstone::Binding::Instruction
13
- class << self
14
- alias :old_release :release
15
- end
16
-
17
- # Squelch error in crabstone
18
- def self.release obj
19
- nil
20
- end
21
- end
22
-
23
11
  module ASMREPL
24
12
  class REPL
25
13
  include Fiddle
@@ -39,13 +27,40 @@ module ASMREPL
39
27
  end
40
28
 
41
29
  def display_state state
42
- puts " CPU STATE ".center(48, "=")
30
+ puts bold(" CPU STATE ".center(48, "="))
43
31
  puts state
44
32
  puts
45
33
  puts "FLAGS: #{state.flags.inspect}"
46
34
  puts
47
35
  end
48
36
 
37
+ def display_state_change last_state, state
38
+ puts bold(" REGISTER CHANGES ".center(48, "="))
39
+ show_flags = false
40
+
41
+ state.fields.each do |field|
42
+ next if field == "rip"
43
+
44
+ if last_state[field] != state[field]
45
+ print "#{field.ljust(6)} "
46
+ print sprintf("%#018x", last_state[field])
47
+ print " => "
48
+ puts bold(sprintf("%#018x", state[field]))
49
+ end
50
+ end
51
+
52
+ if last_state.flags != state.flags
53
+ puts
54
+ puts "FLAGS: #{state.flags.inspect}"
55
+ end
56
+
57
+ puts
58
+ end
59
+
60
+ def bold string
61
+ "\e[1m#{string}\e[0m"
62
+ end
63
+
49
64
  def start
50
65
  pid = fork {
51
66
  CFuncs.traceme
@@ -54,49 +69,73 @@ module ASMREPL
54
69
 
55
70
  tracer = CFuncs::Tracer.new pid
56
71
  should_cpu = true
72
+ last_state = nil
73
+
57
74
  while tracer.wait
58
75
  state = tracer.state
59
76
 
60
77
  # Show CPU state once on boot
61
- if should_cpu
78
+ if last_state.nil?
62
79
  display_state state
63
- should_cpu = false
80
+ last_state = state
81
+ else
82
+ display_state_change last_state, state
83
+ last_state = state
64
84
  end
65
85
 
66
86
  # Move the JIT buffer to the current instruction pointer
67
87
  pos = (state.rip - @buffer.memory.to_i)
68
88
  @buffer.seek pos
69
89
  use_history = true
70
- loop do
71
- cmd = nil
72
- text = Reline.readmultiline(">> ", use_history) do |multiline_input|
73
- if multiline_input =~ /\A\s*(\w+)\s*\Z/
74
- register = $1
75
- cmd = [:read, register]
76
- else
77
- cmd = :run
90
+ begin
91
+ loop do
92
+ cmd = nil
93
+ prompt = sprintf("(rip %#018x)> ", state.rip)
94
+ text = Reline.readmultiline(prompt, use_history) do |multiline_input|
95
+ if multiline_input =~ /\A\s*(\w+)\s*\Z/
96
+ register = $1
97
+ cmd = [:read, register]
98
+ else
99
+ cmd = :run
100
+ end
101
+ true
78
102
  end
79
- true
80
- end
81
103
 
82
- case cmd
83
- in :run
84
- break if text.chomp.empty?
85
- binary = @assembler.assemble @parser.parse text.chomp
86
- binary.bytes.each { |byte| @buffer.putc byte }
87
- break
88
- in [:read, "cpu"]
89
- display_state state
90
- in [:read, reg]
91
- val = state[reg]
92
- if val
93
- puts sprintf("%#018x", state[reg])
104
+ case cmd
105
+ in :run
106
+ break if text.chomp.empty?
107
+ begin
108
+ parser_result = @parser.parse text.chomp
109
+ rescue
110
+ puts "Invalid intruction"
111
+ next
112
+ end
113
+
114
+ begin
115
+ binary = @assembler.assemble parser_result
116
+ binary.bytes.each { |byte| @buffer.putc byte }
117
+ rescue Fisk::Errors::InvalidInstructionError => e
118
+ # Print an error message when the instruction is invalid
119
+ puts e.message
120
+ next
121
+ end
122
+ break
123
+ in [:read, "cpu"]
124
+ display_state state
125
+ in [:read, reg]
126
+ val = state[reg]
127
+ if val
128
+ puts sprintf("%#018x", state[reg])
129
+ else
130
+ puts "Unknown command: "
131
+ puts " " + text
132
+ end
94
133
  else
95
- puts "Unknown command: "
96
- puts " " + text
97
134
  end
98
- else
99
135
  end
136
+ rescue Interrupt
137
+ puts ""
138
+ exit 0
100
139
  end
101
140
  tracer.continue
102
141
  end
@@ -1,3 +1,3 @@
1
1
  module ASMREPL
2
- VERSION = '1.0.0'
2
+ VERSION = '1.1.0'
3
3
  end
data/lib/asmrepl.rb CHANGED
@@ -1,3 +1,11 @@
1
+ require "fiddle"
2
+
3
+ module Fiddle
4
+ unless Fiddle.const_defined?(:SIZEOF_INT64_T)
5
+ SIZEOF_INT64_T = Fiddle::SIZEOF_UINTPTR_T
6
+ end
7
+ end
8
+
1
9
  require "asmrepl/parser"
2
10
  require "asmrepl/assembler"
3
11
  require "asmrepl/repl"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: asmrepl
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Aaron Patterson
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-11-24 00:00:00.000000000 Z
11
+ date: 2021-12-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: minitest
@@ -58,14 +58,14 @@ dependencies:
58
58
  requirements:
59
59
  - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: '2'
61
+ version: 2.3.1
62
62
  type: :runtime
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
- version: '2'
68
+ version: 2.3.1
69
69
  description: Tired of writing assembly and them assembling it? Now you can write assembly
70
70
  and evaluate it!
71
71
  email: tenderlove@ruby-lang.org