indis-arm 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,107 @@
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 'ostruct'
20
+ require 'indis-arm/instruction_helper'
21
+ require 'indis-core/entity'
22
+
23
+ module Indis
24
+ module ARM
25
+
26
+ # ARM::Instruction is a code {Indis::Entity entity} that represens an ARM
27
+ # instruction
28
+ class Instruction < Indis::Entity
29
+ # Instructions can have different value formats. In such a case, +value_format+
30
+ # specifies the format to use
31
+ # @return [Symbol]
32
+ attr_accessor :value_format
33
+
34
+ # @param [Fixnum] vmaddr virtual address
35
+ # @param [Fixnum] bytes bytes that represent an instruction
36
+ def initialize(vmaddr, bytes)
37
+ super vmaddr
38
+ @size = 4
39
+ m = self.class.kmap(bytes)
40
+ self.class.process_automap.each { |p| self.instance_exec(m, &p) } if self.class.process_automap
41
+ self.instance_exec(m, &self.class.process_block) if self.class.process_block
42
+ end
43
+
44
+ # @return [Indis::ARM::InstructionHelper] helper that provides common methods for DSL
45
+ def h
46
+ InstructionHelper
47
+ end
48
+
49
+ def to_s
50
+ s = self.instance_eval "\"#{self.class.formats[:operator]}\""
51
+ if @value_format
52
+ fmt = self.class.formats[@value_format]
53
+ v = self.instance_eval "\"#{fmt}\""
54
+ else
55
+ v = self.instance_eval "\"#{self.class.formats[:value]}\"" if self.class.formats[:value]
56
+ end
57
+ s = "#{s}\t#{v}" if v
58
+ s
59
+ end
60
+
61
+ class << self
62
+ attr_reader :name # @return [String] instruction name
63
+
64
+ attr_reader :encoding # @return [String] instruction encoding per ARMARM
65
+
66
+ attr_reader :process_block # @return [Proc] data-processing proc
67
+
68
+ attr_reader :formats # @return [Hash] output formats
69
+
70
+ attr_reader :process_automap # @return [Array] a list of automapping procs
71
+
72
+ # @return [String] instruction mask bits
73
+ def bits_mask
74
+ @bits.gsub('0', '1').gsub(/[^1]/, '0').to_i(2)
75
+ end
76
+
77
+ # @return [String] instruction matching bits
78
+ def bits_match
79
+ @bits.gsub(/[^01]/, '0').to_i(2)
80
+ end
81
+
82
+ # @return [OpenStruct] a map of known fields to instruction value
83
+ def kmap(v)
84
+ return OpenStruct.new unless @kmap
85
+
86
+ map = @kmap.inject({}) do |map, (m, o, n)|
87
+ map[n] = (v & m) >> o
88
+ map
89
+ end
90
+ OpenStruct.new(map)
91
+ end
92
+ end
93
+ end
94
+
95
+ # UnknownInstruction represents an unknown (not yet mapped in DSL) instruction
96
+ class UnknownInstruction < Instruction
97
+ def initialize(vmaddr, bytes)
98
+ super
99
+ @val = bytes
100
+ end
101
+
102
+ def to_s
103
+ "UNK\t#{@val.to_s(16).upcase}"
104
+ end
105
+ end
106
+ end
107
+ end
@@ -0,0 +1,156 @@
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-core/binaryops_string'
20
+
21
+ module Indis
22
+ module ARM
23
+ module PseudoCodeInstructionHelper
24
+ def ARMExpandImm(bits_imm12) # A5.2.4
25
+ ARMExpandImm_C(bits_imm12, 0)[0] # FIXME APSR.C ???
26
+ end
27
+
28
+ def ARMExpandImm_C(bits_imm12, carry_in) # A5.2.4
29
+ unrotated_value = bits_imm12.bits(7, 0).zero_extend(32)
30
+ Shift_C(unrotated_value, :SRType_ROR, 2*(bits_imm12.bits(11, 8).to_i), carry_in)
31
+ end
32
+
33
+ def DecodeImmShift(bits2_type, bits5_imm5)
34
+ imm = bits5_imm5.to_i
35
+ case bits2_type.to_i
36
+ when 0b00
37
+ [:SRType_LSL, imm]
38
+ when 0b01
39
+ [:SRType_LSR, imm == 0 ? 32 : imm]
40
+ when 0b10
41
+ [:SRType_ASR, imm == 0 ? 32 : imm]
42
+ when 0b11
43
+ imm == 0 ? [:SRType_RRX, 1] : [:SRType_ROR, imm]
44
+ end
45
+ end
46
+
47
+ def ZeroExtend(bits_x, i) # P5.3
48
+ bits_x.zero_extend(i)
49
+ end
50
+
51
+ def SignExtend(bits_x, i) # P5.3
52
+ bits_x.sign_extend(i)
53
+ end
54
+
55
+ def Shift_C(bits_value, type, amount, carry_in) # A8.4.3
56
+ raise ArgumentError unless !(type == :SRType_RRX && amount != 1)
57
+
58
+ return [bits_value, carry_in] if amount == 0
59
+
60
+ case type
61
+ when :SRType_LSL
62
+ LSL_C(bits_value, amount)
63
+ when :SRType_LSR
64
+ LSR_C(bits_value, amount)
65
+ when :SRType_ASR
66
+ ASR_C(bits_value, amount)
67
+ when :SRType_ROR
68
+ ROR_C(bits_value, amount)
69
+ when :SRType_RRX
70
+ RRX_C(bits_value, carry_in)
71
+ end
72
+ end
73
+
74
+ def ROR_C(bits_x, shift) # A2.2.1
75
+ raise ArgumentError unless shift != 0
76
+
77
+ [bits_x.ror(shift), bits_x.rbit(0)]
78
+ end
79
+
80
+ def LSR(bits_x, shift) # A2.2.1
81
+ raise ArgumentError unless shift >= 0
82
+ bits_x >> shift
83
+ end
84
+
85
+ def LSR_C(bits_x, shift) # A2.2.1
86
+ raise ArgumentError unless shift > 0
87
+ [bits_x >> shift, bits_x.bit(shift-1)]
88
+ end
89
+
90
+ def LSL(bits_x, shift) # A2.2.1
91
+ raise ArgumentError unless shift >= 0
92
+ bits_x << shift
93
+ end
94
+
95
+ def LSL_C(bits_x, shift) # A2.2.1
96
+ raise ArgumentError unless shift > 0
97
+ [bits_x << shift, bits_x.bit(shift)]
98
+ end
99
+ end
100
+
101
+ module InstructionHelper
102
+ class << self
103
+ COND = [".EQ", ".NE", ".CS", ".CC", ".MI", ".PL", ".VS", ".VC", ".HI", ".LS", ".GE", ".LT", ".GT", ".LE", ""]
104
+ COND_SYM = [:eq, :ne, :cs, :cc, :mi, :pl, :vs, :vc, :hi, :ls, :ge, :lt, :gt, :le, :al]
105
+ NAMED_REG = { r13: :sp, r14: :lr, r15: :pc }
106
+ REG = [:r0, :r1, :r2, :r3, :r4, :r5, :r6, :r7, :r8, :r9, :r10, :r11, :r12, :r13, :r14, :r15]
107
+ SHIFT_TYPES = {
108
+ SRType_LSL: :lsl,
109
+ SRType_LSR: :lsr,
110
+ SRType_ASR: :asr,
111
+ SRType_ROR: :ror,
112
+ SRType_RRX: :rrx,
113
+ }
114
+
115
+ def regs_from_bits(bits_list)
116
+ bl = bits_list.to_s(2)
117
+ bl = ('0'*(16-bl.length)) + bl
118
+ regs = []
119
+ bl.reverse! # XXX so that r0 is bit 0
120
+ bl.length.times do |i|
121
+ regs << "r#{i}".to_sym if bl[i] == '1'
122
+ end
123
+ regs
124
+ end
125
+
126
+ def shift_type_to_s(shift)
127
+ SHIFT_TYPES[shift]
128
+ end
129
+
130
+ def cond_to_s(cond)
131
+ ('.' + cond.to_s.upcase).sub('.AL', '')
132
+ end
133
+
134
+ def regs_to_s(regs)
135
+ regs = regs.map { |r| NAMED_REG[r] || r }
136
+ regs.join(', ')
137
+ end
138
+
139
+ def flag(f, fn)
140
+ f ? fn : ''
141
+ end
142
+
143
+ def reg(i)
144
+ r = REG[i]
145
+ NAMED_REG[r] || r
146
+ end
147
+
148
+ def cond(i)
149
+ COND_SYM[i]
150
+ end
151
+
152
+ include PseudoCodeInstructionHelper
153
+ end
154
+ end
155
+ end
156
+ end
@@ -0,0 +1,160 @@
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 'singleton'
20
+ require 'indis-arm/instruction'
21
+
22
+ module Indis
23
+ module ARM
24
+
25
+ class NotThisInstructionError < RuntimeError; end
26
+ class UnpredictableError < RuntimeError; end
27
+
28
+ # InstructionLoader is a DSL parser for arm7.inst.rb DSL.
29
+ # The DSL is evaluated in the context of InstructionLoader singleton, the
30
+ # only top-level command is {Indis::ARM::InstructionLoader#instruction}
31
+ class InstructionLoader
32
+ include Singleton
33
+
34
+ # Loads and processes the DSL
35
+ # @return [Array] all mapped classes from DSL
36
+ def load
37
+ return @classes if @classes
38
+
39
+ @classes = []
40
+ instr_file = File.join(File.dirname(__FILE__), 'arm7.inst.rb')
41
+ self.instance_eval open(instr_file).read, instr_file, 1
42
+
43
+ @classes
44
+ end
45
+
46
+ # Loads a named instruction. The block is evaluated in a context of
47
+ # newly-created {Indis::ARM::EncodingLoader}.
48
+ # @param [Symbol] name instruction name
49
+ def instruction(name, &block)
50
+ el = EncodingLoader.new(name, @classes)
51
+ el.instance_eval(&block)
52
+ end
53
+ end
54
+
55
+ class EncodingLoader
56
+ def initialize(name, arr)
57
+ @name = name
58
+ @classes = arr
59
+ end
60
+
61
+ # Loads a specific instruction encoding. The block is evaluated in a
62
+ # context of newly-created {Indis::ARM::MnemonicLoader}.
63
+ # @param [Symbol] enc instruction encoding name
64
+ def encoding(enc, &block)
65
+ unless block_given?
66
+ #puts "Encoding #{enc} of #{@name} is undefined yet"
67
+ return
68
+ end
69
+
70
+ name = @name
71
+ klass = Class.new(Indis::ARM::Instruction) { @name = name; @encoding = enc }
72
+ ARM.const_set("#{name}Instruction_#{enc}", klass)
73
+
74
+ ml = MnemonicLoader.new(klass)
75
+ ml.instance_eval(&block)
76
+
77
+ @classes << klass
78
+ end
79
+ end
80
+
81
+ class MnemonicLoader
82
+ # A default map. Would set up the mapping only if the attribute name
83
+ # was passed in {Indis::ARM::MnemonicLoader#attrs}
84
+ AUTOMAPPED = {
85
+ 'C' => :cond,
86
+ 'n' => :Rn,
87
+ 'm' => :Rm,
88
+ 'd' => :Rd,
89
+ 't' => :Rt,
90
+ 'S' => :setflags,
91
+ }
92
+
93
+ AUTOMAPPED_PROCS = {
94
+ cond: proc { |k| @cond = h.cond(k.cond) },
95
+ Rn: proc { |k| @Rn = h.reg(k.Rn) },
96
+ Rm: proc { |k| @Rm = h.reg(k.Rm) },
97
+ Rd: proc { |k| @Rd = h.reg(k.Rd) },
98
+ Rt: proc { |k| @Rt = h.reg(k.Rt) },
99
+ setflags: proc { |k| @setflags = k.setflags == 1 },
100
+ }
101
+
102
+ def initialize(klass)
103
+ @klass = klass
104
+ end
105
+
106
+ # Loads bit representation of instruction
107
+ # @overload bits(bitstring)
108
+ # @param [String] bitstring a string with no special-mapped bits (either no specail bits at all, or all bits are automapped)
109
+ # @overload bits(bitstring, map)
110
+ # @param [String] bitstring a string with bits map
111
+ # @param [Hash{String => Symbol}] map a map from bit string to parsed symbol
112
+ def bits(*args)
113
+ raise "Malformed bits field" if args.length < 1 || args.length > 2
114
+ b = args.first
115
+ @klass.instance_eval { @bits = b }
116
+
117
+ map = {}
118
+ AUTOMAPPED.each { |k,v| map[k] = v if @klass_attrs.include?(v) }
119
+ map.merge!(args[1]) if args.length == 2
120
+
121
+ a = map.map do |v, name|
122
+ # TODO: chek on what happens if there is no cond 'C'
123
+ mask = b.gsub(Regexp.new("[^#{v}]"), '0').gsub(/[^0]/, "1")
124
+ ofs = mask.match(/0*$/)[0].length
125
+ mask = mask.to_i(2)
126
+
127
+ [mask, ofs, name]
128
+ end
129
+
130
+ @klass.instance_eval { @kmap = a }
131
+ end
132
+
133
+ # Loads instruction attributes
134
+ def attrs(*attrs)
135
+ @klass_attrs = attrs
136
+ @klass.instance_eval { attr_reader *attrs }
137
+ end
138
+
139
+ # Loads instruction format
140
+ def format(fmt)
141
+ if @klass_attrs.include?(:setflags)
142
+ formats = { operator: '#{self.class.name}#{h.flag @setflags, "S"}#{h.cond_to_s(@cond)}' }
143
+ else
144
+ formats = { operator: '#{self.class.name}#{h.cond_to_s(@cond)}' }
145
+ end
146
+ formats.merge!(fmt)
147
+ @klass.instance_eval { @formats = formats }
148
+ end
149
+
150
+ # Loads instruction processing block
151
+ def process(&block)
152
+ automap_keys = @klass_attrs & AUTOMAPPED.values
153
+ automap_proc = AUTOMAPPED_PROCS.map { |k,p| automap_keys.include?(k) ? p : nil }.compact
154
+ @klass.instance_eval { @process_automap = automap_proc }
155
+ @klass.instance_eval { @process_block = block }
156
+ end
157
+ end
158
+
159
+ end
160
+ end
@@ -0,0 +1,23 @@
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
+ VERSION = "0.3.0"
22
+ end
23
+ end
data/lib/indis-arm.rb ADDED
@@ -0,0 +1,28 @@
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/version'
20
+ require 'indis-arm/code_parser'
21
+ require 'indis-arm/analyzer'
22
+
23
+ module Indis
24
+ # Indis::ARM provides instruction parser for ARM and Thumb instruction sets.
25
+ module ARM
26
+
27
+ end
28
+ end
Binary file
@@ -0,0 +1,48 @@
1
+ require 'indis-core/target'
2
+ require 'indis-macho'
3
+ require 'indis-arm/code_parser'
4
+
5
+ describe Indis::ARM::CodeParser do
6
+ it "should decode arm instructions in given section" do
7
+ t = Indis::Target.new('spec/fixtures/single-object.o')
8
+ t.load
9
+
10
+ section = t.segments.find { |seg| seg.name == '__TEXT' }.sections.find { |sect| sect.name == '__text' }
11
+
12
+ code_parser = Indis::ARM::CodeParser.new(t)
13
+
14
+ code_parser.reparse_section(section)
15
+
16
+ sm = t.vmmap[section.to_vmrange]
17
+
18
+ sm.each_with_index do |b, idx|
19
+ break if idx >= section.vmsize
20
+
21
+ if idx % 4 == 0
22
+ b.should be_a(Indis::Entity)
23
+ b.should be_a(Indis::ARM::Instruction)
24
+ else
25
+ b.should be_nil
26
+ end
27
+ end
28
+ end
29
+
30
+ it "should parse known instructions" do
31
+ code_parser = Indis::ARM::CodeParser.new(double("Target", vmmap: double("VMMap")))
32
+
33
+ i = code_parser.instance_eval { build_instruction(0, 0xe92d4080) }
34
+ i.should_not be_a(Indis::ARM::UnknownInstruction)
35
+ end
36
+
37
+ it "should load instructions" do
38
+ Indis::ARM::CodeParser.load_instructions
39
+ expect { Indis::ARM.const_get('PUSHInstruction_A1') }.not_to raise_error
40
+ end
41
+
42
+ it "should honor NotThisInstructionError" do
43
+ code_parser = Indis::ARM::CodeParser.new(double("Target", vmmap: double("VMMap")))
44
+
45
+ i = code_parser.instance_eval { build_instruction(0, 0xe59f0024) }
46
+ i.class.should == Indis::ARM::LDRInstruction_A1_lit
47
+ end
48
+ end
@@ -0,0 +1,29 @@
1
+ require 'indis-arm/instruction_helper'
2
+
3
+ describe Indis::ARM::InstructionHelper do
4
+ it "should decode registers" do
5
+ b = '0000111100000010'.reverse.to_i(2)
6
+ r = Indis::ARM::InstructionHelper.regs_from_bits(b)
7
+ r.should == [:r4, :r5, :r6, :r7, :r14]
8
+ end
9
+ end
10
+
11
+ describe Indis::ARM::PseudoCodeInstructionHelper do
12
+ it "should perform ZeroExtend" do
13
+ Indis::ARM::InstructionHelper.ZeroExtend('1101'.to_bo, 6).to_s.should == '001101'
14
+ end
15
+
16
+ it "should perform LSR" do
17
+ a = Indis::ARM::InstructionHelper.LSR_C('101100'.to_bo, 3)
18
+ a[0].to_s.should == '000101'
19
+ a[1].should == 1
20
+ end
21
+
22
+ it "should perform Shift_C" do
23
+ Indis::ARM::InstructionHelper.Shift_C('101100'.to_bo, :SRType_ROR, 2, 0).map{|v|v.to_s}.should == ['001011', '1']
24
+ end
25
+
26
+ it "should perform ARMExpandImm_C" do
27
+ Indis::ARM::InstructionHelper.ARMExpandImm('000000001100'.to_bo).to_i.should == 12
28
+ end
29
+ end
@@ -0,0 +1,76 @@
1
+ require 'indis-arm/instruction_loader'
2
+
3
+ describe Indis::ARM::InstructionLoader do
4
+ before(:all) { Indis::ARM::InstructionLoader.instance.load }
5
+
6
+ it "should load instructions" do
7
+ expect { Indis::ARM.const_get('PUSHInstruction_A1') }.not_to raise_error
8
+ end
9
+
10
+ it "should parse bitmap to mask and match" do
11
+ Indis::ARM::PUSHInstruction_A1.bits_mask.should == 0xfff0000
12
+ Indis::ARM::PUSHInstruction_A1.bits_match.should == 0x92d0000
13
+ end
14
+
15
+ it "should create attr_readers for fields" do
16
+ i = Indis::ARM::PUSHInstruction_A1.new(0, 0xe92d4080)
17
+ expect { i.regs }.not_to raise_error(NoMethodError)
18
+ end
19
+
20
+ it "should make a keymap for passed values" do
21
+ m = Indis::ARM::PUSHInstruction_A1.kmap(0xe92d4080)
22
+ m.cond.should == 0xe
23
+ m.regs_list.should == 0x4080
24
+ end
25
+
26
+ it "should eval process block and set ivars" do
27
+ i = Indis::ARM::PUSHInstruction_A1.new(0, 0xe92d4080)
28
+ i.regs.should == [:r7, :r14]
29
+ end
30
+
31
+ it "should set instruction name" do
32
+ Indis::ARM::PUSHInstruction_A1.name.should == :PUSH
33
+ end
34
+
35
+ it "should set instruction encoding" do
36
+ Indis::ARM::PUSHInstruction_A1.encoding.should == :A1
37
+ end
38
+
39
+ it "should raise NotThisInstructionError if the other mnemonic should be searched for" do
40
+ expect { Indis::ARM::LDRInstruction_A1_imm.new(0, 0xe59f0024) }.to raise_error(Indis::ARM::NotThisInstructionError)
41
+ end
42
+
43
+ it "should provide full mnemonic when asked to_s" do
44
+ Indis::ARM::PUSHInstruction_A1.new(0, 0xe92d4080).to_s.should == "PUSH\t{r7, lr}"
45
+ Indis::ARM::MOVInstruction_A1_reg.new(0, 0xe1a0700d).to_s.should == "MOV\tr7, sp"
46
+ Indis::ARM::SUBInstruction_A1_spimm.new(0, 0xe24dd00c).to_s.should == "SUB\tsp, sp, #12"
47
+ Indis::ARM::STRInstruction_A1_imm.new(0, 0xe5070004).to_s.should == "STR\tr0, [r7, #-4]"
48
+ Indis::ARM::STRInstruction_A1_imm.new(0, 0xe58d1004).to_s.should == "STR\tr1, [sp, #4]"
49
+ Indis::ARM::LDRInstruction_A1_imm.new(0, 0xe5171004).to_s.should == "LDR\tr1, [r7, #-4]"
50
+ Indis::ARM::LDRInstruction_A1_imm.new(0, 0xe59d2004).to_s.should == "LDR\tr2, [sp, #4]"
51
+ Indis::ARM::LDRInstruction_A1_lit.new(0, 0xe59f0024).to_s.should == "LDR\tr0, [pc, #36]"
52
+ Indis::ARM::LDRInstruction_A1_reg.new(0, 0xe79f1001).to_s.should == "LDR\tr1, [pc, r1]"
53
+ Indis::ARM::ADDInstruction_A1_imm.new(0, 0xe2804001).to_s.should == "ADD\tr4, r0, #1"
54
+ end
55
+
56
+ it "should provide cond when there is 'C' in bits" do
57
+ i = Indis::ARM::PUSHInstruction_A1.new(0, 0xe92d4080)
58
+ i.cond.should == :al
59
+ end
60
+
61
+ it "should not provide cond when there is no 'C' in bits" do
62
+ i = Indis::ARM::DMBInstruction_A1.new(0, 0xf57ff05f)
63
+ expect { i.cond }.to raise_error(NoMethodError)
64
+ end
65
+
66
+ it "should provide Rx when there are 'n', 'd', 'm' in bits" do
67
+ i = Indis::ARM::MOVInstruction_A1_reg.new(0, 0xe1a0700d)
68
+ i.Rd.should == :r7
69
+ i.Rm.should == :sp
70
+ end
71
+
72
+ it "should not provide Rx when there are no 'n', 'd', 'm' in bits" do
73
+ i = Indis::ARM::MOVInstruction_A1_reg.new(0, 0xe1a0700d)
74
+ expect { i.Rn }.to raise_error(NoMethodError)
75
+ end
76
+ end
@@ -0,0 +1,8 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+
4
+ RSpec.configure do |config|
5
+ config.treat_symbols_as_metadata_keys_with_true_values = true
6
+ config.run_all_when_everything_filtered = true
7
+ config.filter_run :focus
8
+ end