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/.gitignore +17 -0
- data/.rspec +2 -0
- data/.travis.yml +5 -0
- data/Gemfile +8 -0
- data/Gemfile.ci +7 -0
- data/LICENSE +674 -0
- data/README.md +5 -0
- data/Rakefile +9 -0
- data/indis-arm.gemspec +22 -0
- data/lib/indis-arm/analyzer/bl_analyzer.rb +20 -0
- data/lib/indis-arm/analyzer/ldr_lit_analyzer.rb +25 -0
- data/lib/indis-arm/analyzer.rb +17 -0
- data/lib/indis-arm/arm7.inst.rb +415 -0
- data/lib/indis-arm/code_parser.rb +109 -0
- data/lib/indis-arm/cpu_state.rb +34 -0
- data/lib/indis-arm/instruction.rb +107 -0
- data/lib/indis-arm/instruction_helper.rb +156 -0
- data/lib/indis-arm/instruction_loader.rb +160 -0
- data/lib/indis-arm/version.rb +23 -0
- data/lib/indis-arm.rb +28 -0
- data/spec/fixtures/single-object.o +0 -0
- data/spec/indis-arm/code_parser_spec.rb +48 -0
- data/spec/indis-arm/instruction_helper_spec.rb +29 -0
- data/spec/indis-arm/instruction_loader_spec.rb +76 -0
- data/spec/spec_helper.rb +8 -0
- metadata +125 -0
data/Rakefile
ADDED
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
|