cfg2asm 0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 9fe9c7d9795d226dbb31a45071c764468a29e04d416c060145660acd79c1ccf0
4
+ data.tar.gz: dcac08b911bc46c252629bf150079d81c648d02f0c6be93b36612a5b344907d5
5
+ SHA512:
6
+ metadata.gz: 1b1c86cc939e77ae3ee16fb0ba796dcc2f6a0bae19287f88f2a121cb125bed6a1fcac8e7030a04aa212cfcea2bb6b07b8f45dbfdbbe398af18b877eff5cfdf24
7
+ data.tar.gz: 5b3433186dbf48aab5d00b817f4ba3151ee663394dfac98c22cee9ac57e1e8bcfd456abdd381f05693b8a429751c16856eb3b2dde9a4ae8e725cf938e26d9bc3
data/bin/cfg2asm ADDED
@@ -0,0 +1,20 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'cfg2asm'
4
+
5
+ # This is the 'cfg2asm' command line entry point.
6
+
7
+ begin
8
+ # Run the command line.
9
+ commands = Cfg2asm::Commands.new($stdout)
10
+ commands.cfg2asm(*ARGV)
11
+ rescue StandardError => e
12
+ if $DEBUG
13
+ # Re-raise the exception so the user sees it, if debugging is
14
+ # enabled (ruby -d).
15
+ raise e
16
+ else
17
+ # Otherwise, just print the message.
18
+ warn "seafoam: #{e.message}"
19
+ end
20
+ end
@@ -0,0 +1,93 @@
1
+ require 'stringio'
2
+ require 'zlib'
3
+
4
+ module Cfg2asm
5
+ module CFG
6
+ Code = Struct.new(:arch, :arch_width, :base, :code)
7
+ Comment = Struct.new(:offset, :comment)
8
+ NMethod = Struct.new(:code, :comments)
9
+
10
+ # A parser for CFG files.
11
+ class CFGParser
12
+ def initialize(out, file)
13
+ @out = out
14
+ data = File.read(file, encoding: Encoding::ASCII_8BIT)
15
+ if data[0..1].bytes == [0x1f, 0x8b]
16
+ data = Zlib.gunzip(data)
17
+ end
18
+ @reader = StringIO.new(data)
19
+ @state = :any
20
+ @cfg_name = nil
21
+ end
22
+
23
+ def skip_over_cfg(name)
24
+ loop do
25
+ line = @reader.readline("\n")
26
+ case line
27
+ when "begin_cfg\n"
28
+ @state = :cfg
29
+ @cfg_name = nil
30
+ when / name "(.*)"\n/
31
+ if @state == :cfg
32
+ @cfg_name = Regexp.last_match(1)
33
+ end
34
+ when "end_cfg\n"
35
+ raise unless @state == :cfg
36
+
37
+ @state = :any
38
+ break if @cfg_name == name
39
+ else
40
+ next
41
+ end
42
+ end
43
+ end
44
+
45
+ def read_nmethod
46
+ raise unless @state == :any
47
+
48
+ arch = nil
49
+ arch_width = nil
50
+ code = nil
51
+ comments = []
52
+ raise unless @reader.readline == "begin_nmethod\n"
53
+
54
+ loop do
55
+ line = @reader.readline("\n")
56
+ case line
57
+ when / Platform (.*) (.*) <\|\|@\n/
58
+ arch = Regexp.last_match(1)
59
+ arch_width = Regexp.last_match(2)
60
+ when / HexCode (.*) (.*) <\|\|@\n/
61
+ base = Regexp.last_match(1).to_i(16)
62
+ code = [Regexp.last_match(2)].pack('H*')
63
+ raise if arch.nil? || arch_width.nil?
64
+
65
+ code = Code.new(arch, arch_width, base, code)
66
+ when / Comment (\d*) (.*) <\|\|@\n/
67
+ offset = Regexp.last_match(1).to_i
68
+ comment = Regexp.last_match(2)
69
+ comments.push Comment.new(offset, comment)
70
+ when " <<<HexCodeFile\n"
71
+ next
72
+ when " HexCodeFile>>> <|@\n"
73
+ next
74
+ when "end_nmethod\n"
75
+ break
76
+ when / (.*) <\|\|@\n/
77
+ offset = -1
78
+ comment = Regexp.last_match(1)
79
+ comments.push Comment.new(offset, comment)
80
+ when / (.*)\n/
81
+ offset = -1
82
+ comment = Regexp.last_match(1)
83
+ comments.push Comment.new(offset, comment)
84
+ else
85
+ # In case anything was missed
86
+ raise 'There is currently no case for this line. Please open an issue so it can be addressed.'
87
+ end
88
+ end
89
+ NMethod.new(code, comments)
90
+ end
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,70 @@
1
+ require 'stringio'
2
+
3
+ module Cfg2asm
4
+ module CFG
5
+ # Disassemble and print comments from cfg files
6
+ class Disassembler
7
+ def initialize(out)
8
+ @out = out
9
+ end
10
+
11
+ def disassemble(nmethod, print_comments)
12
+ require_crabstone
13
+
14
+ comments = nmethod.comments
15
+ comments_n = 0
16
+
17
+ case [nmethod.code.arch, nmethod.code.arch_width]
18
+ when %w[AMD64 64]
19
+ crabstone_arch = [Crabstone::ARCH_X86, Crabstone::MODE_64]
20
+ else
21
+ raise "Unknown architecture #{nmethod.code.arch} and bit width #{nmethod.code.arch_width}"
22
+ end
23
+
24
+ cs = Crabstone::Disassembler.new(*crabstone_arch)
25
+ begin
26
+ cs.disasm(nmethod.code.code, nmethod.code.base).each do |i|
27
+ if print_comments
28
+ # Print comments associated to the instruction.
29
+ last_comment = i.address + i.bytes.length - nmethod.code.base
30
+ while comments_n < comments.length && comments[comments_n].offset < last_comment
31
+ if comments[comments_n].offset == -1
32
+ @out.printf("\t\t\t\t;%<comment>s\n", comment: comments[comments_n].comment)
33
+ else
34
+ @out.printf(
35
+ "\t\t\t\t;Comment %<loc>i:\t%<comment>s\n",
36
+ loc: comments[comments_n].offset,
37
+ comment: comments[comments_n].comment
38
+ )
39
+ end
40
+ comments_n += 1
41
+ end
42
+ end
43
+
44
+ # Print the instruction.
45
+ @out.printf(
46
+ "\t0x%<address>x:\t%<instruction>s\t%<details>s\n",
47
+ address: i.address,
48
+ instruction: i.mnemonic,
49
+ details: i.op_str
50
+ )
51
+ end
52
+ rescue StandardError => e
53
+ raise "Disassembly error: #{e.message}"
54
+ ensure
55
+ cs.close
56
+ end
57
+ end
58
+
59
+ def require_crabstone
60
+ require 'crabstone'
61
+ rescue LoadError => e
62
+ if $DEBUG
63
+ raise e
64
+ else
65
+ raise 'Could not load Capstone - is it installed?'
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,62 @@
1
+ require 'json'
2
+ require 'set'
3
+
4
+ module Cfg2asm
5
+ # Implementations of the command-line commands that you can run in Seafoam.
6
+ class Commands
7
+ def initialize(out)
8
+ @out = out
9
+ end
10
+
11
+ def cfg2asm(*args)
12
+ case args.first
13
+ when nil, 'help', '-h', '--help', '-help'
14
+ args = args.drop(1)
15
+ raise ArgumentError, "unexpected arguments #{args.join(' ')}" unless args.empty?
16
+
17
+ @out.puts 'cfg2asm file.bgv...'
18
+ @out.puts ' --no-comments'
19
+ @out.puts ' --help'
20
+ @out.puts ' --version'
21
+ when 'version', '-v', '-version', '--version'
22
+ args = args.drop(1)
23
+ version(*args)
24
+ else
25
+ comments = true
26
+ files = []
27
+
28
+ until args.empty?
29
+ arg = args.shift
30
+ if arg.start_with?('-')
31
+ case arg
32
+ when '--no-comments'
33
+ comments = false
34
+ else
35
+ raise ArgumentError, "unknown option #{arg}"
36
+ end
37
+ else
38
+ files.push arg
39
+ end
40
+ end
41
+
42
+ files.each_with_index do |file, n|
43
+ parser = Cfg2asm::CFG::CFGParser.new(@out, file)
44
+ parser.skip_over_cfg 'After code installation'
45
+ nmethod = parser.read_nmethod
46
+
47
+ disassembler = Cfg2asm::CFG::Disassembler.new(@out)
48
+ @out.puts if n.positive?
49
+ @out.puts "[#{file}]"
50
+ disassembler.disassemble(nmethod, comments)
51
+ end
52
+ end
53
+ end
54
+
55
+ # Prints the version.
56
+ def version(*args)
57
+ raise ArgumentError, "unexpected arguments #{args.join(' ')}" unless args.empty?
58
+
59
+ @out.puts "cfg2asm #{VERSION}"
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,5 @@
1
+ module Cfg2asm
2
+ MAJOR_VERSION = 0
3
+ MINOR_VERSION = 1
4
+ VERSION = "#{MAJOR_VERSION}.#{MINOR_VERSION}"
5
+ end
data/lib/cfg2asm.rb ADDED
@@ -0,0 +1,4 @@
1
+ require 'cfg2asm/version'
2
+ require 'cfg2asm/cfg/cfg_parser'
3
+ require 'cfg2asm/cfg/disassembler'
4
+ require 'cfg2asm/commands'
metadata ADDED
@@ -0,0 +1,105 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: cfg2asm
3
+ version: !ruby/object:Gem::Version
4
+ version: '0.1'
5
+ platform: ruby
6
+ authors:
7
+ - Chris Seaton
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2022-02-16 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: crabstone
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '4.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '4.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 13.0.6
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 13.0.6
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.8'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.8'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rubocop
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '='
60
+ - !ruby/object:Gem::Version
61
+ version: '0.81'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '='
67
+ - !ruby/object:Gem::Version
68
+ version: '0.81'
69
+ description:
70
+ email:
71
+ executables:
72
+ - cfg2asm
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - bin/cfg2asm
77
+ - lib/cfg2asm.rb
78
+ - lib/cfg2asm/cfg/cfg_parser.rb
79
+ - lib/cfg2asm/cfg/disassembler.rb
80
+ - lib/cfg2asm/commands.rb
81
+ - lib/cfg2asm/version.rb
82
+ homepage: https://github.com/Shopify/cfg2asm
83
+ licenses:
84
+ - MIT
85
+ metadata: {}
86
+ post_install_message:
87
+ rdoc_options: []
88
+ require_paths:
89
+ - lib
90
+ required_ruby_version: !ruby/object:Gem::Requirement
91
+ requirements:
92
+ - - ">="
93
+ - !ruby/object:Gem::Version
94
+ version: 2.3.7
95
+ required_rubygems_version: !ruby/object:Gem::Requirement
96
+ requirements:
97
+ - - ">="
98
+ - !ruby/object:Gem::Version
99
+ version: '0'
100
+ requirements: []
101
+ rubygems_version: 3.3.3
102
+ signing_key:
103
+ specification_version: 4
104
+ summary: A tool for disassembling Graal CFG files
105
+ test_files: []