nexmon – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | /* |
2 | Copyright (c) 2013, Jurriaan Bremer |
||
3 | All rights reserved. |
||
4 | |||
5 | Redistribution and use in source and binary forms, with or without |
||
6 | modification, are permitted provided that the following conditions are met: |
||
7 | |||
8 | * Redistributions of source code must retain the above copyright notice, |
||
9 | this list of conditions and the following disclaimer. |
||
10 | * Redistributions in binary form must reproduce the above copyright notice, |
||
11 | this list of conditions and the following disclaimer in the documentation |
||
12 | and/or other materials provided with the distribution. |
||
13 | * Neither the name of the darm developer(s) nor the names of its |
||
14 | contributors may be used to endorse or promote products derived from this |
||
15 | software without specific prior written permission. |
||
16 | |||
17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
||
18 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
||
19 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
||
20 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE |
||
21 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
||
22 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
||
23 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
||
24 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
||
25 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
||
26 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
||
27 | POSSIBILITY OF SUCH DAMAGE. |
||
28 | */ |
||
29 | |||
30 | #include <stdio.h> |
||
31 | #include <stdint.h> |
||
32 | #include <string.h> |
||
33 | #include "darm.h" |
||
34 | #include "darm-internal.h" |
||
35 | #include "armv7-tbl.h" |
||
36 | |||
37 | #define BITMSK_12 ((1 << 12) - 1) |
||
38 | #define BITMSK_16 ((1 << 16) - 1) |
||
39 | #define BITMSK_24 ((1 << 24) - 1) |
||
40 | |||
41 | #define ROR(val, rotate) (((val) >> (rotate)) | ((val) << (32 - (rotate)))) |
||
42 | |||
43 | // the upper four bits define the rotation value, but we have to multiply the |
||
44 | // rotation value by two, so instead of right shifting by eight, we do a |
||
45 | // right shift of seven, effectively avoiding the left shift of one |
||
46 | #define ARMExpandImm(imm12) ROR((imm12) & 0xff, ((imm12) >> 7) & b11110) |
||
47 | |||
48 | static struct { |
||
49 | const char *mnemonic_extension; |
||
50 | const char *meaning_integer; |
||
51 | const char *meaning_fp; |
||
52 | } g_condition_codes[] = { |
||
53 | {"EQ", "Equal", "Equal"}, |
||
54 | {"NE", "Not equal", "Not equal, or unordered"}, |
||
55 | {"CS", "Carry Set", "Greater than, equal, or unordered"}, |
||
56 | {"CC", "Carry Clear", "Less than"}, |
||
57 | {"MI", "Minus, negative", "Less than"}, |
||
58 | {"PL", "Plus, positive or zero", "Greater than, equal, or unordered"}, |
||
59 | {"VS", "Overflow", "Unordered"}, |
||
60 | {"VC", "No overflow", "Not unordered"}, |
||
61 | {"HI", "Unsigned higher", "Greater than, unordered"}, |
||
62 | {"LS", "Unsigned lower or same", "Greater than, or unordered"}, |
||
63 | {"GE", "Signed greater than or equal", "Greater than, or unordered"}, |
||
64 | {"LT", "Signed less than", "Less than, or unordered"}, |
||
65 | {"GT", "Signed greater than", "Greater than"}, |
||
66 | {"LE", "Signed less than or equal", "Less than, equal, or unordered"}, |
||
67 | {"AL", "Always (unconditional)", "Always (unconditional)"}, |
||
68 | {"", "Unconditional", "Unconditional Instruction"}, |
||
69 | |||
70 | // alias for CS |
||
71 | {"HS", "Carry Set", "Greater than, equal, or unordered"}, |
||
72 | // alias for CC |
||
73 | {"LO", "Carry Clear", "Less than"}, |
||
74 | }; |
||
75 | |||
76 | static const char *shift_types[] = { |
||
77 | "LSL", "LSR", "ASR", "ROR", |
||
78 | }; |
||
79 | |||
80 | int darm_immshift_decode(const darm_t *d, const char **type, |
||
81 | uint32_t *immediate) |
||
82 | { |
||
83 | if(d->shift_type == S_INVLD) { |
||
84 | *type = NULL, *immediate = 0; |
||
85 | return -1; |
||
86 | } |
||
87 | else if(d->shift_type == S_ROR && d->Rs == R_INVLD && d->shift == 0) { |
||
88 | *type = "RRX", *immediate = 0; |
||
89 | } |
||
90 | else { |
||
91 | *type = darm_shift_type_name(d->shift_type); |
||
92 | *immediate = d->shift; |
||
93 | |||
94 | // 32 is encoded as 0 for immediate shifts |
||
95 | if((d->shift_type == S_LSR || d->shift_type == S_ASR) && |
||
96 | d->Rs == R_INVLD && d->shift == 0) { |
||
97 | *immediate = 32; |
||
98 | } |
||
99 | } |
||
100 | return 0; |
||
101 | } |
||
102 | |||
103 | static int armv7_disas_uncond(darm_t *d, uint32_t w) |
||
104 | { |
||
105 | d->instr_type = T_ARM_UNCOND; |
||
106 | |||
107 | // there are not a lot of unconditional instructions, so the following |
||
108 | // values are a bit hardcoded |
||
109 | switch ((w >> 25) & b111) { |
||
110 | case b000: |
||
111 | d->instr = I_SETEND; |
||
112 | d->E = (w >> 9) & 1; |
||
113 | return 0; |
||
114 | |||
115 | case b010: |
||
116 | // if the 21th bit is set, then it's one of the CLREX, DMB, DSB or ISB |
||
117 | // instructions |
||
118 | if((w >> 21) & 1) { |
||
119 | d->instr = type_uncond2_instr_lookup[(w >> 4) & b111]; |
||
120 | if(d->instr != I_INVLD) { |
||
121 | // if the instruction is either DMB, DSB or ISB, then the last |
||
122 | // four bits represent an "option" |
||
123 | if(d->instr != I_CLREX) { |
||
124 | d->option = w & b1111; |
||
125 | } |
||
126 | return 0; |
||
127 | } |
||
128 | } |
||
129 | // otherwise, if the 21th bit is not set, it's either the PLD or the |
||
130 | // PLI instruction |
||
131 | // we fall-through here, as 0b011 also handles the PLD and PLI |
||
132 | // instructions |
||
133 | |||
134 | case b011: |
||
135 | // if the 24th bit is set, then this is a PLD instruction, otherwise |
||
136 | // it's a PLI instruction |
||
137 | d->instr = (w >> 24) & 1 ? I_PLD : I_PLI; |
||
138 | |||
139 | d->Rn = (w >> 16) & b1111; |
||
140 | d->U = (w >> 23) & 1; |
||
141 | |||
142 | // if the 25th bit is set, then this instruction takes a shifted |
||
143 | // register as offset, otherwise, it takes an immediate as offset |
||
144 | if((w >> 25) & 1) { |
||
145 | d->Rm = w & b1111; |
||
146 | d->shift_type = (w >> 5) & b11; |
||
147 | d->shift = (w >> 7) & b11111; |
||
148 | } |
||
149 | else { |
||
150 | d->I = B_SET; |
||
151 | d->imm = w & BITMSK_12; |
||
152 | } |
||
153 | |||
154 | // if this instruction is PLD and the 22th bit is not set, then this |
||
155 | // is in fact PLDW |
||
156 | if(d->instr == I_PLD && ((w >> 22) & 1) == 0) { |
||
157 | d->instr = I_PLDW; |
||
158 | } |
||
159 | return 0; |
||
160 | |||
161 | case b101: |
||
162 | d->instr = I_BLX; |
||
163 | d->H = (w >> 24) & 1; |
||
164 | d->imm = w & BITMSK_24; |
||
165 | d->I = B_SET; |
||
166 | |||
167 | // check if the highest bit of the imm24 is set, if so, we |
||
168 | // manually sign-extend the integer |
||
169 | if((d->imm >> 23) & 1) { |
||
170 | d->imm = (d->imm | 0xff000000) << 2; |
||
171 | } |
||
172 | else { |
||
173 | d->imm = d->imm << 2; |
||
174 | } |
||
175 | |||
176 | // add the H bit |
||
177 | d->imm |= d->H << 1; |
||
178 | return 0; |
||
179 | |||
180 | case b111: |
||
181 | d->CRn = (w >> 16) & b1111; |
||
182 | d->coproc = (w >> 8) & b1111; |
||
183 | d->opc2 = (w >> 5) & b111; |
||
184 | d->CRm = w & b1111; |
||
185 | |||
186 | if(((w >> 4) & 1) == 0) { |
||
187 | d->instr = I_CDP2; |
||
188 | d->CRd = (w >> 12) & b1111; |
||
189 | d->opc1 = (w >> 20) & b1111; |
||
190 | } |
||
191 | else { |
||
192 | d->instr = (w >> 20) & 1 ? I_MRC2 : I_MCR2; |
||
193 | d->opc1 = (w >> 21) & b111; |
||
194 | d->Rt = (w >> 12) & b1111; |
||
195 | } |
||
196 | return 0; |
||
197 | } |
||
198 | return -1; |
||
199 | } |
||
200 | |||
201 | static int armv7_disas_cond(darm_t *d, uint32_t w) |
||
202 | { |
||
203 | // we first handle some exceptions for MUL, STR, and LDR-like |
||
204 | // instructions, which don't fit in the regular table (as they interfere |
||
205 | // with the other instructions) |
||
206 | |||
207 | // we have to check two parts of the encoded instruction, namely bits |
||
208 | // 25..27 which should be zero, and bits 4..7, of which bit 4 and bit 7 |
||
209 | // should be one |
||
210 | const uint32_t mask = (b111 << 25) | (b1001 << 4); |
||
211 | if((w & mask) == (b1001 << 4)) { |
||
212 | |||
213 | // all variants of the MUL instruction |
||
214 | if(((w >> 24) & 1) == 0 && ((w >> 4) & b1111) == b1001) { |
||
215 | |||
216 | d->instr = type_mul_instr_lookup[(w >> 21) & b111]; |
||
217 | d->instr_type = T_ARM_MUL; |
||
218 | |||
219 | // except for UMAAL and MLS, every variant takes the S bit |
||
220 | d->S = (w >> 20) & 1; |
||
221 | |||
222 | // each variant takes Rm and Rn |
||
223 | d->Rm = (w >> 8) & b1111; |
||
224 | d->Rn = w & b1111; |
||
225 | |||
226 | // if this is the UMAAL or MLS instruction *and* the S bit is set, |
||
227 | // then this is an invalid instruction |
||
228 | if((d->instr == I_UMAAL || d->instr == I_MLS) && d->S != 0) { |
||
229 | return -1; |
||
230 | } |
||
231 | |||
232 | switch ((uint32_t) d->instr) { |
||
233 | case I_MLA: case I_MLS: |
||
234 | d->Ra = (w >> 12) & b1111; |
||
235 | // fall-through |
||
236 | |||
237 | case I_MUL: |
||
238 | d->Rd = (w >> 16) & b1111; |
||
239 | break; |
||
240 | |||
241 | case I_UMAAL: case I_UMULL: case I_UMLAL: case I_SMULL: |
||
242 | case I_SMLAL: |
||
243 | d->RdHi = (w >> 16) & b1111; |
||
244 | d->RdLo = (w >> 12) & b1111; |
||
245 | break; |
||
246 | } |
||
247 | return 0; |
||
248 | } |
||
249 | else if(((w >> 24) & 1) == 0 && ((w >> 5) & b11) != 0 && |
||
250 | (w >> 21) & 1) { |
||
251 | |||
252 | // the high 2 bits are represented by the 5th and 6th bit, the |
||
253 | // lower bit is represented by the 20th bit |
||
254 | uint32_t index = ((w >> 4) & b110) | ((w >> 20) & 1); |
||
255 | d->instr = type_stack1_instr_lookup[index]; |
||
256 | if(d->instr == I_INVLD) return -1; |
||
257 | |||
258 | d->instr_type = T_ARM_STACK1; |
||
259 | d->Rn = (w >> 16) & b1111; |
||
260 | d->Rt = (w >> 12) & b1111; |
||
261 | d->P = (w >> 24) & 1; |
||
262 | d->U = (w >> 23) & 1; |
||
263 | |||
264 | // depending on the register form we either have to extract a |
||
265 | // register or an immediate |
||
266 | if(((w >> 22) & 1) == 0) { |
||
267 | d->Rm = w & b1111; |
||
268 | } |
||
269 | else { |
||
270 | // the four high bits start at bit 8, so we shift them right |
||
271 | // to their destination |
||
272 | d->imm = ((w >> 4) & b11110000) | (w & b1111); |
||
273 | d->I = B_SET; |
||
274 | } |
||
275 | return 0; |
||
276 | } |
||
277 | else if(((w >> 5) & b11) != 0 && ((w >> 20) & b10010) != b00010) { |
||
278 | |||
279 | // the high 2 bits are represented by the 5th and 6th bit, the |
||
280 | // lower bit is represented by the 20th bit |
||
281 | uint32_t index = ((w >> 4) & b110) | ((w >> 20) & 1); |
||
282 | d->instr = type_stack2_instr_lookup[index]; |
||
283 | if(d->instr == I_INVLD) return -1; |
||
284 | |||
285 | d->instr_type = T_ARM_STACK2; |
||
286 | d->Rn = (w >> 16) & b1111; |
||
287 | d->Rt = (w >> 12) & b1111; |
||
288 | d->P = (w >> 24) & 1; |
||
289 | d->U = (w >> 23) & 1; |
||
290 | d->W = (w >> 21) & 1; |
||
291 | |||
292 | // depending on the register form we either have to extract a |
||
293 | // register or an immediate |
||
294 | if(((w >> 22) & 1) == 0) { |
||
295 | d->Rm = w & b1111; |
||
296 | } |
||
297 | else { |
||
298 | // the four high bits start at bit 8, so we shift them right |
||
299 | // to their destination |
||
300 | d->imm = ((w >> 4) & b11110000) | (w & b1111); |
||
301 | d->I = B_SET; |
||
302 | } |
||
303 | return 0; |
||
304 | } |
||
305 | // synchronization primitive instructions |
||
306 | else if(((w >> 24) & 1) == 1 && ((w >> 4) & b1111) == b1001) { |
||
307 | d->instr = type_sync_instr_lookup[(w >> 20) & b1111]; |
||
308 | d->instr_type = T_ARM_SYNC; |
||
309 | d->Rn = (w >> 16) & b1111; |
||
310 | switch ((uint32_t) d->instr) { |
||
311 | case I_SWP: case I_SWPB: |
||
312 | d->B = (w >> 22) & 1; |
||
313 | d->Rt = (w >> 12) & b1111; |
||
314 | d->Rt2 = w & b1111; |
||
315 | return 0; |
||
316 | |||
317 | case I_LDREX: case I_LDREXD: case I_LDREXB: case I_LDREXH: |
||
318 | d->Rt = (w >> 12) & b1111; |
||
319 | return 0; |
||
320 | |||
321 | case I_STREX: case I_STREXD: case I_STREXB: case I_STREXH: |
||
322 | d->Rd = (w >> 12) & b1111; |
||
323 | d->Rt = w & b1111; |
||
324 | return 0; |
||
325 | } |
||
326 | } |
||
327 | } |
||
328 | // handles the STR, STRT, LDR, LDRT, STRB, STRBT, LDRB, LDRBT stack |
||
329 | // instructions, and the media instructions |
||
330 | else if(((w >> 26) & b11) == b01) { |
||
331 | |||
332 | // if both the 25th and the 4th bit are set, then this is a media |
||
333 | // instruction, which is handled in the big switch-case statement |
||
334 | const uint32_t media_mask = (1 << 25) | (1 << 4); |
||
335 | if((w & media_mask) != media_mask) { |
||
336 | d->instr = type_stack0_instr_lookup[(w >> 20) & b11111]; |
||
337 | d->instr_type = T_ARM_STACK0; |
||
338 | |||
339 | d->Rn = (w >> 16) & b1111; |
||
340 | d->Rt = (w >> 12) & b1111; |
||
341 | |||
342 | // extract some flags |
||
343 | d->P = (w >> 24) & 1; |
||
344 | d->U = (w >> 23) & 1; |
||
345 | d->W = (w >> 21) & 1; |
||
346 | |||
347 | // if the 25th bit is not set, then this instruction takes an |
||
348 | // immediate, otherwise, it takes a shifted register |
||
349 | if(((w >> 25) & 1) == 0) { |
||
350 | d->imm = w & BITMSK_12; |
||
351 | d->I = B_SET; |
||
352 | } |
||
353 | else { |
||
354 | d->shift_type = (w >> 5) & b11; |
||
355 | d->shift = (w >> 7) & b11111; |
||
356 | d->Rm = w & b1111; |
||
357 | } |
||
358 | |||
359 | // if Rn == SP and P = 1 and U = 0 and W = 1 and imm12 = 4 and |
||
360 | // this is a STR instruction, then this is a PUSH instruction |
||
361 | if(d->instr == I_STR && d->Rn == SP && d->P == 1 && d->U == 0 && |
||
362 | d->W == 1 && d->imm == 4) { |
||
363 | d->instr = I_PUSH; |
||
364 | } |
||
365 | // if Rn == SP and P = 0 and U = 1 and W = 0 and imm12 = 4 and |
||
366 | // this is a LDR instruction, then this is a POP instruction |
||
367 | else if(d->instr == I_LDR && d->Rn == SP && d->P == 0 && |
||
368 | d->U == 1 && d->W == 0 && d->imm == 4) { |
||
369 | d->instr = I_POP; |
||
370 | } |
||
371 | return 0; |
||
372 | } |
||
373 | } |
||
374 | // handle saturating addition and subtraction instructions, these |
||
375 | // instructions have various masks; of bits 20..27 bit 24 is set and bits |
||
376 | // 21..22 specify which instruction this is, furthermore, bits 4..7 |
||
377 | // represent the value 0b0101 |
||
378 | const uint32_t mask2 = (b11111001 << 20) | (b1111 << 4); |
||
379 | if((w & mask2) == ((1 << 24) | (b0101 << 4))) { |
||
380 | d->instr = type_sat_instr_lookup[(w >> 21) & b11]; |
||
381 | d->instr_type = T_ARM_SAT; |
||
382 | d->Rn = (w >> 16) & b1111; |
||
383 | d->Rd = (w >> 12) & b1111; |
||
384 | d->Rm = w & b1111; |
||
385 | return 0; |
||
386 | } |
||
387 | // handle packing, unpacking, saturation, and reversal instructions, these |
||
388 | // instructions have the 4th bit set and bits 23..27 represent 0b01101 |
||
389 | const uint32_t mask3 = (b11111 << 23) | (1 << 4); |
||
390 | if((w & mask3) == ((b01101 << 23) | (1 << 4))) { |
||
391 | // some instructions are already handled elsewhere (namely, PKH, SEL, |
||
392 | // REV, REV16, RBIT, and REVSH) |
||
393 | uint32_t op1 = (w >> 20) & b111; |
||
394 | uint32_t A = (w >> 16) & b1111; |
||
395 | uint32_t op2 = (w >> 5) & b111; |
||
396 | |||
397 | d->instr_type = T_ARM_PUSR; |
||
398 | |||
399 | // the (SX|UX)T(A)(B|H)(16) instructions |
||
400 | // op1 represents the upper three bits, and A = 0b1111 represents |
||
401 | if(op2 == b011) { |
||
402 | // the lower bit |
||
403 | d->instr = type_pusr_instr_lookup[(op1 << 1) | (A == b1111)]; |
||
404 | if(d->instr != I_INVLD) { |
||
405 | d->Rd = (w >> 12) & b1111; |
||
406 | d->Rm = w & b1111; |
||
407 | |||
408 | // rotation is shifted to the left by three, so we do this |
||
409 | // directly in our shift as well |
||
410 | d->rotate = (w >> 7) & b11000; |
||
411 | |||
412 | // if A is not 0b1111, then A represents the Rn operand |
||
413 | if(A != b1111) { |
||
414 | d->Rn = A; |
||
415 | } |
||
416 | return 0; |
||
417 | } |
||
418 | } |
||
419 | |||
420 | // SSAT |
||
421 | if((op1 & b010) == b010 && (op2 & 1) == 0) { |
||
422 | // if the upper bit is set, then it's USAT, otherwise SSAT |
||
423 | d->instr = (op1 >> 2) ? I_USAT : I_SSAT; |
||
424 | d->imm = (w >> 16) & b11111; |
||
425 | d->I = B_SET; |
||
426 | // signed saturate adds one to the immediate |
||
427 | if(d->instr == I_SSAT) { |
||
428 | d->imm++; |
||
429 | } |
||
430 | d->Rd = (w >> 12) & b1111; |
||
431 | d->shift = (w >> 7) & b11111; |
||
432 | d->shift_type = (w >> 5) & b11; |
||
433 | d->Rn = w & b1111; |
||
434 | return 0; |
||
435 | } |
||
436 | |||
437 | // SSAT16 and USAT16 |
||
438 | if((op1 == b010 || op1 == b110) && op2 == b001) { |
||
439 | d->instr = op1 == b010 ? I_SSAT16 : I_USAT16; |
||
440 | d->imm = (w >> 16) & b1111; |
||
441 | d->I = B_SET; |
||
442 | // signed saturate 16 adds one to the immediate |
||
443 | if(d->instr == I_SSAT16) { |
||
444 | d->imm++; |
||
445 | } |
||
446 | d->Rd = (w >> 12) & b1111; |
||
447 | d->Rn = w & b1111; |
||
448 | return 0; |
||
449 | } |
||
450 | } |
||
451 | |||
452 | // the instruction label |
||
453 | d->instr = armv7_instr_labels[(w >> 20) & 0xff]; |
||
454 | d->instr_type = armv7_instr_types[(w >> 20) & 0xff]; |
||
455 | |||
456 | // do a lookup for the type of instruction |
||
457 | switch ((uint32_t) d->instr_type) { |
||
458 | case T_ARM_ARITH_SHIFT: |
||
459 | d->S = (w >> 20) & 1; |
||
460 | d->Rd = (w >> 12) & b1111; |
||
461 | d->Rn = (w >> 16) & b1111; |
||
462 | d->Rm = w & b1111; |
||
463 | d->shift_type = (w >> 5) & b11; |
||
464 | |||
465 | // type == 1, shift with the value of the lower bits of Rs |
||
466 | if(((w >> 4) & 1) == B_SET) { |
||
467 | d->Rs = (w >> 8) & b1111; |
||
468 | } |
||
469 | else { |
||
470 | d->shift = (w >> 7) & b11111; |
||
471 | } |
||
472 | return 0; |
||
473 | |||
474 | case T_ARM_ARITH_IMM: |
||
475 | d->S = (w >> 20) & 1; |
||
476 | d->Rd = (w >> 12) & b1111; |
||
477 | d->Rn = (w >> 16) & b1111; |
||
478 | d->imm = ARMExpandImm(w & BITMSK_12); |
||
479 | d->I = B_SET; |
||
480 | |||
481 | // check whether this instruction is in fact an ADR instruction |
||
482 | if((d->instr == I_ADD || d->instr == I_SUB) && |
||
483 | d->S == 0 && d->Rn == PC) { |
||
484 | d->instr = I_ADR, d->Rn = R_INVLD; |
||
485 | d->U = (w >> 23) & 1; |
||
486 | } |
||
487 | return 0; |
||
488 | |||
489 | case T_ARM_BITS: |
||
490 | d->instr = type_bits_instr_lookup[(w >> 21) & b11]; |
||
491 | |||
492 | d->instr_type = T_ARM_BITS; |
||
493 | d->Rd = (w >> 12) & b1111; |
||
494 | d->Rn = w & b1111; |
||
495 | d->lsb = (w >> 7) & b11111; |
||
496 | |||
497 | // the bfi and bfc instructions specify the MSB, whereas the SBFX and |
||
498 | // UBFX instructions specify the width minus one |
||
499 | if(d->instr == I_BFI) { |
||
500 | d->width = ((w >> 16) & b11111) - d->lsb + 1; |
||
501 | |||
502 | // if Rn is 0b1111, then this is in fact the BFC instruction |
||
503 | if(d->Rn == b1111) { |
||
504 | d->Rn = R_INVLD; |
||
505 | d->instr = I_BFC; |
||
506 | } |
||
507 | } |
||
508 | else { |
||
509 | d->width = ((w >> 16) & b11111) + 1; |
||
510 | } |
||
511 | return 0; |
||
512 | |||
513 | case T_ARM_BRNCHSC: |
||
514 | d->imm = w & BITMSK_24; |
||
515 | d->I = B_SET; |
||
516 | |||
517 | // if the instruction is B or BL, then we have to sign-extend it and |
||
518 | // multiply it with four |
||
519 | if(d->instr != I_SVC) { |
||
520 | // check if the highest bit of the imm24 is set, if so, we |
||
521 | // manually sign-extend the integer |
||
522 | if((d->imm >> 23) & 1) { |
||
523 | d->imm = (d->imm | 0xff000000) << 2; |
||
524 | } |
||
525 | else { |
||
526 | d->imm = d->imm << 2; |
||
527 | } |
||
528 | } |
||
529 | return 0; |
||
530 | |||
531 | case T_ARM_BRNCHMISC: |
||
532 | // first get the real instruction label |
||
533 | d->instr = type_brnchmisc_instr_lookup[(w >> 4) & b1111]; |
||
534 | |||
535 | // now we do a switch statement based on the instruction label, |
||
536 | // rather than some magic values |
||
537 | switch ((uint32_t) d->instr) { |
||
538 | case I_BKPT: |
||
539 | d->imm = (((w >> 8) & BITMSK_12) << 4) + (w & b1111); |
||
540 | d->I = B_SET; |
||
541 | return 0; |
||
542 | |||
543 | case I_BX: case I_BXJ: case I_BLX: |
||
544 | d->Rm = w & b1111; |
||
545 | return 0; |
||
546 | |||
547 | case I_MSR: |
||
548 | d->Rn = w & b1111; |
||
549 | d->imm = (w >> 18) & b11; |
||
550 | d->I = B_SET; |
||
551 | return 0; |
||
552 | |||
553 | case I_QSUB: case I_SMLAW: case I_SMULW: default: |
||
554 | // returns -1 |
||
555 | break; |
||
556 | } |
||
557 | break; |
||
558 | |||
559 | case T_ARM_MOV_IMM: |
||
560 | d->Rd = (w >> 12) & b1111; |
||
561 | d->imm = w & BITMSK_12; |
||
562 | d->I = B_SET; |
||
563 | |||
564 | // the MOV and MVN instructions have an S bit |
||
565 | if(d->instr == I_MOV || d->instr == I_MVN) { |
||
566 | d->S = (w >> 20) & 1; |
||
567 | |||
568 | // the immediate values of the MOV and MVN instructions have to |
||
569 | // be decoded |
||
570 | d->imm = ARMExpandImm(d->imm); |
||
571 | } |
||
572 | // the MOVW and the MOVT instructions take another 4 bits of immediate |
||
573 | else { |
||
574 | d->imm |= ((w >> 16) & b1111) << 12; |
||
575 | } |
||
576 | return 0; |
||
577 | |||
578 | case T_ARM_CMP_OP: |
||
579 | d->Rn = (w >> 16) & b1111; |
||
580 | d->Rm = w & b1111; |
||
581 | d->shift_type = (w >> 5) & b11; |
||
582 | |||
583 | // type == 1, shift with the value of the lower bits of Rs |
||
584 | if(((w >> 4) & 1) == B_SET) { |
||
585 | d->Rs = (w >> 8) & b1111; |
||
586 | } |
||
587 | else { |
||
588 | d->shift = (w >> 7) & b11111; |
||
589 | } |
||
590 | return 0; |
||
591 | |||
592 | case T_ARM_CMP_IMM: |
||
593 | d->Rn = (w >> 16) & b1111; |
||
594 | d->imm = ARMExpandImm(w & BITMSK_12); |
||
595 | d->I = B_SET; |
||
596 | return 0; |
||
597 | |||
598 | case T_ARM_OPLESS: |
||
599 | d->instr = type_opless_instr_lookup[w & b111]; |
||
600 | return d->instr == I_INVLD ? -1 : 0; |
||
601 | |||
602 | case T_ARM_DST_SRC: |
||
603 | d->instr = type_shift_instr_lookup[(w >> 4) & b1111]; |
||
604 | if(d->instr == I_INVLD) return -1; |
||
605 | |||
606 | d->S = (w >> 20) & 1; |
||
607 | d->Rd = (w >> 12) & b1111; |
||
608 | d->shift_type = (w >> 5) & b11; |
||
609 | if((w >> 4) & 1) { |
||
610 | d->Rm = (w >> 8) & b1111; |
||
611 | d->Rn = w & b1111; |
||
612 | } |
||
613 | else { |
||
614 | d->Rm = w & b1111; |
||
615 | d->shift = (w >> 7) & b11111; |
||
616 | |||
617 | // if this is a LSL instruction with a zero shift, then it's |
||
618 | // actually a MOV instruction (there's no register-shifted LSL) |
||
619 | if(d->instr == I_LSL && d->shift_type == S_LSL && d->shift == 0) { |
||
620 | d->instr = I_MOV; |
||
621 | } |
||
622 | |||
623 | // if this is a ROR instruction with a zero shift, then it's |
||
624 | // actually a RRX instruction (there's no register-shifted ROR) |
||
625 | else if(d->instr == I_ROR && d->shift_type == S_ROR && |
||
626 | d->shift == 0) { |
||
627 | d->instr = I_RRX; |
||
628 | } |
||
629 | } |
||
630 | |||
631 | return 0; |
||
632 | |||
633 | case T_ARM_LDSTREGS: |
||
634 | d->W = (w >> 21) & 1; |
||
635 | d->Rn = (w >> 16) & b1111; |
||
636 | d->reglist = w & BITMSK_16; |
||
637 | |||
638 | // if this is the LDM instruction and W = 1 and Rn = SP then this is |
||
639 | // a POP instruction |
||
640 | if(d->instr == I_LDM && d->W == 1 && d->Rn == SP) { |
||
641 | d->instr = I_POP; |
||
642 | } |
||
643 | // if this is the STMDB instruction and W = 1 and Rn = SP then this is |
||
644 | // the PUSH instruction |
||
645 | else if(d->instr == I_STMDB && d->W == 1 && d->Rn == SP) { |
||
646 | d->instr = I_PUSH; |
||
647 | } |
||
648 | return 0; |
||
649 | |||
650 | case T_ARM_BITREV: |
||
651 | d->Rd = (w >> 12) & b1111; |
||
652 | d->Rm = w & b1111; |
||
653 | |||
654 | // if this is the REV16 instruction and bits 4..7 are 0b0011, then |
||
655 | // this is in fact the REV instruction |
||
656 | if(d->instr == I_REV16 && ((w >> 4) & b1111) == b0011) { |
||
657 | d->instr = I_REV; |
||
658 | } |
||
659 | // if this is the REVSH instruction and bits 4..7 are 0b0011, then |
||
660 | // this is in fact the RBIT instruction |
||
661 | else if(d->instr == I_REVSH && ((w >> 4) & b1111) == b0011) { |
||
662 | d->instr = I_RBIT; |
||
663 | } |
||
664 | return 0; |
||
665 | |||
666 | case T_ARM_MISC: |
||
667 | switch ((uint32_t) d->instr) { |
||
668 | case I_MVN: |
||
669 | d->S = (w >> 20) & 1; |
||
670 | d->Rd = (w >> 12) & b1111; |
||
671 | d->shift_type = (w >> 5) & b11; |
||
672 | d->Rm = w & b1111; |
||
673 | if(((w >> 4) & 1) == B_UNSET) { |
||
674 | d->shift = (w >> 7) & b11111; |
||
675 | } |
||
676 | else { |
||
677 | d->Rs = (w >> 8) & b1111; |
||
678 | } |
||
679 | return 0; |
||
680 | |||
681 | case I_DBG: |
||
682 | d->option = w & b1111; |
||
683 | return 0; |
||
684 | |||
685 | case I_SMC: |
||
686 | switch ((w >> 4) & b1111) { |
||
687 | // if the 7th bit is 1 and the 4th bit 0, then this is |
||
688 | // the SMUL instruction |
||
689 | case b1000: case b1010: case b1100: case b1110: |
||
690 | d->instr = I_SMUL; |
||
691 | d->instr_type = T_ARM_SM; |
||
692 | d->Rd = (w >> 16) & b1111; |
||
693 | d->Rm = (w >> 8) & b1111; |
||
694 | d->M = (w >> 6) & 1; |
||
695 | d->N = (w >> 5) & 1; |
||
696 | d->Rn = w & b1111; |
||
697 | break; |
||
698 | |||
699 | // smc |
||
700 | case b0111: |
||
701 | d->instr = I_SMC; |
||
702 | d->imm = w & b1111; |
||
703 | d->I = B_SET; |
||
704 | break; |
||
705 | |||
706 | // clz |
||
707 | case b0001: |
||
708 | d->instr = I_CLZ; |
||
709 | d->Rm = w & b1111; |
||
710 | d->Rd = (w >> 12) & b1111; |
||
711 | break; |
||
712 | |||
713 | default: |
||
714 | return -1; |
||
715 | } |
||
716 | return 0; |
||
717 | |||
718 | case I_SEL: |
||
719 | d->Rd = (w >> 12) & b1111; |
||
720 | d->Rn = (w >> 16) & b1111; |
||
721 | d->Rm = w & b1111; |
||
722 | |||
723 | // the SEL and PKH instructions share the same 8-bit identifier, |
||
724 | // if the 5th bit is set, then this is the SEL instruction, |
||
725 | // otherwise it's the PKH instruction |
||
726 | if(((w >> 5) & 1) == 0) { |
||
727 | d->instr = I_PKH; |
||
728 | d->shift_type = (w >> 5) & b10; |
||
729 | d->shift = (w >> 7) & b11111; |
||
730 | d->T = (w >> 6) & 1; |
||
731 | } |
||
732 | return 0; |
||
733 | } |
||
734 | |||
735 | case T_ARM_SM: |
||
736 | switch ((uint32_t) d->instr) { |
||
737 | case I_SMMUL: |
||
738 | d->Rd = (w >> 16) & b1111; |
||
739 | d->Ra = (w >> 12) & b1111; |
||
740 | d->Rm = (w >> 8) & b1111; |
||
741 | d->R = (w >> 5) & 1; |
||
742 | d->Rn = w & b1111; |
||
743 | |||
744 | // this can be either the SMMUL, the SMMLA, or the SMMLS |
||
745 | // instruction, depending on the 6th bit and Ra |
||
746 | if((w >> 6) & 1) { |
||
747 | d->instr = I_SMMLS; |
||
748 | } |
||
749 | // if it's SMMUL instruction, but Ra is not 0b1111, then this is |
||
750 | // the SMMLA instruction |
||
751 | else if(d->Ra != b1111) { |
||
752 | d->instr = I_SMMLA; |
||
753 | } |
||
754 | return 0; |
||
755 | |||
756 | case I_SMUSD: |
||
757 | d->Rd = (w >> 16) & b1111; |
||
758 | d->Ra = (w >> 12) & b1111; |
||
759 | d->Rm = (w >> 8) & b1111; |
||
760 | d->M = (w >> 5) & 1; |
||
761 | d->Rn = w & b1111; |
||
762 | |||
763 | // this can be either the SMLAD, the SMLSD, the SMUAD, or the |
||
764 | // SMUSD instruction, depending on the 6th bit and Ra |
||
765 | if((w >> 6) & 1 && d->Rn != b1111) { |
||
766 | d->instr = I_SMLSD; |
||
767 | } |
||
768 | else if(((w >> 6) & 1) == 0) { |
||
769 | d->instr = d->Ra == b1111 ? I_SMUAD : I_SMLAD; |
||
770 | } |
||
771 | return 0; |
||
772 | |||
773 | case I_SMLSLD: |
||
774 | d->RdHi = (w >> 16) & b1111; |
||
775 | d->RdLo = (w >> 12) & b1111; |
||
776 | d->Rm = (w >> 8) & b1111; |
||
777 | d->M = (w >> 5) & 1; |
||
778 | d->Rn = w & b1111; |
||
779 | |||
780 | // if the 6th bit is zero, then this is in fact the SMLALD |
||
781 | // instruction |
||
782 | if(((w >> 6) & 1) == 0) { |
||
783 | d->instr = I_SMLALD; |
||
784 | } |
||
785 | return 0; |
||
786 | |||
787 | case I_SMLA: |
||
788 | d->Rd = (w >> 16) & b1111; |
||
789 | d->Ra = (w >> 12) & b1111; |
||
790 | d->Rm = (w >> 8) & b1111; |
||
791 | d->M = (w >> 6) & 1; |
||
792 | d->N = (w >> 5) & 1; |
||
793 | d->Rn = w & b1111; |
||
794 | return 0; |
||
795 | |||
796 | case I_SMLAL: |
||
797 | d->RdHi = (w >> 16) & b1111; |
||
798 | d->RdLo = (w >> 12) & b1111; |
||
799 | d->Rm = (w >> 8) & b1111; |
||
800 | d->M = (w >> 6) & 1; |
||
801 | d->N = (w >> 5) & 1; |
||
802 | d->Rn = w & b1111; |
||
803 | return 0; |
||
804 | |||
805 | case I_SMUL: |
||
806 | // SMUL overlaps with SMC, so we define SMUL in SMC.. |
||
807 | break; |
||
808 | } |
||
809 | |||
810 | case T_ARM_PAS: |
||
811 | // we have a lookup table with size 64, for all parallel signed and |
||
812 | // unsigned addition and subtraction instructions |
||
813 | // the upper three bits are represented by bits 20..22, so we only |
||
814 | // right-shift those 17 bytes, the lower three bits are represented |
||
815 | // by bits 5..7 |
||
816 | d->instr = type_pas_instr_lookup[((w >> 17) & b111000) | |
||
817 | ((w >> 5) & b111)]; |
||
818 | if(d->instr == I_INVLD) return -1; |
||
819 | |||
820 | d->Rn = (w >> 16) & b1111; |
||
821 | d->Rd = (w >> 12) & b1111; |
||
822 | d->Rm = w & b1111; |
||
823 | return 0; |
||
824 | |||
825 | case T_ARM_MVCR: |
||
826 | d->CRn = (w >> 16) & b1111; |
||
827 | d->coproc = (w >> 8) & b1111; |
||
828 | d->opc2 = (w >> 5) & b111; |
||
829 | d->CRm = w & b1111; |
||
830 | |||
831 | if(((w >> 4) & 1) == 0) { |
||
832 | d->instr = I_CDP; |
||
833 | d->opc1 = (w >> 20) & b1111; |
||
834 | d->CRd = (w >> 12) & b1111; |
||
835 | } |
||
836 | else { |
||
837 | d->opc1 = (w >> 21) & b111; |
||
838 | d->Rt = (w >> 12) & b1111; |
||
839 | } |
||
840 | return 0; |
||
841 | |||
842 | case T_ARM_UDF: |
||
843 | d->I = B_SET; |
||
844 | d->imm = (w & b1111) | ((w >> 4) & (BITMSK_12 << 4)); |
||
845 | return 0; |
||
846 | } |
||
847 | return -1; |
||
848 | } |
||
849 | |||
850 | int darm_armv7_disasm(darm_t *d, uint32_t w) |
||
851 | { |
||
852 | int ret; |
||
853 | |||
854 | darm_init(d); |
||
855 | d->w = w; |
||
856 | d->cond = (w >> 28) & b1111; |
||
857 | |||
858 | if(d->cond == C_UNCOND) { |
||
859 | ret = armv7_disas_uncond(d, w); |
||
860 | } |
||
861 | else { |
||
862 | ret = armv7_disas_cond(d, w); |
||
863 | } |
||
864 | |||
865 | // return error |
||
866 | if(ret < 0) return ret; |
||
867 | |||
868 | // if the shift-type is set to S_LSL, but Rs is R_INVLD and shift is zero, |
||
869 | // then there's effectively no shift, so we set shift-type to S_INVLD |
||
870 | if(d->shift_type == S_LSL && d->Rs == R_INVLD && d->shift == 0) { |
||
871 | d->shift_type = S_INVLD; |
||
872 | } |
||
873 | |||
874 | return 0; |
||
875 | } |
||
876 | |||
877 | const char *darm_mnemonic_name(darm_instr_t instr) |
||
878 | { |
||
879 | return instr < ARRAYSIZE(darm_mnemonics) ? |
||
880 | darm_mnemonics[instr] : NULL; |
||
881 | } |
||
882 | |||
883 | const char *darm_enctype_name(darm_enctype_t enctype) |
||
884 | { |
||
885 | return enctype < ARRAYSIZE(darm_enctypes) ? |
||
886 | darm_enctypes[enctype] : NULL; |
||
887 | } |
||
888 | |||
889 | const char *darm_register_name(darm_reg_t reg) |
||
890 | { |
||
891 | return reg != R_INVLD && reg < (int32_t) ARRAYSIZE(darm_registers) ? |
||
892 | darm_registers[reg] : NULL; |
||
893 | } |
||
894 | |||
895 | const char *darm_shift_type_name(darm_shift_type_t shifttype) |
||
896 | { |
||
897 | return |
||
898 | shifttype != S_INVLD && shifttype < (int32_t) ARRAYSIZE(shift_types) ? |
||
899 | shift_types[shifttype] : NULL; |
||
900 | } |
||
901 | |||
902 | const char *darm_condition_name(darm_cond_t cond, int omit_always_execute) |
||
903 | { |
||
904 | // we don't give the AL postfix, as almost every instruction would need |
||
905 | // one then |
||
906 | if(omit_always_execute != 0 && cond == C_AL) return ""; |
||
907 | |||
908 | return cond != C_INVLD && cond < (int32_t) ARRAYSIZE(g_condition_codes) ? |
||
909 | g_condition_codes[cond].mnemonic_extension : NULL; |
||
910 | } |
||
911 | |||
912 | const char *darm_condition_meaning_int(darm_cond_t cond) |
||
913 | { |
||
914 | return cond != C_INVLD && cond < (int32_t) ARRAYSIZE(g_condition_codes) ? |
||
915 | g_condition_codes[cond].meaning_integer : NULL; |
||
916 | } |
||
917 | |||
918 | const char *darm_condition_meaning_fp(darm_cond_t cond) |
||
919 | { |
||
920 | return cond != C_INVLD && cond < (int32_t) ARRAYSIZE(g_condition_codes) ? |
||
921 | g_condition_codes[cond].meaning_fp : NULL; |
||
922 | } |
||
923 | |||
924 | darm_cond_t darm_condition_index(const char *condition_code) |
||
925 | { |
||
926 | if(condition_code == NULL) return -1; |
||
927 | |||
928 | // the "AL" condition flag |
||
929 | if(condition_code[0] == 0) return C_AL; |
||
930 | |||
931 | for (uint32_t i = 0; i < ARRAYSIZE(g_condition_codes); i++) { |
||
932 | if(!strcmp(condition_code, g_condition_codes[i].mnemonic_extension)) { |
||
933 | return i; |
||
934 | } |
||
935 | } |
||
936 | |||
937 | return C_INVLD; |
||
938 | } |