Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 39 additions & 4 deletions lib/cfg2asm/cfg/cfg_parser.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@
module Cfg2asm
module CFG
Code = Struct.new(:arch, :arch_width, :base, :code)
JumpTable = Struct.new(:position, :entry_format, :low, :high)
Comment = Struct.new(:offset, :comment)
NMethod = Struct.new(:code, :comments)
NMethod = Struct.new(:code, :comments, :jump_tables)

# A parser for CFG files.
class CFGParser
Expand All @@ -19,8 +20,34 @@ def initialize(out, file)
@state = :any
@cfg_name = nil
end

def print_summar_of_content
state = :any
loop do
line = @reader.readline("\n")
case line
when "begin_compilation\n"
state = :some
puts "Compilation:"
when "end_compilation\n"
state = :any
when "begin_cfg\n"
state = :some
puts "Config:"
when "end_cfg\n"
state = :any
when / name "(.*)"\n/
if state == :some
puts "name: #{Regexp.last_match(1)}"
state = :any
end
else
next
end
end
end

def skip_over_cfg(name)
def skip_over_cfg(name1, name2)
loop do
line = @reader.readline("\n")
case line
Expand All @@ -35,7 +62,7 @@ def skip_over_cfg(name)
raise unless @state == :cfg

@state = :any
break if @cfg_name == name
break if @cfg_name == name1 || @cfg_name == name2
else
next
end
Expand All @@ -48,6 +75,7 @@ def read_nmethod
arch = nil
arch_width = nil
code = nil
jump_tables = []
comments = []
raise unless @reader.readline == "begin_nmethod\n"

Expand All @@ -63,6 +91,13 @@ def read_nmethod
raise if arch.nil? || arch_width.nil?

code = Code.new(arch, arch_width, base, code)
when / JumpTable (\d+) (\d+) (\d+) (\d+) <\|\|@\n/
position = Regexp.last_match(1).to_i
entry_format = Regexp.last_match(2).to_i
low = Regexp.last_match(3).to_i
high = Regexp.last_match(4).to_i

jump_tables.push JumpTable.new(position, entry_format, low, high)
when / Comment (\d*) (.*) <\|\|@\n/
offset = Regexp.last_match(1).to_i
comment = Regexp.last_match(2)
Expand All @@ -86,7 +121,7 @@ def read_nmethod
raise 'There is currently no case for this line. Please open an issue so it can be addressed.'
end
end
NMethod.new(code, comments)
NMethod.new(code, comments, jump_tables)
end
end
end
Expand Down
26 changes: 26 additions & 0 deletions lib/cfg2asm/cfg/disassembler.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,30 @@ class Disassembler
def initialize(out)
@out = out
end

def turn_jump_table_into_noops(nmethod)
code = nmethod.code.code
nmethod.jump_tables.each do |t|
# t.:position, :entry_format, :low, :high
(t.low..t.high).each do |i|
if t.entry_format == 4
code.setbyte(t.position + (t.entry_format * i) + 0, 0x0F)
code.setbyte(t.position + (t.entry_format * i) + 1, 0x1F)
code.setbyte(t.position + (t.entry_format * i) + 2, 0x40)
code.setbyte(t.position + (t.entry_format * i) + 3, 0x00)
elsif t.entry_format == 8
code.setbyte(t.position + (t.entry_format * i) + 0, 0x0F)
code.setbyte(t.position + (t.entry_format * i) + 1, 0x1F)
code.setbyte(t.position + (t.entry_format * i) + 2, 0x84)
code.setbyte(t.position + (t.entry_format * i) + 3, 0x00)
code.setbyte(t.position + (t.entry_format * i) + 4, 0x00)
code.setbyte(t.position + (t.entry_format * i) + 5, 0x00)
code.setbyte(t.position + (t.entry_format * i) + 6, 0x00)
code.setbyte(t.position + (t.entry_format * i) + 7, 0x00)
end
end
end
end

def disassemble(nmethod, print_comments)
require_crabstone
Expand All @@ -23,6 +47,8 @@ def disassemble(nmethod, print_comments)
raise "Unknown architecture #{nmethod.code.arch} and bit width #{nmethod.code.arch_width}"
end

turn_jump_table_into_noops(nmethod)

cs = Crabstone::Disassembler.new(*crabstone_arch)
begin
cs.disasm(nmethod.code.code, nmethod.code.base).each do |i|
Expand Down
48 changes: 31 additions & 17 deletions lib/cfg2asm/commands.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,27 @@ class Commands
def initialize(out)
@out = out
end

def get_files_and_comments_flag(args)
comments = true
files = []

until args.empty?
arg = args.shift
if arg.start_with?('-')
case arg
when '--no-comments'
comments = false
else
raise ArgumentError, "unknown option #{arg}"
end
else
files.push arg
end
end

[files, comments]
end

def cfg2asm(*args)
case args.first
Expand All @@ -21,27 +42,20 @@ def cfg2asm(*args)
when 'version', '-v', '-version', '--version'
args = args.drop(1)
version(*args)
else
comments = true
files = []

until args.empty?
arg = args.shift
if arg.start_with?('-')
case arg
when '--no-comments'
comments = false
else
raise ArgumentError, "unknown option #{arg}"
end
else
files.push arg
end
when 'summary'
args.shift
files, comments = get_files_and_comments_flag(args)

files.each_with_index do |file, n|
parser = Cfg2asm::CFG::CFGParser.new(@out, file)
parser.print_summar_of_content
end
else
files, comments = get_files_and_comments_flag(args)

files.each_with_index do |file, n|
parser = Cfg2asm::CFG::CFGParser.new(@out, file)
parser.skip_over_cfg 'After code installation'
parser.skip_over_cfg('After code installation', 'After code generation')
nmethod = parser.read_nmethod

disassembler = Cfg2asm::CFG::Disassembler.new(@out)
Expand Down