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.
@@ -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