indis-arm 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
data/Rakefile ADDED
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env rake
2
+
3
+ require "bundler/gem_tasks"
4
+ Bundler::GemHelper.install_tasks
5
+
6
+ require 'rspec/core/rake_task'
7
+ RSpec::Core::RakeTask.new('spec')
8
+
9
+ task :default => :spec
data/indis-arm.gemspec ADDED
@@ -0,0 +1,22 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/indis-arm/version', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.authors = ["Vladimir Pouzanov"]
6
+ gem.email = ["farcaller@gmail.com"]
7
+ gem.description = "ARM and Thumb instruction set code parser for indis"
8
+ gem.summary = "ARM and Thumb instruction set code parser for indis"
9
+ gem.homepage = "http://www.indis.org/"
10
+ gem.license = "GPL-3"
11
+
12
+ gem.files = `git ls-files`.split($\)
13
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
14
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
15
+ gem.name = "indis-arm"
16
+ gem.require_paths = ["lib"]
17
+ gem.version = Indis::ARM::VERSION
18
+
19
+ gem.add_development_dependency 'rspec'
20
+ gem.add_development_dependency 'indis-macho', '~> 0.3.0'
21
+ gem.add_runtime_dependency 'indis-core', '~> 0.1.2'
22
+ end
@@ -0,0 +1,20 @@
1
+ module Indis
2
+ module ARM
3
+ module Analyzer
4
+
5
+ class BLAnalyzer < Analyzer
6
+
7
+ def initialize(target)
8
+ super target, :instruction_mapped
9
+ end
10
+
11
+ def instruction_mapped(instr)
12
+ return unless instr.class.name == :BL
13
+ sym = @target.resolve_symbol_at_address(instr.branch_address)
14
+ instr.tags[:branch_to_sym] = sym if sym
15
+ end
16
+ end
17
+
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,25 @@
1
+ require 'indis-core/data_entity'
2
+
3
+ module Indis
4
+ module ARM
5
+ module Analyzer
6
+
7
+ class LDRLitAnalyzer < Analyzer
8
+
9
+ def initialize(target)
10
+ super target, :instruction_mapped
11
+ end
12
+
13
+ def instruction_mapped(instr)
14
+ return unless instr.class.name == :LDR && instr.class.encoding == :A1_lit
15
+
16
+ datab = Indis::DataEntity.new(instr.vmaddr+instr.imm+8, 4, @target.vmmap)
17
+ @target.vmmap.map!(datab)
18
+ instr.tags[:value] = datab
19
+ datab.tags[:loaded_by] = instr
20
+ end
21
+ end
22
+
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,17 @@
1
+ module Indis
2
+ module ARM
3
+ module Analyzer
4
+
5
+ class Analyzer
6
+ def initialize(target, evt)
7
+ @target = target
8
+ target.subscribe_for_event(evt, self)
9
+ end
10
+ end
11
+
12
+ end
13
+ end
14
+ end
15
+
16
+ require 'indis-arm/analyzer/bl_analyzer'
17
+ require 'indis-arm/analyzer/ldr_lit_analyzer'
@@ -0,0 +1,415 @@
1
+ ##############################################################################
2
+ # Indis framework #
3
+ # Copyright (C) 2012 Vladimir "Farcaller" Pouzanov <farcaller@gmail.com> #
4
+ # #
5
+ # This program is free software: you can redistribute it and/or modify #
6
+ # it under the terms of the GNU General Public License as published by #
7
+ # the Free Software Foundation, either version 3 of the License, or #
8
+ # (at your option) any later version. #
9
+ # #
10
+ # This program is distributed in the hope that it will be useful, #
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of #
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
13
+ # GNU General Public License for more details. #
14
+ # #
15
+ # You should have received a copy of the GNU General Public License #
16
+ # along with this program. If not, see <http://www.gnu.org/licenses/>. #
17
+ ##############################################################################
18
+
19
+ instruction :ADD do # 8.8.4-11
20
+ encoding :T1_imm
21
+ encoding :T2_imm
22
+ encoding :T3_imm
23
+ encoding :T4_imm
24
+ encoding :A1_imm do
25
+ attrs :cond, :Rd, :Rn, :imm, :setflags
26
+ bits 'CCCC0010100Snnnnddddiiiiiiiiiiii', 'i' => :imm12
27
+ format value: '#{@Rd}, #{@Rn}, ##{@imm}'
28
+ process do |k|
29
+ raise Indis::ARM::NotThisInstructionError if k.Rn == 0b1111 && k.setflags == 0 # ADR
30
+ raise Indis::ARM::NotThisInstructionError if k.Rn == 0b1101 # ADD:spimm
31
+ raise Indis::ARM::NotThisInstructionError if k.Rd == 0b1111 && k.setflags == 1 # SUBS PC, LR
32
+ @imm = h.ARMExpandImm(k.imm12.to_boz(12)).to_i
33
+ end
34
+ end
35
+ encoding :T1_reg
36
+ encoding :T2_reg
37
+ encoding :A1_reg do
38
+ attrs :cond, :Rd, :Rn, :Rm, :imm, :setflags, :imm_shift
39
+ bits 'CCCC0000100SnnnnddddiiiiiTT0mmmm', 'i' => :imm5, 'T' => :type
40
+ format value: '#{@Rd}, #{@Rn}, #{@Rm}#{@imm > 0 ? ", #{h.shift_type_to_s(@imm_shift)} ##{@imm}" : "" }'
41
+ process do |k|
42
+ # FIXME: mnemonic is wrong?
43
+ raise Indis::ARM::NotThisInstructionError if k.Rd == 0b1111 && k.setflags == 1 # SUBS PC, LR
44
+ raise Indis::ARM::NotThisInstructionError if k.Rn == 0b1101 # ADD:spreg
45
+ (@imm_shift, @imm) = h.DecodeImmShift(k.type.to_bo, k.imm5.to_bo)
46
+ @imm = @imm.to_i
47
+ end
48
+ end
49
+ encoding :A1_rsr
50
+ encoding :T1_spimm
51
+ encoding :T2_spimm
52
+ encoding :T3_spimm
53
+ encoding :T4_spimm
54
+ encoding :A1_spimm do
55
+ attrs :cond, :Rd, :imm, :setflags
56
+ bits 'CCCC0010100S1101ddddiiiiiiiiiiii', 'i' => :imm12
57
+ format value: '#{@Rd}, sp, ##{@imm}'
58
+ process do |k|
59
+ raise Indis::ARM::NotThisInstructionError if k.Rd == 0b1111 && k.setflags == 1 # SUBS PC, LR
60
+ @imm = h.ARMExpandImm(k.imm12.to_boz(12)).to_i
61
+ end
62
+ end
63
+ encoding :T1_spreg
64
+ encoding :T2_spreg
65
+ encoding :T3_spreg
66
+ encoding :A1_spreg
67
+ end
68
+
69
+ instruction :B do # 8.8.18
70
+ encoding :T1
71
+ encoding :T2
72
+ encoding :T3
73
+ encoding :T4
74
+ encoding :A1 do
75
+ attrs :cond, :imm, :branch_address
76
+ bits 'CCCC1010iiiiiiiiiiiiiiiiiiiiiiii', 'i' => :imm24
77
+ format value: '##{@imm}',
78
+ value_const: '#{sprintf("0x%x", @branch_address)}'
79
+ process do |k|
80
+ @imm = h.SignExtend(k.imm24.to_boz(24) << 2, 32).to_signed_i
81
+ @value_format = :value_const
82
+ @branch_address = @vmaddr+8+@imm
83
+ end
84
+ end
85
+ end
86
+
87
+ instruction :BIC do # 8.8.21
88
+ encoding :T1_imm
89
+ encoding :A1_imm do
90
+ attrs :cond, :setflags, :Rn, :Rd, :imm
91
+ bits 'CCCC0011110Snnnnddddiiiiiiiiiiii', 'i' => :imm12
92
+ format value: '#{@Rd}, #{@Rn}, ##{@imm}'
93
+ process do |k|
94
+ (@imm, @carry) = h.ARMExpandImm_C(k.imm12.to_boz(12), 0) # TODO: APSR.C ?
95
+ @imm = @imm.to_i
96
+ end
97
+ end
98
+ encoding :T1_reg
99
+ encoding :T2_reg
100
+ encoding :A1_reg do
101
+ attrs :cond, :setflags, :Rn, :Rd, :Rm, :imm, :imm_shift
102
+ bits 'CCCC0001110SnnnnddddiiiiiTT0mmmm', 'i' => :imm5, 'T' => :type
103
+ format value: '#{@Rd}, #{@Rn}, #{@Rm}#{@imm > 0 ? ", #{h.shift_type_to_s(@imm_shift)} ##{@imm}" : "" }'
104
+ process do |k|
105
+ raise Indis::ARM::NotThisInstructionError if k.Rd = 0b1111 && k.setflags == 1 # SUBS PC, LR
106
+ (@imm_shift, @imm) = h.DecodeImmShift(k.type.to_bo, k.imm5.to_bo)
107
+ @imm = @imm.to_i
108
+ end
109
+ end
110
+ encoding :A1_rsr
111
+ end
112
+
113
+ instruction :BL do # 8.8.25
114
+ encoding :T1
115
+ encoding :T2
116
+ encoding :A1 do
117
+ attrs :cond, :imm, :target_instr_set, :branch_address
118
+ bits 'CCCC1011iiiiiiiiiiiiiiiiiiiiiiii', 'i' => :imm24
119
+ format value: '##{@imm}',
120
+ value_const: '#{sprintf("0x%x", @branch_address)}'
121
+ process do |k|
122
+ @imm = h.SignExtend(k.imm24.to_boz(24) << 2, 32).to_signed_i
123
+ @target_instr_set = :arm
124
+ @value_format = :value_const
125
+ @branch_address = @vmaddr+8+@imm
126
+ end
127
+ end
128
+ encoding :A2 do
129
+ attrs :imm, :target_instr_set, :branch_address
130
+ bits '1111101Hiiiiiiiiiiiiiiiiiiiiiiii', 'i' => :imm24, 'H' => :h
131
+ format operator: 'BLX',
132
+ value: '##{@imm}',
133
+ value_const: '#{sprintf("0x%x", @branch_address)}'
134
+ process do |k|
135
+ # FIXME what is H used for?..
136
+ @imm = h.SignExtend(k.imm24.to_boz(24) << 2, 32).to_signed_i
137
+ @target_instr_set = :thumb
138
+ @value_format = :value_const
139
+ @branch_address = @vmaddr+8+@imm
140
+ end
141
+ end
142
+ end
143
+
144
+ instruction :CMP do # 8.8.37-39
145
+ encoding :T1_imm
146
+ encoding :T2_imm
147
+ encoding :A1_imm do
148
+ attrs :cond, :Rn, :imm
149
+ bits 'CCCC00110101nnnn0000iiiiiiiiiiii', 'i' => :imm12
150
+ format value: '#{@Rn}, ##{@imm}'
151
+ process do |k|
152
+ @imm = h.ARMExpandImm(k.imm12.to_boz(12)).to_i
153
+ end
154
+ end
155
+ encoding :T1_reg
156
+ encoding :T2_reg
157
+ encoding :T3_reg
158
+ encoding :A1_reg
159
+ encoding :A1_rsr
160
+ end
161
+
162
+ instruction :DMB do # 8.8.43
163
+ encoding :T1
164
+ encoding :A1 do
165
+ attrs :option
166
+ bits '1111010101111111111100000101oooo', 'o' => :option
167
+ format value: '#{@option == :sy ? "" : "#{@option}" }'
168
+ process do |k|
169
+ @option = {
170
+ 0b1111 => :sy, 0b1110 => :st, 0b1011 => :ish, 0b1010 => :ishst,
171
+ 0b0111 => :nsh, 0b0110 => :nshst, 0b0011 => :osh, 0b0010 => :oshst,
172
+ }[k.option]
173
+ end
174
+ end
175
+ end
176
+
177
+ instruction :MOV do # 8.8.102-105
178
+ encoding :T1_imm
179
+ encoding :T2_imm
180
+ encoding :T3_imm
181
+ encoding :A1_imm do
182
+ attrs :cond, :Rd, :imm, :setflags
183
+ bits 'CCCC0011101S0000ddddiiiiiiiiiiii', 'i' => :imm12
184
+ format value: '#{@Rd}, ##{@imm}'
185
+ process do |k|
186
+ raise NotThisInstructionError if k.Rd == 0b1111 && k.setflags == 1 # SUBS PC, LR
187
+ (@imm, @carry) = h.ARMExpandImm_C(k.imm12.to_boz(12), 0) # TODO: APSR.C ?
188
+ @imm = @imm.to_i
189
+ end
190
+ end
191
+ encoding :A2_imm do
192
+ attrs :cond, :Rd, :imm
193
+ bits 'CCCC00110000jjjjddddiiiiiiiiiiii', 'i' => :imm12, 'j' => :imm4
194
+ format operator: 'MOVW#{h.cond_to_s(@cond)}',
195
+ value: '#{@Rd}, ##{@imm}'
196
+ process do |k|
197
+ @imm = h.ZeroExtend(k.imm4.to_boz(4).concat(k.imm12.to_boz(12)), 32).to_i
198
+ raise UnpredictableError if k.Rd == 15
199
+ end
200
+ end
201
+ encoding :T1_reg
202
+ encoding :T2_reg
203
+ encoding :T3_reg
204
+ encoding :A1_reg do
205
+ attrs :cond, :Rd, :Rm, :setflags
206
+ bits 'CCCC0001101S0000dddd00000000mmmm'
207
+ format value: '#{@Rd}, #{@Rm}'
208
+ process do |k|
209
+ raise Indis::ARM::NotThisInstructionError if k.Rd == 0b1111 && k.setflags == 1
210
+ end
211
+ end
212
+ end
213
+
214
+ instruction :MOVT do # 8.8.106
215
+ encoding :T1
216
+ encoding :A1 do
217
+ attrs :cond, :Rd, :imm
218
+ bits 'CCCC00110100jjjjddddiiiiiiiiiiii', 'i' => :imm12, 'j' => :imm4
219
+ format value: '#{@Rd}, ##{@imm}'
220
+ process do |k|
221
+ @imm = k.imm4.to_boz(4).concat(k.imm12.to_boz(12)).to_i
222
+ raise UnpredictableError if k.Rd == 15
223
+ end
224
+ end
225
+ end
226
+
227
+ instruction :POP do # 8.8.131-132
228
+ encoding :T1
229
+ encoding :T2
230
+ encoding :T3
231
+ encoding :A1 do
232
+ attrs :cond, :regs
233
+ bits 'CCCC100010111101rrrrrrrrrrrrrrrr', 'r' => :regs_list
234
+ format value: '{#{h.regs_to_s(@regs)}}'
235
+ process do |k|
236
+ @regs = h.regs_from_bits(k.regs_list)
237
+ raise Indis::ARM::NotThisInstructionError if @regs.length < 2
238
+ # XXX: UnalignedAllowed = FALSE;
239
+ raise UnpredictableError if @regs.include?(:sp)
240
+ end
241
+ end
242
+ encoding :A2
243
+ end
244
+
245
+ instruction :PUSH do # 8.8.133
246
+ encoding :T1
247
+ encoding :T2
248
+ encoding :T3
249
+ encoding :A1 do
250
+ attrs :cond, :regs
251
+ bits 'CCCC100100101101rrrrrrrrrrrrrrrr', 'r' => :regs_list
252
+ format value: '{#{h.regs_to_s(@regs)}}'
253
+ process do |k|
254
+ @regs = h.regs_from_bits(k.regs_list)
255
+ raise Indis::ARM::NotThisInstructionError if @regs.length < 2
256
+ end
257
+ end
258
+ encoding :A2
259
+ end
260
+
261
+ instruction :SUB do # 8.8.221-226
262
+ encoding :T1_imm
263
+ encoding :T2_imm
264
+ encoding :T3_imm
265
+ encoding :T4_imm
266
+ encoding :A1_imm
267
+ encoding :T1_reg
268
+ encoding :T2_reg
269
+ encoding :A1_reg
270
+ encoding :A1_rsr
271
+ encoding :T1_spimm
272
+ encoding :T2_spimm
273
+ encoding :T3_spimm
274
+ encoding :A1_spimm do
275
+ attrs :cond, :Rd, :imm, :setflags
276
+ bits 'CCCC0010010S1101ddddiiiiiiiiiiii', 'i' => :imm12
277
+ format value: '#{@Rd}, sp, ##{@imm}'
278
+ process do |k|
279
+ raise Indis::ARM::NotThisInstructionError if k.Rd == 0b1111 && k.setflags == 1
280
+ @imm = h.ARMExpandImm(k.imm12.to_boz(12)).to_i
281
+ end
282
+ end
283
+ encoding :T1_spreg
284
+ encoding :A1_spreg
285
+ end
286
+
287
+ instruction :STR do # 8.8.203-205
288
+ encoding :T1_imm
289
+ encoding :T2_imm
290
+ encoding :T3_imm
291
+ encoding :T4_imm
292
+ encoding :A1_imm do
293
+ attrs :cond, :Rn, :Rt, :imm, :add, :index, :wback
294
+ bits 'CCCC010PU0W0nnnnttttiiiiiiiiiiii', 'P' => :p, 'U' => :u, 'W' => :w, 'i' => :imm12
295
+ format value_offset: '#{@Rt}, [#{@Rn}#{@imm != 0 ? ", ##{@imm}" : ""}]',
296
+ value_preindexed: '#{@Rt}, [#{@Rn}, ##{@imm}]!',
297
+ value_postindexed: '#{@Rt}, [#{@Rn}], ##{@imm}'
298
+ process do |k|
299
+ raise Indis::ARM::NotThisInstructionError if k.p == 0 && k.w == 1 # STRT
300
+ raise Indis::ARM::NotThisInstructionError if k.Rn == 0b1101 && k.p == 1 && k.u == 0 && k.w == 1 && k.imm12 == 0b100 # PUSH
301
+ @index = k.p == 1
302
+ @add = k.u == 1
303
+ if @add
304
+ @imm = k.imm12 # XXX: zero_expand(32)
305
+ else
306
+ @imm = -k.imm12 # XXX: zero_expand(32)
307
+ end
308
+ @wback = (k.p == 0 || k.w == 1)
309
+ raise Indis::ARM::UnpredictableError if @wback && (k.Rn == 15 || k.Rn == k.Rt)
310
+
311
+ if @index && !@wback
312
+ @value_format = :value_offset
313
+ elsif @index && @wback
314
+ @value_format = :value_preindexed
315
+ elsif !@index && @wback
316
+ @value_format = :value_postindexed
317
+ else
318
+ raise "Unknown format combo"
319
+ end
320
+ end
321
+ end
322
+ encoding :T1_reg
323
+ encoding :T2_reg
324
+ encoding :A1_reg
325
+ end
326
+
327
+ instruction :LDR do # 8.8.62-66
328
+ encoding :T1_imm
329
+ encoding :T2_imm
330
+ encoding :T3_imm
331
+ encoding :T4_imm
332
+ encoding :A1_imm do
333
+ attrs :cond, :Rn, :Rt, :imm, :add, :index, :wback
334
+ bits 'CCCC010PU0W1nnnnttttiiiiiiiiiiii', 'P' => :p, 'U' => :u, 'W' => :w, 'i' => :imm12
335
+ format value_offset: '#{@Rt}, [#{@Rn}#{@imm != 0 ? ", ##{@imm}" : ""}]',
336
+ value_preindexed: '#{@Rt}, [#{@Rn}, ##{@imm}]!',
337
+ value_postindexed: '#{@Rt}, [#{@Rn}], ##{@imm}'
338
+ process do |k|
339
+ raise Indis::ARM::NotThisInstructionError if k.Rn == 0b1111 # LDR :A1_lit
340
+ raise Indis::ARM::NotThisInstructionError if k.p == 0 && k.w == 1 # LDRT
341
+ raise Indis::ARM::NotThisInstructionError if k.Rn == 0b1101 && k.p == 0 && k.u == 1 && k.w == 0 && k.imm12 == 0b100 # POP
342
+ @index = k.p == 1
343
+ @add = k.u == 1
344
+ if @add
345
+ @imm = k.imm12 # XXX: zero_expand(32)
346
+ else
347
+ @imm = -k.imm12 # XXX: zero_expand(32)
348
+ end
349
+ @wback = (k.p == 0 || k.w == 1)
350
+ raise Indis::ARM::UnpredictableError if @wback && (k.Rn == k.Rt)
351
+
352
+ if @index && !@wback
353
+ @value_format = :value_offset
354
+ elsif @index && @wback
355
+ @value_format = :value_preindexed
356
+ elsif !@index && @wback
357
+ @value_format = :value_postindexed
358
+ else
359
+ raise "Unknown format combo"
360
+ end
361
+ end
362
+ end
363
+ encoding :T1_lit
364
+ encoding :T2_lit
365
+ encoding :A1_lit do
366
+ attrs :cond, :Rn, :Rt, :imm, :add
367
+ bits 'CCCC0101U0011111ttttiiiiiiiiiiii', 'U' => :u, 'i' => :imm12
368
+ format value: '#{@Rt}, [#{@Rn}, ##{@imm}]',
369
+ value_const: '#{@Rt}, [#{@va+8+@imm}]',
370
+ value_xref: '#{@Rt}, =0x#{@xrefs[:value].value.to_s(16)}'
371
+ process do |k|
372
+ @Rn = :pc
373
+ @add = k.u == 1
374
+ if @add
375
+ @imm = k.imm12 # XXX: zero_expand(32)
376
+ else
377
+ @imm = -k.imm12 # XXX: zero_expand(32)
378
+ end
379
+ end
380
+ end
381
+ encoding :T1_reg
382
+ encoding :T2_reg
383
+ encoding :A1_reg do
384
+ attrs :cond, :Rn, :Rt, :Rm, :imm, :add, :index, :wback, :imm_shift
385
+ bits 'CCCC011PU0W1nnnnttttiiiiiTT0mmmm', 'P' => :p, 'U' => :u, 'W' => :w, 'i' => :imm5, 'T' => :type
386
+ format value_offset: '#{@Rt}, [#{@Rn}, #{@Rm}#{@imm != 0 ? ", ##{@imm}" : ""}]',
387
+ value_preindexed: '#{@Rt}, [#{@Rn}, #{@Rm}#{@imm != 0 ? ", ##{@imm}" : ""}]!',
388
+ value_postindexed: '#{@Rt}, [#{@Rn}], #{@Rm}#{@imm != 0 ? ", ##{@imm}" : ""}'
389
+ process do |k|
390
+ raise Indis::ARM::NotThisInstructionError if k.p == 0 && k.w == 1 # LDRT
391
+ @index = k.p == 1
392
+ @add = k.u == 1
393
+ (@imm_shift, @imm) = h.DecodeImmShift(k.type.to_bo, k.imm5.to_bo)
394
+ if @add
395
+ @imm = @imm.to_i
396
+ else
397
+ @imm = -(@imm.to_i)
398
+ end
399
+ @wback = (k.p == 0 || k.w == 1)
400
+ raise Indis::ARM::UnpredictableError if k.Rm == 15
401
+ raise Indis::ARM::UnpredictableError if @wback && (k.Rn == k.Rt)
402
+ # TODO: also raise on: if ArchVersion() < 6 && wback && m == n then UNPREDICTABLE
403
+
404
+ if @index && !@wback
405
+ @value_format = :value_offset
406
+ elsif @index && @wback
407
+ @value_format = :value_preindexed
408
+ elsif !@index && @wback
409
+ @value_format = :value_postindexed
410
+ else
411
+ raise "Unknown format combo"
412
+ end
413
+ end
414
+ end
415
+ end
@@ -0,0 +1,109 @@
1
+ ##############################################################################
2
+ # Indis framework #
3
+ # Copyright (C) 2012 Vladimir "Farcaller" Pouzanov <farcaller@gmail.com> #
4
+ # #
5
+ # This program is free software: you can redistribute it and/or modify #
6
+ # it under the terms of the GNU General Public License as published by #
7
+ # the Free Software Foundation, either version 3 of the License, or #
8
+ # (at your option) any later version. #
9
+ # #
10
+ # This program is distributed in the hope that it will be useful, #
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of #
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
13
+ # GNU General Public License for more details. #
14
+ # #
15
+ # You should have received a copy of the GNU General Public License #
16
+ # along with this program. If not, see <http://www.gnu.org/licenses/>. #
17
+ ##############################################################################
18
+
19
+ require 'indis-arm/cpu_state'
20
+ require 'indis-arm/instruction'
21
+ require 'indis-arm/instruction_loader'
22
+
23
+ module Indis
24
+ module ARM
25
+
26
+ class CodeParser
27
+ attr_accessor :endianness
28
+
29
+ def initialize(target)
30
+ @target = target
31
+ @map = target.vmmap
32
+
33
+ @endianness = :little
34
+ @state = CpuState.new
35
+ end
36
+
37
+ def reparse_section(sect)
38
+ virt_addr = sect.vmaddr
39
+ io = StringIO.new(sect.bytes)
40
+
41
+ while virt_addr < sect.vmaddr + sect.vmsize
42
+ @state.pc = virt_addr + 8 # XXX: 4 for thumb
43
+
44
+ bytes = io.read(4)
45
+
46
+ unless @map.has_unmapped(virt_addr, 4)
47
+ virt_addr += 4 # TODO: skip 2 for thumb
48
+ next
49
+ end
50
+
51
+ i = build_instruction(virt_addr, bytes.unpack('V')[0])
52
+ @map.map(i)
53
+ @target.publish_event(:instruction_mapped, i)
54
+
55
+ if i.size == 2
56
+ io.ungetbyte(bytes[2..-1])
57
+ virt_addr += 2
58
+ else
59
+ virt_addr += 4
60
+ end
61
+ end
62
+ end
63
+
64
+ def endianness=(en)
65
+ raise "Unknown endianness set" unless en == :big || en == :little
66
+ @endianness = en
67
+ end
68
+
69
+ private
70
+ def build_instruction(va, bytes)
71
+ CodeParser.instruction_masks.each do |m, arr|
72
+ instr = arr.find { |i| (bytes & m) == i.bits_match}
73
+ begin
74
+ return instr.new(va, bytes) if instr
75
+ rescue NotThisInstructionError
76
+ next
77
+ end
78
+ end
79
+ UnknownInstruction.new(va, bytes)
80
+ end
81
+
82
+ class << self
83
+ def instruction_masks
84
+ @instruction_masks = load_instructions unless @instruction_masks
85
+
86
+ @instruction_masks
87
+ end
88
+
89
+ def load_instructions
90
+ masks = {}
91
+
92
+ InstructionLoader.instance.load.each do |klass|
93
+ m = klass.bits_mask
94
+ a = masks[m]
95
+ unless a
96
+ a = []
97
+ masks[m] = a
98
+ end
99
+
100
+ a << klass
101
+ end
102
+
103
+ masks
104
+ end
105
+ end
106
+ end
107
+
108
+ end
109
+ end
@@ -0,0 +1,34 @@
1
+ ##############################################################################
2
+ # Indis framework #
3
+ # Copyright (C) 2012 Vladimir "Farcaller" Pouzanov <farcaller@gmail.com> #
4
+ # #
5
+ # This program is free software: you can redistribute it and/or modify #
6
+ # it under the terms of the GNU General Public License as published by #
7
+ # the Free Software Foundation, either version 3 of the License, or #
8
+ # (at your option) any later version. #
9
+ # #
10
+ # This program is distributed in the hope that it will be useful, #
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of #
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
13
+ # GNU General Public License for more details. #
14
+ # #
15
+ # You should have received a copy of the GNU General Public License #
16
+ # along with this program. If not, see <http://www.gnu.org/licenses/>. #
17
+ ##############################################################################
18
+
19
+ module Indis
20
+ module ARM
21
+ class CpuState
22
+ 16.times { |i| attr_accessor "r#{i}" }
23
+
24
+ alias :sp :r13
25
+ alias :sp= :r13=
26
+
27
+ alias :lr :r14
28
+ alias :lr= :r14=
29
+
30
+ alias :pc :r15
31
+ alias :pc= :r15=
32
+ end
33
+ end
34
+ end