• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

SamboyCoding / Disarm / 10668496526

02 Sep 2024 01:55PM UTC coverage: 44.746% (+0.6%) from 44.151%
10668496526

push

github

SamboyCoding
Implemented some more families:

- Add/subtract imm (with tags)
- Data processing (register, 1-source)
- Add/subtract with carry
- Rotate right into flags
- Evaluate into flags
- Floating point conversion to/from fixed point

689 of 2012 branches covered (34.24%)

Branch coverage included in aggregate %.

86 of 183 new or added lines in 3 files covered. (46.99%)

3 existing lines in 2 files now uncovered.

1551 of 2994 relevant lines covered (51.8%)

102.47 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

47.87
/Disarm/InternalDisassembly/Arm64DataProcessingImmediate.cs
1
namespace Disarm.InternalDisassembly;
2

3
internal static class Arm64DataProcessingImmediate
4
{
5
    public static Arm64Instruction Disassemble(uint instruction)
6
    {
7
        //This one, at least, is mercifully simple
8
        var op0 = (instruction >> 23) & 0b111; //Bits 23-25
156✔
9
        
10
        //All 8 possible variants are defined, as 7 subcategories.
11
        return op0 switch
156!
12
        {
156✔
13
            0b000 or 0b001 => PcRelativeAddressing(instruction),
35✔
14
            0b010 => AddSubtractImmediate(instruction),
81✔
15
            0b011 => AddSubtractImmediateWithTags(instruction),
×
16
            0b100 => LogicalImmediate(instruction),
39✔
17
            0b101 => MoveWideImmediate(instruction),
×
18
            0b110 => Bitfield(instruction),
1✔
19
            0b111 => Extract(instruction),
×
20
            _ => throw new ArgumentOutOfRangeException(nameof(op0), "Impossible op0 value")
×
21
        };
156✔
22
    }
23

24
    public static Arm64Instruction PcRelativeAddressing(uint instruction)
25
    {
26
        var hasP = instruction.TestBit(31);
35✔
27
        var immlo = (instruction >> 29) & 0b11; //01
35✔
28
        var immhi = (instruction >> 5) & 0b111_1111_1111_1111_1111; //Bits 5-23, 000_0000_0100_0011_0011
35✔
29
        var rd = (int) (instruction & 0b11111);
35✔
30
        
31
        //Signed 21-bit immediate gives 2MB range, result value +/- 1MB
32
        //If ADRP, concat 12 0s on the end, giving a 33-bit value - 8GB range, +/- 4GB, 4kb aligned
33
        var immRaw = immhi << 2 | immlo;
35✔
34

35
        if (hasP)
35✔
36
            immRaw <<= 12;
35✔
37
        
38
        var imm21 = Arm64CommonUtils.CorrectSignBit(immRaw, hasP ? 33 : 21);
35!
39

40
        var mnemonic = hasP ? Arm64Mnemonic.ADRP : Arm64Mnemonic.ADR;
35!
41

42
        var regD = Arm64Register.X0 + rd;
35✔
43

44
        return new()
35✔
45
        {
35✔
46
            Mnemonic = mnemonic,
35✔
47
            Op0Kind = Arm64OperandKind.Register,
35✔
48
            Op1Kind = Arm64OperandKind.Immediate,
35✔
49
            Op0Reg = regD,
35✔
50
            Op1Imm = imm21,
35✔
51
            MnemonicCategory = Arm64MnemonicCategory.LoadAddress,
35✔
52
        };
35✔
53
    }
54

55
    public static Arm64Instruction AddSubtractImmediate(uint instruction)
56
    {
57
        var is64Bit = instruction.TestBit(31); //sf flag
81✔
58
        var isSubtract = instruction.TestBit(30); //op flag
81✔
59
        var setFlags = instruction.TestBit(29); //S flag
81✔
60
        var shiftLeftBy12 = instruction.TestBit(22);
81✔
61

62
        var imm12 = (ulong) (instruction >> 10) & 0b1111_1111_1111;
81✔
63
        var rn = (int) (instruction >> 5) & 0b1_1111;
81✔
64
        var rd = (int) instruction & 0b1_1111;
81✔
65
        
66
        if(shiftLeftBy12)
81!
67
            imm12 <<= 12;
×
68

69
        var mnemonic = isSubtract switch
81✔
70
        {
81✔
71
            true when setFlags => Arm64Mnemonic.SUBS,
44✔
72
            true => Arm64Mnemonic.SUB,
14✔
73
            false when setFlags => Arm64Mnemonic.ADDS,
52!
74
            false => Arm64Mnemonic.ADD
52✔
75
        };
81✔
76

77
        var baseReg = is64Bit ? Arm64Register.X0 : Arm64Register.W0;
81✔
78

79
        var regN = baseReg + rn;
81✔
80
        var regD = baseReg + rd;
81✔
81
        var immediate = is64Bit switch
81✔
82
        {
81✔
83
            true => imm12,
60✔
84
            false => (uint) imm12
21✔
85
        };
81✔
86

87
        return new()
81✔
88
        {
81✔
89
            Mnemonic = mnemonic,
81✔
90
            Op0Kind = Arm64OperandKind.Register,
81✔
91
            Op1Kind = Arm64OperandKind.Register,
81✔
92
            Op2Kind = Arm64OperandKind.Immediate,
81✔
93
            Op0Reg = regD,
81✔
94
            Op1Reg = regN,
81✔
95
            Op2Imm = (long)immediate,
81✔
96
            MnemonicCategory = Arm64MnemonicCategory.Math,
81✔
97
        };
81✔
98
    }
99

100
    public static Arm64Instruction AddSubtractImmediateWithTags(uint instruction)
101
    {
102
        //Technically this is all MTE extension which isn't really supported, but it's simple enough to disassemble
NEW
103
        var sf = instruction.TestBit(31);
×
NEW
104
        var s = instruction.TestBit(29);
×
NEW
105
        var o2 = instruction.TestBit(22);
×
106
        
NEW
107
        if(o2)
×
NEW
108
            throw new Arm64UndefinedInstructionException("Add/subtract immediate (with tags): o2 set");
×
109
        
NEW
110
        if(!sf)
×
NEW
111
            throw new Arm64UndefinedInstructionException("Add/subtract immediate (with tags): sf not set");
×
112
        
NEW
113
        if(s)
×
NEW
114
            throw new Arm64UndefinedInstructionException("Add/subtract immediate (with tags): S set");
×
115
        
NEW
116
        var op = instruction.TestBit(30);
×
NEW
117
        var uimm6 = (instruction >> 16) & 0b11_1111;
×
118
        var op3 = (int) (instruction >> 14) & 0b11;
NEW
119
        var uimm4 = (instruction >> 10) & 0b1111;
×
NEW
120
        var rn = (int) (instruction >> 5) & 0b1_1111;
×
NEW
121
        var rd = (int) instruction & 0b1_1111;
×
122
        
NEW
123
        var regN = Arm64Register.X0 + rn;
×
NEW
124
        var regD = Arm64Register.X0 + rd;
×
125

NEW
126
        uimm6 <<= 4; //Multiple of 16
×
127
        
128
        return new()
×
129
        {
×
NEW
130
            Mnemonic = op ? Arm64Mnemonic.SUBG : Arm64Mnemonic.ADDG,
×
131
            MnemonicCategory = Arm64MnemonicCategory.Math,
×
NEW
132
            Op0Kind = Arm64OperandKind.Register,
×
NEW
133
            Op1Kind = Arm64OperandKind.Register,
×
NEW
134
            Op2Kind = Arm64OperandKind.Immediate,
×
NEW
135
            Op3Kind = Arm64OperandKind.Immediate,
×
NEW
136
            Op0Reg = regD,
×
NEW
137
            Op1Reg = regN,
×
NEW
138
            Op2Imm = uimm6,
×
NEW
139
            Op3Imm = uimm4,
×
UNCOV
140
        };
×
141
    }
142

143
    public static Arm64Instruction LogicalImmediate(uint instruction)
144
    {
145
        var is64Bit = instruction.TestBit(31); //sf flag
39✔
146
        var opc = (instruction >> 29) & 0b11; //bits 29-30
39✔
147
        var n = instruction.TestBit(22);
39✔
148
        var immr = (byte) ((instruction >> 16) & 0b11_1111);
39✔
149
        var imms = (byte) ((instruction >> 10) & 0b11_1111);
39✔
150
        var rn = (int) (instruction >> 5) & 0b1_1111;
39✔
151
        var rd = (int) instruction & 0b1_1111;
39✔
152

153
        if (!is64Bit && n)
39!
154
            throw new Arm64UndefinedInstructionException("32-bit instruction with N flag set");
×
155

156
        var mnemonic = opc switch
39!
157
        {
39✔
158
            0b00 => Arm64Mnemonic.AND,
7✔
159
            0b01 => Arm64Mnemonic.ORR,
32✔
160
            0b10 => Arm64Mnemonic.EOR,
×
161
            0b11 => Arm64Mnemonic.ANDS,
×
162
            _ => throw new("Impossible opc value")
×
163
        };
39✔
164
        
165
        var baseReg = is64Bit ? Arm64Register.X0 : Arm64Register.W0;
39!
166
        var regN = baseReg + rn;
39✔
167
        var regD = baseReg + rd;
39✔
168

169
        var (immediate, _) = Arm64CommonUtils.DecodeBitMasks(n, is64Bit ? 64 : 32, imms, immr, true);
39!
170
        return new()
39✔
171
        {
39✔
172
            Mnemonic = mnemonic,
39✔
173
            Op0Kind = Arm64OperandKind.Register,
39✔
174
            Op1Kind = Arm64OperandKind.Register,
39✔
175
            Op2Kind = Arm64OperandKind.Immediate,
39✔
176
            Op0Reg = regD,
39✔
177
            Op1Reg = regN,
39✔
178
            Op2Imm = immediate,
39✔
179
            MnemonicCategory = Arm64MnemonicCategory.Math,
39✔
180
        };
39✔
181
    }
182

183
    public static Arm64Instruction MoveWideImmediate(uint instruction)
184
    {
185
        var is64Bit = instruction.TestBit(31);
×
186
        var opc = (instruction >> 29) & 0b11;
×
187
        var hw = (instruction >> 21) & 0b11;
×
188
        var imm16 = (instruction >> 5) & 0b1111_1111_1111_1111;
×
189
        var rd = (int) instruction & 0b1_1111;
×
190
        
191
        if(opc == 0b01)
×
192
            throw new Arm64UndefinedInstructionException("Move wide immediate with opc == 0b01");
×
193
        
194
        if(!is64Bit && hw.TestBit(1))
×
195
            throw new Arm64UndefinedInstructionException("Move wide immediate with hw bit 1 and !is64Bit");
×
196

197
        var mnemonic = opc switch
×
198
        {
×
199
            0b00 => Arm64Mnemonic.MOVN, //Move not
×
200
            0b10 => Arm64Mnemonic.MOVZ, //Move zero
×
201
            0b11 => Arm64Mnemonic.MOVK,
×
202
            _ => throw new("Impossible opc value")
×
203
        };
×
204

205
        var baseReg = is64Bit ? Arm64Register.X0 : Arm64Register.W0;
×
206
        
207
        var regD = baseReg + rd;
×
208
        var shift = (int) hw * 16;
×
209

210
        imm16 <<= shift;
×
211
        
212
        return new()
×
213
        {
×
214
            Mnemonic = mnemonic,
×
215
            Op0Kind = Arm64OperandKind.Register,
×
216
            Op1Kind = Arm64OperandKind.Immediate,
×
217
            Op0Reg = regD,
×
218
            Op1Imm = imm16,
×
219
            MnemonicCategory = Arm64MnemonicCategory.Move,
×
220
        };
×
221
    }
222

223
    public static Arm64Instruction Bitfield(uint instruction)
224
    {
225
        var is64Bit = instruction.TestBit(31);
1✔
226
        var opc = (instruction >> 29) & 0b11;
1✔
227
        var n = instruction.TestBit(22);
1✔
228
        var immr = (byte) ((instruction >> 16) & 0b11_1111);
1✔
229
        var imms = (byte) ((instruction >> 10) & 0b11_1111);
1✔
230
        var rn = (int) (instruction >> 5) & 0b1_1111;
1✔
231
        var rd = (int) instruction & 0b1_1111;
1✔
232
        
233
        if(opc == 0b11)
1!
234
            throw new Arm64UndefinedInstructionException("Bitfield with opc == 0b11");
×
235
        
236
        if(is64Bit != n)
1!
237
            throw new Arm64UndefinedInstructionException("Bitfield with is64Bit != n");
×
238

239
        var mnemonic = opc switch
1!
240
        {
1✔
241
            0b00 => Arm64Mnemonic.SBFM,
1✔
242
            0b01 => Arm64Mnemonic.BFM,
×
243
            0b10 => Arm64Mnemonic.UBFM,
×
244
            _ => throw new("Impossible opc")
×
245
        };
1✔
246
        
247
        var baseReg = is64Bit ? Arm64Register.X0 : Arm64Register.W0;
1!
248
        var regN = baseReg + rn;
1✔
249
        var regD = baseReg + rd;
1✔
250

251
        // var (wmask, tmask) = Arm64CommonUtils.DecodeBitMasks(n, is64Bit ? 64 : 32, imms, immr, false);
252

253
        return new()
1✔
254
        {
1✔
255
            Mnemonic = mnemonic,
1✔
256
            Op0Kind = Arm64OperandKind.Register,
1✔
257
            Op1Kind = Arm64OperandKind.Register,
1✔
258
            Op2Kind = Arm64OperandKind.Immediate,
1✔
259
            Op3Kind = Arm64OperandKind.Immediate,
1✔
260
            Op0Reg = regD,
1✔
261
            Op1Reg = regN,
1✔
262
            Op2Imm = immr,
1✔
263
            Op3Imm = imms,
1✔
264
            MnemonicCategory = Arm64MnemonicCategory.Move,
1✔
265
        };
1✔
266
    }
267

268
    public static Arm64Instruction Extract(uint instruction)
269
    {
270
        var sf = instruction.TestBit(31);
×
271
        var op21 = (instruction >> 29) & 0b11;
×
272
        var nFlag = instruction.TestBit(22);
×
273
        var o0 = instruction.TestBit(21);
×
274
        var rm = (int) (instruction >> 16) & 0b1_1111;
×
275
        var imms = (instruction >> 10) & 0b11_1111;
×
276
        var rn = (int) (instruction >> 5) & 0b1_1111;
×
277
        var rd = (int) instruction & 0b1_1111;
×
278
        
279
        if(op21 != 0)
×
280
            throw new Arm64UndefinedInstructionException("Extract with op21 != 0");
×
281
        
282
        if(sf != nFlag)
×
283
            throw new Arm64UndefinedInstructionException("Extract with sf != N");
×
284

285
        if(o0)
×
286
            throw new Arm64UndefinedInstructionException("Extract with o0 == 1");
×
287

288
        if (!sf && imms.TestBit(5))
×
289
            throw new Arm64UndefinedInstructionException("Extract: imms top bit can only be set if sf is also set");
×
290
        
291
        //Basically op21 and o0 must be clear, sf must be the same as N, and imms top bit must be clear if sf is clear
292
        
293
        var baseReg = sf ? Arm64Register.X0 : Arm64Register.W0;
×
294
        var regN = baseReg + rn;
×
295
        var regD = baseReg + rd;
×
296
        var regM = baseReg + rm;
×
297
        
298
        return new()
×
299
        {
×
300
            Mnemonic = Arm64Mnemonic.EXTR,
×
301
            MnemonicCategory = Arm64MnemonicCategory.Unspecified,
×
302
            Op0Kind = Arm64OperandKind.Register,
×
303
            Op1Kind = Arm64OperandKind.Register,
×
304
            Op2Kind = Arm64OperandKind.Register,
×
305
            Op3Kind = Arm64OperandKind.Immediate,
×
306
            Op0Reg = regD,
×
307
            Op1Reg = regN,
×
308
            Op2Reg = regM,
×
309
            Op3Imm = imms,
×
310
        };
×
311
    }
312
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc