binrip 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: fdcf48f2dbbcf86fbaee2b8df4ae52e7e3d5d780c2355550c3067207b398b958
4
+ data.tar.gz: '096136cc21c5a841782054f55f7fcfe7d44687ff9af8346796752fe97664b2df'
5
+ SHA512:
6
+ metadata.gz: bfc2e4aca21afb16774675b4967da77f8631aa91594098d1eb2c062b24a4549b8452ae222415fb3e1226abdcd6c6100a693dd24354498df22d58845e6c8f6ad4
7
+ data.tar.gz: b115be023cfa59e5c171b9ba1f0c01a8ca13171b2163baede955dd74a847e4476d44839a397b71ab313b31afd35de39882b82902785ace638b369d6e7e2ab10b
data/Gemfile ADDED
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
4
+
5
+ git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
6
+
7
+ # Specify your gem's dependencies in binrip.gemspec
8
+ gemspec
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'bundler/setup'
5
+ require 'binrip'
6
+
7
+ # You can add fixtures and/or initialization code here to make experimenting
8
+ # with your gem easier. You can also use a different console, if you like.
9
+
10
+ # (If you use this, don't forget to add pry to your Gemfile!)
11
+ # require "pry"
12
+ # Pry.start
13
+
14
+ require 'irb'
15
+ IRB.start(__FILE__)
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ lib = File.expand_path('lib', __dir__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+ require 'binrip/version'
6
+
7
+ Gem::Specification.new do |spec|
8
+ unless spec.respond_to?(:metadata)
9
+ # Prevent pushing this gem to RubyGems.org by setting 'allowed_push_host',
10
+ # or delete this section to allow pushing this gem to any host.
11
+ raise <<-ERR
12
+ RubyGems 2.0 or newer is required to protect against public gem pushes.
13
+ ERR
14
+ end
15
+
16
+ spec.name = 'binrip'
17
+ spec.version = Binrip::VERSION
18
+ spec.authors = ['David Siaw']
19
+ spec.email = ['davidsiaw@gmail.com']
20
+
21
+ spec.summary = 'Binary file format language'
22
+ spec.description = 'Ripper of binary files'
23
+ spec.homepage = 'https://github.com/davidsiaw/binrip'
24
+ spec.license = 'MIT'
25
+
26
+ spec.metadata['homepage_uri'] = spec.homepage
27
+ spec.metadata['source_code_uri'] = 'https://github.com/davidsiaw/binrip'
28
+ spec.metadata['changelog_uri'] = 'https://github.com/davidsiaw/binrip'
29
+
30
+ spec.files = Dir['{data,exe,lib,bin}/**/*'] +
31
+ %w[Gemfile binrip.gemspec]
32
+ spec.test_files = Dir['{spec,features}/**/*']
33
+ spec.bindir = 'exe'
34
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
35
+ spec.require_paths = ['lib']
36
+
37
+ spec.add_dependency 'activesupport'
38
+ spec.add_dependency 'optimist'
39
+ spec.add_dependency 'sinatra', '~> 2.0.3'
40
+
41
+ spec.add_development_dependency 'bundler', '~> 1.9'
42
+ spec.add_development_dependency 'rspec'
43
+
44
+ spec.metadata['allowed_push_host'] = 'https://rubygems.org'
45
+ end
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'binrip/version'
4
+ require 'yaml'
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Binrip
4
+ VERSION = '0.1.0'
5
+ end
@@ -0,0 +1,283 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Main module
4
+ module Binrip
5
+ class Device
6
+ def index(something)
7
+ end
8
+ end
9
+
10
+ class SetInstruction
11
+ def initialize(machine, params)
12
+ @machine = machine
13
+ @params = params
14
+ end
15
+
16
+ def run!
17
+ @machine.registers[dst_register_name] = src_value
18
+ end
19
+
20
+ def src_value
21
+ return @params[1] if @params[1].is_a? Integer
22
+
23
+ @machine.registers[src_register_name]
24
+ end
25
+
26
+ def src_register_name
27
+ name_of @params[1]
28
+ end
29
+
30
+ def dst_register_name
31
+ name_of @params[0]
32
+ end
33
+
34
+ def name_of(thing)
35
+ thing.to_s.sub(/^reg_/, '').to_sym
36
+ end
37
+ end
38
+
39
+ # interpreter
40
+ class Interpreter
41
+ attr_reader :error, :memory, :device, :rom, :registers
42
+
43
+ # a, b, c, d, e, f, g, h -> general purpose registers
44
+ # pc -> register with address of next operation
45
+ # mr -> register with address of memory being used
46
+ # err -> error register
47
+ # mem -> setting this register outputs to memory
48
+ # reading this register inputs from memory
49
+ # dev -> setting this register outputs to device
50
+ # reading this register inputs from device
51
+ REGISTER_NAMES = %i[a b c d e f g h pc mr err mem dev].freeze
52
+
53
+ def initialize(rom, device)
54
+ @rom = rom
55
+ @memory = {}
56
+ @stack = []
57
+ @halted = false
58
+ @device = device
59
+ @registers = REGISTER_NAMES.map { |x| [x, 0] }.to_h
60
+ end
61
+
62
+ def step!
63
+ return if halted? # no need to run if halted
64
+
65
+ execute!
66
+
67
+ rescue => e
68
+ @error = e
69
+ set_register(:err, 1)
70
+
71
+ ensure
72
+ increment(:pc)
73
+ @halted = true if register_value(:pc) >= @rom.length
74
+ end
75
+
76
+ def execute!
77
+ instruction = @rom[register_value(:pc)]
78
+ params = instruction.values[0]
79
+
80
+ case instruction.keys[0]
81
+ when 'set'
82
+ SetInstruction.new(self, params).run!
83
+ end
84
+ end
85
+
86
+ def register_value(register)
87
+ @registers[register]
88
+ end
89
+
90
+ def set_register(register, value)
91
+ @registers[register] = value
92
+ end
93
+
94
+ def increment(register)
95
+ @registers[register] += 1
96
+ end
97
+
98
+ def halted?
99
+ @halted
100
+ end
101
+ end
102
+
103
+ # linker
104
+ class Linker
105
+ def initialize(asm)
106
+ @asm = asm
107
+ p @asm
108
+ end
109
+
110
+ def positions
111
+ pos = {}
112
+ count = 0
113
+ @asm.each do |fname, fdef|
114
+ pos[fname] = count
115
+ count += fdef.length + 1
116
+ end
117
+ pos
118
+ end
119
+
120
+ def output
121
+ result = []
122
+ @asm.each do |fname, fdef|
123
+ fdef.each do |instr|
124
+ params = instr.values[0]
125
+ if instr.keys[0] == 'call'
126
+ result << { 'call' => [ positions[params[0]] ] }
127
+ else
128
+ result << instr
129
+ end
130
+ end
131
+ result << { 'return' => [] }
132
+ end
133
+ result
134
+ end
135
+ end
136
+
137
+ # compiler
138
+ class Compiler
139
+ def initialize(desc)
140
+ @desc = desc
141
+ end
142
+
143
+ def functions
144
+ result = {}
145
+ @desc['formats'].each do |name, info|
146
+ result["alloc_#{name}"] = [
147
+ { 'alloc' => [name, 'reg_a'] }
148
+ ]
149
+
150
+ init_instrs = []
151
+ read_instrs = []
152
+ write_instrs = []
153
+
154
+ info['fields'].each do |field_info|
155
+ read_func = "read_#{name}_#{field_info['name']}"
156
+ write_func = "write_#{name}_#{field_info['name']}"
157
+
158
+ result[read_func] = [
159
+ { 'index' => ['reg_a', 'simple.number', 1] },
160
+ { 'read_bytes' => [1, 'reg_dev'] }
161
+ ]
162
+
163
+ result[write_func] = [
164
+ { 'index' => ['reg_a', 'simple.number', 1] },
165
+ { 'write_bytes' => [1, 'reg_dev'] }
166
+ ]
167
+
168
+ init_instrs += [
169
+ { 'index' => ['reg_a', 'simple.number', 1] },
170
+ { 'set' => ['reg_dev', 0] }
171
+ ]
172
+
173
+ read_instrs << { 'call' => [read_func] }
174
+ write_instrs << { 'call' => [write_func] }
175
+ end
176
+
177
+ result["init_#{name}"] = init_instrs
178
+ result["read_#{name}"] = read_instrs
179
+ result["write_#{name}"] = write_instrs
180
+ end
181
+ result
182
+ end
183
+
184
+ def output
185
+ {
186
+ 'functions' => functions
187
+ }
188
+ end
189
+ end
190
+ end
191
+
192
+ RSpec.describe Binrip do
193
+ it 'has a version number' do
194
+ expect(Binrip::VERSION).not_to be nil
195
+ end
196
+ end
197
+
198
+ RSpec.describe Binrip::Compiler do
199
+ it 'compiles a description to read and write' do
200
+
201
+ yaml = <<~YAML
202
+ formats:
203
+ simple:
204
+ fields:
205
+ - name: count
206
+ type: int8
207
+ YAML
208
+ compiler = Binrip::Compiler.new(YAML.load(yaml))
209
+ expect(compiler.output).to eq YAML.load(<<~YAML)
210
+ functions:
211
+ alloc_simple:
212
+ - alloc: [simple, reg_a]
213
+
214
+ init_simple:
215
+ - index: [reg_a, simple.number, 1]
216
+ - set: [reg_dev, 0]
217
+
218
+ read_simple:
219
+ - call: [read_simple_count]
220
+
221
+ read_simple_count:
222
+ - index: [reg_a, simple.number, 1]
223
+ - read_bytes: [1, reg_dev]
224
+
225
+ write_simple:
226
+ - call: [write_simple_count]
227
+
228
+ write_simple_count:
229
+ - index: [reg_a, simple.number, 1]
230
+ - write_bytes: [1, reg_dev]
231
+ YAML
232
+ end
233
+ end
234
+
235
+ RSpec.describe Binrip::Linker do
236
+ it 'assembles compiler output to a string of instructions' do
237
+ compiler_output = YAML.load(<<~YAML)
238
+ ---
239
+ main:
240
+ - set: [reg_a, 2]
241
+ - call: [a_function]
242
+ - inc: [reg_a, 3]
243
+
244
+ a_function:
245
+ - inc: [reg_a, 1]
246
+ YAML
247
+
248
+ linker = Binrip::Linker.new(compiler_output)
249
+
250
+ expect(linker.output).to eq YAML.load(<<~YAML)
251
+ - set: [reg_a, 2] # 0 main
252
+ - call: [4] # 1 call a_function
253
+ - inc: [reg_a, 3] # 2
254
+ - return: [] # 3
255
+ - inc: [reg_a, 1] # 4 a_function
256
+ - return: [] # 5 ret
257
+ YAML
258
+ end
259
+ end
260
+
261
+ RSpec.describe Binrip::Interpreter do
262
+ it 'interprets a simple set of instructions' do
263
+ instructions = YAML.load(<<~YAML)
264
+ - set: [reg_a, 2]
265
+ - set: [reg_b, 3]
266
+ - set: [reg_c, 4]
267
+ YAML
268
+
269
+ d = Binrip::Device.new
270
+
271
+ machine = Binrip::Interpreter.new(instructions, d)
272
+
273
+ loop do
274
+ machine.step!
275
+ break if machine.halted?
276
+ end
277
+
278
+ expect(machine.error).to be_nil
279
+ expect(machine.register_value(:a)).to eq 2
280
+ expect(machine.register_value(:b)).to eq 3
281
+ expect(machine.register_value(:c)).to eq 4
282
+ end
283
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/setup'
4
+ require 'binrip'
5
+
6
+ RSpec.configure do |config|
7
+ # Enable flags like --only-failures and --next-failure
8
+ config.example_status_persistence_file_path = '.rspec_status'
9
+
10
+ # Disable RSpec exposing methods globally on `Module` and `main`
11
+ config.disable_monkey_patching!
12
+
13
+ config.expect_with :rspec do |c|
14
+ c.syntax = :expect
15
+ end
16
+ end
metadata ADDED
@@ -0,0 +1,128 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: binrip
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - David Siaw
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2020-05-29 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activesupport
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: optimist
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: sinatra
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: 2.0.3
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 2.0.3
55
+ - !ruby/object:Gem::Dependency
56
+ name: bundler
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '1.9'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '1.9'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rspec
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ description: Ripper of binary files
84
+ email:
85
+ - davidsiaw@gmail.com
86
+ executables: []
87
+ extensions: []
88
+ extra_rdoc_files: []
89
+ files:
90
+ - Gemfile
91
+ - bin/console
92
+ - bin/setup
93
+ - binrip.gemspec
94
+ - lib/binrip.rb
95
+ - lib/binrip/version.rb
96
+ - spec/binrip_spec.rb
97
+ - spec/spec_helper.rb
98
+ homepage: https://github.com/davidsiaw/binrip
99
+ licenses:
100
+ - MIT
101
+ metadata:
102
+ homepage_uri: https://github.com/davidsiaw/binrip
103
+ source_code_uri: https://github.com/davidsiaw/binrip
104
+ changelog_uri: https://github.com/davidsiaw/binrip
105
+ allowed_push_host: https://rubygems.org
106
+ post_install_message:
107
+ rdoc_options: []
108
+ require_paths:
109
+ - lib
110
+ required_ruby_version: !ruby/object:Gem::Requirement
111
+ requirements:
112
+ - - ">="
113
+ - !ruby/object:Gem::Version
114
+ version: '0'
115
+ required_rubygems_version: !ruby/object:Gem::Requirement
116
+ requirements:
117
+ - - ">="
118
+ - !ruby/object:Gem::Version
119
+ version: '0'
120
+ requirements: []
121
+ rubyforge_project:
122
+ rubygems_version: 2.7.8
123
+ signing_key:
124
+ specification_version: 4
125
+ summary: Binary file format language
126
+ test_files:
127
+ - spec/binrip_spec.rb
128
+ - spec/spec_helper.rb