Class: ASMREPL::REPL

Inherits:
Object
  • Object
show all
Includes:
Fiddle
Defined in:
lib/asmrepl/repl.rb

Constant Summary collapse

CFuncs =
Linux

Constants included from Fiddle

Fiddle::SIZEOF_INT64_T

Instance Method Summary collapse

Constructor Details

#initializeREPL

Returns a new instance of REPL.



21
22
23
24
25
26
27
# File 'lib/asmrepl/repl.rb', line 21

def initialize
  size = 1024 * 16 # 16k is enough for anyone!
  @buffer = CFuncs.jitbuffer(size)
  CFuncs.memset(@buffer.memory, 0xCC, size)
  @parser    = ASMREPL::Parser.new
  @assembler = ASMREPL::Assembler.new
end

Instance Method Details

#display_state(state) ⇒ Object



29
30
31
32
33
34
35
# File 'lib/asmrepl/repl.rb', line 29

def display_state state
  puts " CPU STATE ".center(48, "=")
  puts state
  puts
  puts "FLAGS: #{state.flags.inspect}"
  puts
end

#startObject



37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
# File 'lib/asmrepl/repl.rb', line 37

def start
  pid = fork {
    CFuncs.traceme
    @buffer.to_function([], TYPE_INT).call
  }

  tracer = CFuncs::Tracer.new pid
  should_cpu = true
  while tracer.wait
    state = tracer.state

    # Show CPU state once on boot
    if should_cpu
      display_state state
      should_cpu = false
    end

    # Move the JIT buffer to the current instruction pointer
    pos = (state.rip - @buffer.memory.to_i)
    @buffer.seek pos
    use_history = true
    begin
      loop do
        cmd = nil
        text = Reline.readmultiline(">> ", use_history) do |multiline_input|
          if multiline_input =~ /\A\s*(\w+)\s*\Z/
            register = $1
            cmd = [:read, register]
          else
            cmd = :run
          end
          true
        end

        case cmd
        in :run
          break if text.chomp.empty?
          binary = @assembler.assemble @parser.parse text.chomp
          binary.bytes.each { |byte| @buffer.putc byte }
          break
        in [:read, "cpu"]
          display_state state
        in [:read, reg]
          val = state[reg]
          if val
            puts sprintf("%#018x", state[reg])
          else
            puts "Unknown command: "
            puts "  " + text
          end
        else
        end
      end
    rescue Interrupt
      exit 0
    end
    tracer.continue
  end
end