indis-arm 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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