1 | // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
2 | // for details. All rights reserved. Use of this source code is governed by a |
3 | // BSD-style license that can be found in the LICENSE file. |
4 | |
5 | #include "vm/globals.h" // Needed here to get TARGET_ARCH_ARM. |
6 | #if defined(TARGET_ARCH_ARM) |
7 | |
8 | #include "vm/compiler/assembler/disassembler.h" |
9 | |
10 | #include "platform/assert.h" |
11 | #include "vm/cpu.h" |
12 | #include "vm/instructions.h" |
13 | |
14 | namespace dart { |
15 | |
16 | #if !defined(PRODUCT) || defined(FORCE_INCLUDE_DISASSEMBLER) |
17 | |
18 | class ARMDecoder : public ValueObject { |
19 | public: |
20 | ARMDecoder(char* buffer, size_t buffer_size) |
21 | : buffer_(buffer), buffer_size_(buffer_size), buffer_pos_(0) { |
22 | buffer_[buffer_pos_] = '\0'; |
23 | } |
24 | |
25 | ~ARMDecoder() {} |
26 | |
27 | // Writes one disassembled instruction into 'buffer' (0-terminated). |
28 | // Returns true if the instruction was successfully decoded, false otherwise. |
29 | void InstructionDecode(uword pc); |
30 | |
31 | private: |
32 | // Bottleneck functions to print into the out_buffer. |
33 | void Print(const char* str); |
34 | |
35 | // Printing of common values. |
36 | void PrintRegister(int reg); |
37 | void PrintSRegister(int reg); |
38 | void PrintDRegister(int reg); |
39 | void PrintDRegisterList(int start, int reg_count); |
40 | void PrintQRegister(int reg); |
41 | void PrintCondition(Instr* instr); |
42 | void PrintShiftRm(Instr* instr); |
43 | void PrintShiftImm(Instr* instr); |
44 | void PrintPU(Instr* instr); |
45 | |
46 | // Handle formatting of instructions and their options. |
47 | int FormatRegister(Instr* instr, const char* option); |
48 | int FormatSRegister(Instr* instr, const char* option); |
49 | int FormatDRegister(Instr* instr, const char* option); |
50 | int FormatQRegister(Instr* instr, const char* option); |
51 | int FormatOption(Instr* instr, const char* option); |
52 | void Format(Instr* instr, const char* format); |
53 | void Unknown(Instr* instr); |
54 | |
55 | // Each of these functions decodes one particular instruction type, a 3-bit |
56 | // field in the instruction encoding. |
57 | // Types 0 and 1 are combined as they are largely the same except for the way |
58 | // they interpret the shifter operand. |
59 | void DecodeType01(Instr* instr); |
60 | void DecodeType2(Instr* instr); |
61 | void DecodeType3(Instr* instr); |
62 | void DecodeType4(Instr* instr); |
63 | void DecodeType5(Instr* instr); |
64 | void DecodeType6(Instr* instr); |
65 | void DecodeType7(Instr* instr); |
66 | void DecodeSIMDDataProcessing(Instr* instr); |
67 | |
68 | // Convenience functions. |
69 | char* get_buffer() const { return buffer_; } |
70 | char* current_position_in_buffer() { return buffer_ + buffer_pos_; } |
71 | size_t remaining_size_in_buffer() { return buffer_size_ - buffer_pos_; } |
72 | |
73 | char* buffer_; // Decode instructions into this buffer. |
74 | size_t buffer_size_; // The size of the character buffer. |
75 | size_t buffer_pos_; // Current character position in buffer. |
76 | |
77 | DISALLOW_ALLOCATION(); |
78 | DISALLOW_COPY_AND_ASSIGN(ARMDecoder); |
79 | }; |
80 | |
81 | // Support for assertions in the ARMDecoder formatting functions. |
82 | #define STRING_STARTS_WITH(string, compare_string) \ |
83 | (strncmp(string, compare_string, strlen(compare_string)) == 0) |
84 | |
85 | // Append the str to the output buffer. |
86 | void ARMDecoder::Print(const char* str) { |
87 | char cur = *str++; |
88 | while (cur != '\0' && (buffer_pos_ < (buffer_size_ - 1))) { |
89 | buffer_[buffer_pos_++] = cur; |
90 | cur = *str++; |
91 | } |
92 | buffer_[buffer_pos_] = '\0'; |
93 | } |
94 | |
95 | // These condition names are defined in a way to match the native disassembler |
96 | // formatting. See for example the command "objdump -d <binary file>". |
97 | static const char* cond_names[kNumberOfConditions] = { |
98 | "eq" , "ne" , "cs" , "cc" , "mi" , "pl" , "vs" , "vc" , |
99 | "hi" , "ls" , "ge" , "lt" , "gt" , "le" , "" , "invalid" , |
100 | }; |
101 | |
102 | // Print the condition guarding the instruction. |
103 | void ARMDecoder::PrintCondition(Instr* instr) { |
104 | Print(cond_names[instr->ConditionField()]); |
105 | } |
106 | |
107 | // These register names are defined in a way to match the native disassembler |
108 | // formatting, except for register alias pp (r5). |
109 | // See for example the command "objdump -d <binary file>". |
110 | static const char* reg_names[kNumberOfCpuRegisters] = { |
111 | #if defined(TARGET_OS_MACOS) || defined(TARGET_OS_MACOS_IOS) |
112 | "r0" , "r1" , "r2" , "r3" , "r4" , "pp" , "r6" , "fp" , |
113 | "r8" , "r9" , "thr" , "r11" , "ip" , "sp" , "lr" , "pc" , |
114 | #else |
115 | "r0" , "r1" , "r2" , "r3" , "r4" , "pp" , "r6" , "r7" , |
116 | "r8" , "r9" , "thr" , "fp" , "ip" , "sp" , "lr" , "pc" , |
117 | #endif |
118 | }; |
119 | |
120 | // Print the register name according to the active name converter. |
121 | void ARMDecoder::PrintRegister(int reg) { |
122 | ASSERT(0 <= reg); |
123 | ASSERT(reg < kNumberOfCpuRegisters); |
124 | Print(reg_names[reg]); |
125 | } |
126 | |
127 | void ARMDecoder::PrintSRegister(int reg) { |
128 | ASSERT(0 <= reg); |
129 | ASSERT(reg < kNumberOfSRegisters); |
130 | buffer_pos_ += Utils::SNPrint(current_position_in_buffer(), |
131 | remaining_size_in_buffer(), "s%d" , reg); |
132 | } |
133 | |
134 | void ARMDecoder::PrintDRegister(int reg) { |
135 | ASSERT(0 <= reg); |
136 | ASSERT(reg < kNumberOfDRegisters); |
137 | buffer_pos_ += Utils::SNPrint(current_position_in_buffer(), |
138 | remaining_size_in_buffer(), "d%d" , reg); |
139 | } |
140 | |
141 | void ARMDecoder::PrintQRegister(int reg) { |
142 | ASSERT(0 <= reg); |
143 | ASSERT(reg < kNumberOfQRegisters); |
144 | buffer_pos_ += Utils::SNPrint(current_position_in_buffer(), |
145 | remaining_size_in_buffer(), "q%d" , reg); |
146 | } |
147 | |
148 | // These shift names are defined in a way to match the native disassembler |
149 | // formatting. See for example the command "objdump -d <binary file>". |
150 | static const char* shift_names[kMaxShift] = {"lsl" , "lsr" , "asr" , "ror" }; |
151 | |
152 | // Print the register shift operands for the instruction. Generally used for |
153 | // data processing instructions. |
154 | void ARMDecoder::PrintShiftRm(Instr* instr) { |
155 | Shift shift = instr->ShiftField(); |
156 | int shift_amount = instr->ShiftAmountField(); |
157 | int rm = instr->RmField(); |
158 | |
159 | PrintRegister(rm); |
160 | |
161 | if ((instr->RegShiftField() == 0) && (shift == LSL) && (shift_amount == 0)) { |
162 | // Special case for using rm only. |
163 | return; |
164 | } |
165 | if (instr->RegShiftField() == 0) { |
166 | // by immediate |
167 | if ((shift == ROR) && (shift_amount == 0)) { |
168 | Print(", RRX" ); |
169 | return; |
170 | } else if (((shift == LSR) || (shift == ASR)) && (shift_amount == 0)) { |
171 | shift_amount = 32; |
172 | } |
173 | buffer_pos_ += |
174 | Utils::SNPrint(current_position_in_buffer(), remaining_size_in_buffer(), |
175 | ", %s #%d" , shift_names[shift], shift_amount); |
176 | } else { |
177 | // by register |
178 | int rs = instr->RsField(); |
179 | buffer_pos_ += |
180 | Utils::SNPrint(current_position_in_buffer(), remaining_size_in_buffer(), |
181 | ", %s " , shift_names[shift]); |
182 | PrintRegister(rs); |
183 | } |
184 | } |
185 | |
186 | // Print the immediate operand for the instruction. Generally used for data |
187 | // processing instructions. |
188 | void ARMDecoder::PrintShiftImm(Instr* instr) { |
189 | uint8_t rotate = instr->RotateField() * 2; |
190 | int32_t immed8 = instr->Immed8Field(); |
191 | int32_t imm = Utils::RotateRight(immed8, rotate); |
192 | buffer_pos_ += Utils::SNPrint(current_position_in_buffer(), |
193 | remaining_size_in_buffer(), "#%d" , imm); |
194 | } |
195 | |
196 | // Print PU formatting to reduce complexity of FormatOption. |
197 | void ARMDecoder::PrintPU(Instr* instr) { |
198 | switch (instr->PUField()) { |
199 | case 0: { |
200 | Print("da" ); |
201 | break; |
202 | } |
203 | case 1: { |
204 | Print("ia" ); |
205 | break; |
206 | } |
207 | case 2: { |
208 | Print("db" ); |
209 | break; |
210 | } |
211 | case 3: { |
212 | Print("ib" ); |
213 | break; |
214 | } |
215 | default: { |
216 | UNREACHABLE(); |
217 | break; |
218 | } |
219 | } |
220 | } |
221 | |
222 | // Handle all register based formatting in these functions to reduce the |
223 | // complexity of FormatOption. |
224 | int ARMDecoder::FormatRegister(Instr* instr, const char* format) { |
225 | ASSERT(format[0] == 'r'); |
226 | if (format[1] == 'n') { // 'rn: Rn register |
227 | int reg = instr->RnField(); |
228 | PrintRegister(reg); |
229 | return 2; |
230 | } else if (format[1] == 'd') { // 'rd: Rd register |
231 | int reg = instr->RdField(); |
232 | PrintRegister(reg); |
233 | if (format[2] == '2') { // 'rd2: possibly Rd, Rd+1 register pair |
234 | if (instr->HasSign() && !instr->HasL()) { |
235 | if ((reg % 2) != 0) { |
236 | Print(" *** unknown (odd register pair) ***" ); |
237 | } else { |
238 | Print(", " ); |
239 | PrintRegister(reg + 1); |
240 | } |
241 | } |
242 | return 3; |
243 | } |
244 | return 2; |
245 | } else if (format[1] == 's') { // 'rs: Rs register |
246 | int reg = instr->RsField(); |
247 | PrintRegister(reg); |
248 | return 2; |
249 | } else if (format[1] == 'm') { // 'rm: Rm register |
250 | int reg = instr->RmField(); |
251 | PrintRegister(reg); |
252 | return 2; |
253 | } else if (format[1] == 'l') { |
254 | // 'rlist: register list for load and store multiple instructions |
255 | ASSERT(STRING_STARTS_WITH(format, "rlist" )); |
256 | int rlist = instr->RlistField(); |
257 | int reg = 0; |
258 | Print("{" ); |
259 | // Print register list in ascending order, by scanning the bit mask. |
260 | while (rlist != 0) { |
261 | if ((rlist & 1) != 0) { |
262 | PrintRegister(reg); |
263 | if ((rlist >> 1) != 0) { |
264 | Print(", " ); |
265 | } |
266 | } |
267 | reg++; |
268 | rlist >>= 1; |
269 | } |
270 | Print("}" ); |
271 | return 5; |
272 | } |
273 | UNREACHABLE(); |
274 | return -1; |
275 | } |
276 | |
277 | int ARMDecoder::FormatSRegister(Instr* instr, const char* format) { |
278 | ASSERT(format[0] == 's'); |
279 | if (format[1] == 'n') { // 'sn: Sn register |
280 | int reg = instr->SnField(); |
281 | PrintSRegister(reg); |
282 | return 2; |
283 | } else if (format[1] == 'd') { // 'sd: Sd register |
284 | int reg = instr->SdField(); |
285 | PrintSRegister(reg); |
286 | return 2; |
287 | } else if (format[1] == 'm') { |
288 | int reg = instr->SmField(); |
289 | if (format[2] == '1') { // 'sm1: S[m+1] register |
290 | reg++; |
291 | ASSERT(reg < kNumberOfSRegisters); |
292 | PrintSRegister(reg); |
293 | return 3; |
294 | } else { // 'sm: Sm register |
295 | PrintSRegister(reg); |
296 | return 2; |
297 | } |
298 | } else if (format[1] == 'l') { |
299 | ASSERT(STRING_STARTS_WITH(format, "slist" )); |
300 | int reg_count = instr->Bits(0, 8); |
301 | int start = instr->Bit(22) | (instr->Bits(12, 4) << 1); |
302 | Print("{" ); |
303 | for (int i = start; i < start + reg_count; i++) { |
304 | PrintSRegister(i); |
305 | if (i != start + reg_count - 1) { |
306 | Print(", " ); |
307 | } |
308 | } |
309 | Print("}" ); |
310 | return 5; |
311 | } |
312 | UNREACHABLE(); |
313 | return -1; |
314 | } |
315 | |
316 | void ARMDecoder::PrintDRegisterList(int start, int reg_count) { |
317 | Print("{" ); |
318 | for (int i = start; i < start + reg_count; i++) { |
319 | PrintDRegister(i); |
320 | if (i != start + reg_count - 1) { |
321 | Print(", " ); |
322 | } |
323 | } |
324 | Print("}" ); |
325 | } |
326 | |
327 | int ARMDecoder::FormatDRegister(Instr* instr, const char* format) { |
328 | ASSERT(format[0] == 'd'); |
329 | if (format[1] == 'n') { // 'dn: Dn register |
330 | int reg = instr->DnField(); |
331 | PrintDRegister(reg); |
332 | return 2; |
333 | } else if (format[1] == 'd') { // 'dd: Dd register |
334 | int reg = instr->DdField(); |
335 | PrintDRegister(reg); |
336 | return 2; |
337 | } else if (format[1] == 'm') { // 'dm: Dm register |
338 | int reg = instr->DmField(); |
339 | PrintDRegister(reg); |
340 | return 2; |
341 | } else if (format[1] == 'l') { |
342 | ASSERT(STRING_STARTS_WITH(format, "dlist" )); |
343 | int reg_count = instr->Bits(0, 8) >> 1; |
344 | int start = (instr->Bit(22) << 4) | instr->Bits(12, 4); |
345 | PrintDRegisterList(start, reg_count); |
346 | return 5; |
347 | } else if (format[1] == 't') { |
348 | ASSERT(STRING_STARTS_WITH(format, "dtbllist" )); |
349 | int reg_count = instr->Bits(8, 2) + 1; |
350 | int start = (instr->Bit(7) << 4) | instr->Bits(16, 4); |
351 | PrintDRegisterList(start, reg_count); |
352 | return 8; |
353 | } |
354 | UNREACHABLE(); |
355 | return -1; |
356 | } |
357 | |
358 | int ARMDecoder::FormatQRegister(Instr* instr, const char* format) { |
359 | ASSERT(format[0] == 'q'); |
360 | if (format[1] == 'n') { // 'qn: Qn register |
361 | int reg = instr->QnField(); |
362 | PrintQRegister(reg); |
363 | return 2; |
364 | } else if (format[1] == 'd') { // 'qd: Qd register |
365 | int reg = instr->QdField(); |
366 | PrintQRegister(reg); |
367 | return 2; |
368 | } else if (format[1] == 'm') { // 'qm: Qm register |
369 | int reg = instr->QmField(); |
370 | PrintQRegister(reg); |
371 | return 2; |
372 | } |
373 | UNREACHABLE(); |
374 | return -1; |
375 | } |
376 | |
377 | // FormatOption takes a formatting string and interprets it based on |
378 | // the current instructions. The format string points to the first |
379 | // character of the option string (the option escape has already been |
380 | // consumed by the caller.) FormatOption returns the number of |
381 | // characters that were consumed from the formatting string. |
382 | int ARMDecoder::FormatOption(Instr* instr, const char* format) { |
383 | switch (format[0]) { |
384 | case 'a': { // 'a: accumulate multiplies |
385 | if (instr->Bit(21) == 0) { |
386 | Print("ul" ); |
387 | } else { |
388 | Print("la" ); |
389 | } |
390 | return 1; |
391 | } |
392 | case 'b': { // 'b: byte loads or stores |
393 | if (instr->HasB()) { |
394 | Print("b" ); |
395 | } |
396 | return 1; |
397 | } |
398 | case 'c': { // 'cond: conditional execution |
399 | ASSERT(STRING_STARTS_WITH(format, "cond" )); |
400 | PrintCondition(instr); |
401 | return 4; |
402 | } |
403 | case 'd': { |
404 | if (format[1] == 'e') { // 'dest: branch destination |
405 | ASSERT(STRING_STARTS_WITH(format, "dest" )); |
406 | const int32_t off = |
407 | (static_cast<uint32_t>(instr->SImmed24Field()) << 2) + 8; |
408 | if (FLAG_disassemble_relative) { |
409 | buffer_pos_ += |
410 | Utils::SNPrint(current_position_in_buffer(), |
411 | remaining_size_in_buffer(), "%+" Pd32 "" , off); |
412 | } else { |
413 | uword destination = reinterpret_cast<uword>(instr) + off; |
414 | buffer_pos_ += Utils::SNPrint(current_position_in_buffer(), |
415 | remaining_size_in_buffer(), "%#" Px "" , |
416 | destination); |
417 | } |
418 | return 4; |
419 | } else { |
420 | return FormatDRegister(instr, format); |
421 | } |
422 | } |
423 | case 'q': { |
424 | return FormatQRegister(instr, format); |
425 | } |
426 | case 'i': { // 'imm12_4, imm4_12, immf, or immd |
427 | uint16_t immed16; |
428 | if (format[3] == 'f') { |
429 | ASSERT(STRING_STARTS_WITH(format, "immf" )); |
430 | buffer_pos_ += Utils::SNPrint(current_position_in_buffer(), |
431 | remaining_size_in_buffer(), "%f" , |
432 | instr->ImmFloatField()); |
433 | return 4; |
434 | } else if (format[3] == 'd') { |
435 | ASSERT(STRING_STARTS_WITH(format, "immd" )); |
436 | buffer_pos_ += Utils::SNPrint(current_position_in_buffer(), |
437 | remaining_size_in_buffer(), "%g" , |
438 | instr->ImmDoubleField()); |
439 | return 4; |
440 | } else if (format[3] == '1') { |
441 | ASSERT(STRING_STARTS_WITH(format, "imm12_4" )); |
442 | immed16 = instr->BkptField(); |
443 | } else { |
444 | ASSERT(format[3] == '4'); |
445 | if (format[5] == 'v') { |
446 | ASSERT(STRING_STARTS_WITH(format, "imm4_vdup" )); |
447 | int32_t idx = -1; |
448 | int32_t imm4 = instr->Bits(16, 4); |
449 | if ((imm4 & 1) != 0) |
450 | idx = imm4 >> 1; |
451 | else if ((imm4 & 2) != 0) |
452 | idx = imm4 >> 2; |
453 | else if ((imm4 & 4) != 0) |
454 | idx = imm4 >> 3; |
455 | buffer_pos_ += Utils::SNPrint(current_position_in_buffer(), |
456 | remaining_size_in_buffer(), "%d" , idx); |
457 | return 9; |
458 | } else { |
459 | ASSERT(STRING_STARTS_WITH(format, "imm4_12" )); |
460 | immed16 = instr->MovwField(); |
461 | } |
462 | } |
463 | buffer_pos_ += |
464 | Utils::SNPrint(current_position_in_buffer(), |
465 | remaining_size_in_buffer(), "0x%x" , immed16); |
466 | return 7; |
467 | } |
468 | case 'l': { // 'l: branch and link |
469 | if (instr->HasLink()) { |
470 | Print("l" ); |
471 | } |
472 | return 1; |
473 | } |
474 | case 'm': { // 'memop: load/store instructions |
475 | ASSERT(STRING_STARTS_WITH(format, "memop" )); |
476 | if (instr->HasL() || |
477 | // Extra load/store instructions. |
478 | ((instr->TypeField() == 0) && instr->HasSign() && !instr->HasH())) { |
479 | Print("ldr" ); |
480 | } else { |
481 | Print("str" ); |
482 | } |
483 | return 5; |
484 | } |
485 | case 'o': { |
486 | if (format[3] == '1') { |
487 | if (format[4] == '0') { |
488 | // 'off10: 10-bit offset for VFP load and store instructions |
489 | buffer_pos_ += Utils::SNPrint(current_position_in_buffer(), |
490 | remaining_size_in_buffer(), "%d" , |
491 | instr->Bits(0, 8) << 2); |
492 | } else { |
493 | // 'off12: 12-bit offset for load and store instructions. |
494 | ASSERT(STRING_STARTS_WITH(format, "off12" )); |
495 | buffer_pos_ += Utils::SNPrint(current_position_in_buffer(), |
496 | remaining_size_in_buffer(), "%d" , |
497 | instr->Offset12Field()); |
498 | } |
499 | return 5; |
500 | } |
501 | // 'off8: 8-bit offset for extra load and store instructions. |
502 | ASSERT(STRING_STARTS_WITH(format, "off8" )); |
503 | int offs8 = (instr->ImmedHField() << 4) | instr->ImmedLField(); |
504 | buffer_pos_ += Utils::SNPrint(current_position_in_buffer(), |
505 | remaining_size_in_buffer(), "%d" , offs8); |
506 | return 4; |
507 | } |
508 | case 'p': { // 'pu: P and U bits for load and store instructions. |
509 | ASSERT(STRING_STARTS_WITH(format, "pu" )); |
510 | PrintPU(instr); |
511 | return 2; |
512 | } |
513 | case 'r': { |
514 | return FormatRegister(instr, format); |
515 | } |
516 | case 's': { |
517 | if (format[1] == 'h') { // 'shift_op or 'shift_rm |
518 | if (format[6] == 'o') { // 'shift_op |
519 | ASSERT(STRING_STARTS_WITH(format, "shift_op" )); |
520 | if (instr->TypeField() == 0) { |
521 | PrintShiftRm(instr); |
522 | } else { |
523 | ASSERT(instr->TypeField() == 1); |
524 | PrintShiftImm(instr); |
525 | } |
526 | return 8; |
527 | } else { // 'shift_rm |
528 | ASSERT(STRING_STARTS_WITH(format, "shift_rm" )); |
529 | PrintShiftRm(instr); |
530 | return 8; |
531 | } |
532 | } else if (format[1] == 'v') { // 'svc |
533 | ASSERT(STRING_STARTS_WITH(format, "svc" )); |
534 | buffer_pos_ += Utils::SNPrint(current_position_in_buffer(), |
535 | remaining_size_in_buffer(), "0x%x" , |
536 | instr->SvcField()); |
537 | return 3; |
538 | } else if (format[1] == 'z') { |
539 | // 'sz: Size field of SIMD instructions. |
540 | int sz = instr->Bits(20, 2); |
541 | char const* sz_str; |
542 | switch (sz) { |
543 | case 0: |
544 | sz_str = "b" ; |
545 | break; |
546 | case 1: |
547 | sz_str = "h" ; |
548 | break; |
549 | case 2: |
550 | sz_str = "w" ; |
551 | break; |
552 | case 3: |
553 | sz_str = "l" ; |
554 | break; |
555 | default: |
556 | sz_str = "?" ; |
557 | break; |
558 | } |
559 | buffer_pos_ += Utils::SNPrint(current_position_in_buffer(), |
560 | remaining_size_in_buffer(), "%s" , sz_str); |
561 | return 2; |
562 | } else if (format[1] == ' ') { |
563 | // 's: S field of data processing instructions. |
564 | if (instr->HasS()) { |
565 | Print("s" ); |
566 | } |
567 | return 1; |
568 | } else { |
569 | return FormatSRegister(instr, format); |
570 | } |
571 | } |
572 | case 't': { // 'target: target of branch instructions. |
573 | ASSERT(STRING_STARTS_WITH(format, "target" )); |
574 | int32_t off = (static_cast<uint32_t>(instr->SImmed24Field()) << 2) + 8; |
575 | buffer_pos_ += Utils::SNPrint(current_position_in_buffer(), |
576 | remaining_size_in_buffer(), "%+d" , off); |
577 | return 6; |
578 | } |
579 | case 'u': { // 'u: signed or unsigned multiplies. |
580 | if (instr->Bit(22) == 0) { |
581 | Print("u" ); |
582 | } else { |
583 | Print("s" ); |
584 | } |
585 | return 1; |
586 | } |
587 | case 'w': { // 'w: W field of load and store instructions. |
588 | if (instr->HasW()) { |
589 | Print("!" ); |
590 | } |
591 | return 1; |
592 | } |
593 | case 'x': { // 'x: type of extra load/store instructions. |
594 | if (!instr->HasSign()) { |
595 | Print("h" ); |
596 | } else if (instr->HasL()) { |
597 | if (instr->HasH()) { |
598 | Print("sh" ); |
599 | } else { |
600 | Print("sb" ); |
601 | } |
602 | } else { |
603 | Print("d" ); |
604 | } |
605 | return 1; |
606 | } |
607 | default: { |
608 | UNREACHABLE(); |
609 | break; |
610 | } |
611 | } |
612 | UNREACHABLE(); |
613 | return -1; |
614 | } |
615 | |
616 | // Format takes a formatting string for a whole instruction and prints it into |
617 | // the output buffer. All escaped options are handed to FormatOption to be |
618 | // parsed further. |
619 | void ARMDecoder::Format(Instr* instr, const char* format) { |
620 | char cur = *format++; |
621 | while ((cur != 0) && (buffer_pos_ < (buffer_size_ - 1))) { |
622 | if (cur == '\'') { // Single quote is used as the formatting escape. |
623 | format += FormatOption(instr, format); |
624 | } else { |
625 | buffer_[buffer_pos_++] = cur; |
626 | } |
627 | cur = *format++; |
628 | } |
629 | buffer_[buffer_pos_] = '\0'; |
630 | } |
631 | |
632 | // For currently unimplemented decodings the disassembler calls Unknown(instr) |
633 | // which will just print "unknown" of the instruction bits. |
634 | void ARMDecoder::Unknown(Instr* instr) { |
635 | Format(instr, "unknown" ); |
636 | } |
637 | |
638 | void ARMDecoder::DecodeType01(Instr* instr) { |
639 | if (!instr->IsDataProcessing()) { |
640 | // miscellaneous, multiply, sync primitives, extra loads and stores. |
641 | if (instr->IsMiscellaneous()) { |
642 | switch (instr->Bits(4, 3)) { |
643 | case 1: { |
644 | if (instr->Bits(21, 2) == 0x3) { |
645 | Format(instr, "clz'cond 'rd, 'rm" ); |
646 | } else if (instr->Bits(21, 2) == 0x1) { |
647 | Format(instr, "bx'cond 'rm" ); |
648 | } else { |
649 | Unknown(instr); |
650 | } |
651 | break; |
652 | } |
653 | case 3: { |
654 | if (instr->Bits(21, 2) == 0x1) { |
655 | Format(instr, "blx'cond 'rm" ); |
656 | } else { |
657 | // Could be inlined constant. |
658 | Unknown(instr); |
659 | } |
660 | break; |
661 | } |
662 | case 7: { |
663 | if ((instr->Bits(21, 2) == 0x1) && (instr->ConditionField() == AL)) { |
664 | Format(instr, "bkpt #'imm12_4" ); |
665 | } else { |
666 | // Format(instr, "smc'cond"); |
667 | Unknown(instr); // Not used. |
668 | } |
669 | break; |
670 | } |
671 | default: { |
672 | Unknown(instr); // Not used. |
673 | break; |
674 | } |
675 | } |
676 | } else if (instr->IsMultiplyOrSyncPrimitive()) { |
677 | if (instr->Bit(24) == 0) { |
678 | // multiply instructions |
679 | switch (instr->Bits(21, 3)) { |
680 | case 0: { |
681 | // Assembler registers rd, rn, rm are encoded as rn, rm, rs. |
682 | Format(instr, "mul'cond's 'rn, 'rm, 'rs" ); |
683 | break; |
684 | } |
685 | case 1: { |
686 | // Assembler registers rd, rn, rm, ra are encoded as rn, rm, rs, rd. |
687 | Format(instr, "mla'cond's 'rn, 'rm, 'rs, 'rd" ); |
688 | break; |
689 | } |
690 | case 2: { |
691 | // Registers rd_lo, rd_hi, rn, rm are encoded as rd, rn, rm, rs. |
692 | Format(instr, "umaal'cond's 'rd, 'rn, 'rm, 'rs" ); |
693 | break; |
694 | } |
695 | case 3: { |
696 | // Assembler registers rd, rn, rm, ra are encoded as rn, rm, rs, rd. |
697 | Format(instr, "mls'cond's 'rn, 'rm, 'rs, 'rd" ); |
698 | break; |
699 | } |
700 | case 4: { |
701 | // Registers rd_lo, rd_hi, rn, rm are encoded as rd, rn, rm, rs. |
702 | Format(instr, "umull'cond's 'rd, 'rn, 'rm, 'rs" ); |
703 | break; |
704 | } |
705 | case 5: { |
706 | // Registers rd_lo, rd_hi, rn, rm are encoded as rd, rn, rm, rs. |
707 | Format(instr, "umlal'cond's 'rd, 'rn, 'rm, 'rs" ); |
708 | break; |
709 | } |
710 | case 6: { |
711 | // Registers rd_lo, rd_hi, rn, rm are encoded as rd, rn, rm, rs. |
712 | Format(instr, "smull'cond's 'rd, 'rn, 'rm, 'rs" ); |
713 | break; |
714 | } |
715 | default: { |
716 | Unknown(instr); // Not used. |
717 | break; |
718 | } |
719 | } |
720 | } else { |
721 | // synchronization primitives |
722 | switch (instr->Bits(20, 4)) { |
723 | case 8: { |
724 | Format(instr, "strex'cond 'rd, 'rm, ['rn]" ); |
725 | break; |
726 | } |
727 | case 9: { |
728 | Format(instr, "ldrex'cond 'rd, ['rn]" ); |
729 | break; |
730 | } |
731 | default: { |
732 | Unknown(instr); // Not used. |
733 | break; |
734 | } |
735 | } |
736 | } |
737 | } else if (instr->Bit(25) == 1) { |
738 | // 16-bit immediate loads, msr (immediate), and hints |
739 | switch (instr->Bits(20, 5)) { |
740 | case 16: { |
741 | Format(instr, "movw'cond 'rd, #'imm4_12" ); |
742 | break; |
743 | } |
744 | case 18: { |
745 | if ((instr->Bits(16, 4) == 0) && (instr->Bits(0, 8) == 0)) { |
746 | Format(instr, "nop'cond" ); |
747 | } else { |
748 | Unknown(instr); // Not used. |
749 | } |
750 | break; |
751 | } |
752 | case 20: { |
753 | Format(instr, "movt'cond 'rd, #'imm4_12" ); |
754 | break; |
755 | } |
756 | default: { |
757 | Unknown(instr); // Not used. |
758 | break; |
759 | } |
760 | } |
761 | } else { |
762 | // extra load/store instructions |
763 | switch (instr->PUField()) { |
764 | case 0: { |
765 | if (instr->Bit(22) == 0) { |
766 | Format(instr, "'memop'cond'x 'rd2, ['rn], -'rm" ); |
767 | } else { |
768 | Format(instr, "'memop'cond'x 'rd2, ['rn], #-'off8" ); |
769 | } |
770 | break; |
771 | } |
772 | case 1: { |
773 | if (instr->Bit(22) == 0) { |
774 | Format(instr, "'memop'cond'x 'rd2, ['rn], +'rm" ); |
775 | } else { |
776 | Format(instr, "'memop'cond'x 'rd2, ['rn], #+'off8" ); |
777 | } |
778 | break; |
779 | } |
780 | case 2: { |
781 | if (instr->Bit(22) == 0) { |
782 | Format(instr, "'memop'cond'x 'rd2, ['rn, -'rm]'w" ); |
783 | } else { |
784 | Format(instr, "'memop'cond'x 'rd2, ['rn, #-'off8]'w" ); |
785 | } |
786 | break; |
787 | } |
788 | case 3: { |
789 | if (instr->Bit(22) == 0) { |
790 | Format(instr, "'memop'cond'x 'rd2, ['rn, +'rm]'w" ); |
791 | } else { |
792 | Format(instr, "'memop'cond'x 'rd2, ['rn, #+'off8]'w" ); |
793 | } |
794 | break; |
795 | } |
796 | default: { |
797 | // The PU field is a 2-bit field. |
798 | UNREACHABLE(); |
799 | break; |
800 | } |
801 | } |
802 | } |
803 | } else { |
804 | switch (instr->OpcodeField()) { |
805 | case AND: { |
806 | Format(instr, "and'cond's 'rd, 'rn, 'shift_op" ); |
807 | break; |
808 | } |
809 | case EOR: { |
810 | Format(instr, "eor'cond's 'rd, 'rn, 'shift_op" ); |
811 | break; |
812 | } |
813 | case SUB: { |
814 | Format(instr, "sub'cond's 'rd, 'rn, 'shift_op" ); |
815 | break; |
816 | } |
817 | case RSB: { |
818 | Format(instr, "rsb'cond's 'rd, 'rn, 'shift_op" ); |
819 | break; |
820 | } |
821 | case ADD: { |
822 | Format(instr, "add'cond's 'rd, 'rn, 'shift_op" ); |
823 | break; |
824 | } |
825 | case ADC: { |
826 | Format(instr, "adc'cond's 'rd, 'rn, 'shift_op" ); |
827 | break; |
828 | } |
829 | case SBC: { |
830 | Format(instr, "sbc'cond's 'rd, 'rn, 'shift_op" ); |
831 | break; |
832 | } |
833 | case RSC: { |
834 | Format(instr, "rsc'cond's 'rd, 'rn, 'shift_op" ); |
835 | break; |
836 | } |
837 | case TST: { |
838 | if (instr->HasS()) { |
839 | Format(instr, "tst'cond 'rn, 'shift_op" ); |
840 | } else { |
841 | Unknown(instr); // Not used. |
842 | } |
843 | break; |
844 | } |
845 | case TEQ: { |
846 | if (instr->HasS()) { |
847 | Format(instr, "teq'cond 'rn, 'shift_op" ); |
848 | } else { |
849 | Unknown(instr); // Not used. |
850 | } |
851 | break; |
852 | } |
853 | case CMP: { |
854 | if (instr->HasS()) { |
855 | Format(instr, "cmp'cond 'rn, 'shift_op" ); |
856 | } else { |
857 | Unknown(instr); // Not used. |
858 | } |
859 | break; |
860 | } |
861 | case CMN: { |
862 | if (instr->HasS()) { |
863 | Format(instr, "cmn'cond 'rn, 'shift_op" ); |
864 | } else { |
865 | Unknown(instr); // Not used. |
866 | } |
867 | break; |
868 | } |
869 | case ORR: { |
870 | Format(instr, "orr'cond's 'rd, 'rn, 'shift_op" ); |
871 | break; |
872 | } |
873 | case MOV: { |
874 | Format(instr, "mov'cond's 'rd, 'shift_op" ); |
875 | break; |
876 | } |
877 | case BIC: { |
878 | Format(instr, "bic'cond's 'rd, 'rn, 'shift_op" ); |
879 | break; |
880 | } |
881 | case MVN: { |
882 | Format(instr, "mvn'cond's 'rd, 'shift_op" ); |
883 | break; |
884 | } |
885 | default: { |
886 | // The Opcode field is a 4-bit field. |
887 | UNREACHABLE(); |
888 | break; |
889 | } |
890 | } |
891 | } |
892 | } |
893 | |
894 | void ARMDecoder::DecodeType2(Instr* instr) { |
895 | switch (instr->PUField()) { |
896 | case 0: { |
897 | if (instr->HasW()) { |
898 | Unknown(instr); // Not used. |
899 | } else { |
900 | Format(instr, "'memop'cond'b 'rd, ['rn], #-'off12" ); |
901 | } |
902 | break; |
903 | } |
904 | case 1: { |
905 | if (instr->HasW()) { |
906 | Unknown(instr); // Not used. |
907 | } else { |
908 | Format(instr, "'memop'cond'b 'rd, ['rn], #+'off12" ); |
909 | } |
910 | break; |
911 | } |
912 | case 2: { |
913 | Format(instr, "'memop'cond'b 'rd, ['rn, #-'off12]'w" ); |
914 | break; |
915 | } |
916 | case 3: { |
917 | Format(instr, "'memop'cond'b 'rd, ['rn, #+'off12]'w" ); |
918 | break; |
919 | } |
920 | default: { |
921 | // The PU field is a 2-bit field. |
922 | UNREACHABLE(); |
923 | break; |
924 | } |
925 | } |
926 | } |
927 | |
928 | void ARMDecoder::DecodeType3(Instr* instr) { |
929 | if (instr->IsDivision()) { |
930 | if (!TargetCPUFeatures::integer_division_supported()) { |
931 | Unknown(instr); |
932 | return; |
933 | } |
934 | if (instr->Bit(21)) { |
935 | Format(instr, "udiv'cond 'rn, 'rs, 'rm" ); |
936 | } else { |
937 | Format(instr, "sdiv'cond 'rn, 'rs, 'rm" ); |
938 | } |
939 | return; |
940 | } |
941 | switch (instr->PUField()) { |
942 | case 0: { |
943 | if (instr->HasW()) { |
944 | Unknown(instr); |
945 | } else { |
946 | Format(instr, "'memop'cond'b 'rd, ['rn], -'shift_rm" ); |
947 | } |
948 | break; |
949 | } |
950 | case 1: { |
951 | if (instr->HasW()) { |
952 | Unknown(instr); |
953 | } else { |
954 | Format(instr, "'memop'cond'b 'rd, ['rn], +'shift_rm" ); |
955 | } |
956 | break; |
957 | } |
958 | case 2: { |
959 | Format(instr, "'memop'cond'b 'rd, ['rn, -'shift_rm]'w" ); |
960 | break; |
961 | } |
962 | case 3: { |
963 | Format(instr, "'memop'cond'b 'rd, ['rn, +'shift_rm]'w" ); |
964 | break; |
965 | } |
966 | default: { |
967 | // The PU field is a 2-bit field. |
968 | UNREACHABLE(); |
969 | break; |
970 | } |
971 | } |
972 | } |
973 | |
974 | void ARMDecoder::DecodeType4(Instr* instr) { |
975 | if (instr->Bit(22) == 1) { |
976 | Unknown(instr); // Privileged mode currently not supported. |
977 | } else if (instr->HasL()) { |
978 | Format(instr, "ldm'cond'pu 'rn'w, 'rlist" ); |
979 | } else { |
980 | Format(instr, "stm'cond'pu 'rn'w, 'rlist" ); |
981 | } |
982 | } |
983 | |
984 | void ARMDecoder::DecodeType5(Instr* instr) { |
985 | Format(instr, "b'l'cond 'target ; 'dest" ); |
986 | } |
987 | |
988 | void ARMDecoder::DecodeType6(Instr* instr) { |
989 | if (instr->IsVFPDoubleTransfer()) { |
990 | if (instr->Bit(8) == 0) { |
991 | if (instr->Bit(20) == 1) { |
992 | Format(instr, "vmovrrs'cond 'rd, 'rn, {'sm, 'sm1}" ); |
993 | } else { |
994 | Format(instr, "vmovsrr'cond {'sm, 'sm1}, 'rd, 'rn" ); |
995 | } |
996 | } else { |
997 | if (instr->Bit(20) == 1) { |
998 | Format(instr, "vmovrrd'cond 'rd, 'rn, 'dm" ); |
999 | } else { |
1000 | Format(instr, "vmovdrr'cond 'dm, 'rd, 'rn" ); |
1001 | } |
1002 | } |
1003 | } else if (instr->IsVFPLoadStore()) { |
1004 | if (instr->Bit(8) == 0) { |
1005 | if (instr->Bit(20) == 1) { // vldrs |
1006 | if (instr->Bit(23) == 1) { |
1007 | Format(instr, "vldrs'cond 'sd, ['rn, #+'off10]" ); |
1008 | } else { |
1009 | Format(instr, "vldrs'cond 'sd, ['rn, #-'off10]" ); |
1010 | } |
1011 | } else { // vstrs |
1012 | if (instr->Bit(23) == 1) { |
1013 | Format(instr, "vstrs'cond 'sd, ['rn, #+'off10]" ); |
1014 | } else { |
1015 | Format(instr, "vstrs'cond 'sd, ['rn, #-'off10]" ); |
1016 | } |
1017 | } |
1018 | } else { |
1019 | if (instr->Bit(20) == 1) { // vldrd |
1020 | if (instr->Bit(23) == 1) { |
1021 | Format(instr, "vldrd'cond 'dd, ['rn, #+'off10]" ); |
1022 | } else { |
1023 | Format(instr, "vldrd'cond 'dd, ['rn, #-'off10]" ); |
1024 | } |
1025 | } else { // vstrd |
1026 | if (instr->Bit(23) == 1) { |
1027 | Format(instr, "vstrd'cond 'dd, ['rn, #+'off10]" ); |
1028 | } else { |
1029 | Format(instr, "vstrd'cond 'dd, ['rn, #-'off10]" ); |
1030 | } |
1031 | } |
1032 | } |
1033 | } else if (instr->IsVFPMultipleLoadStore()) { |
1034 | if (instr->HasL()) { // vldm |
1035 | if (instr->Bit(8)) { // vldmd |
1036 | Format(instr, "vldmd'cond'pu 'rn'w, 'dlist" ); |
1037 | } else { // vldms |
1038 | Format(instr, "vldms'cond'pu 'rn'w, 'slist" ); |
1039 | } |
1040 | } else { // vstm |
1041 | if (instr->Bit(8)) { // vstmd |
1042 | Format(instr, "vstmd'cond'pu 'rn'w, 'dlist" ); |
1043 | } else { // vstms |
1044 | Format(instr, "vstms'cond'pu 'rn'w, 'slist" ); |
1045 | } |
1046 | } |
1047 | } else { |
1048 | Unknown(instr); |
1049 | } |
1050 | } |
1051 | |
1052 | void ARMDecoder::DecodeType7(Instr* instr) { |
1053 | if (instr->Bit(24) == 1) { |
1054 | Format(instr, "svc'cond #'svc" ); |
1055 | } else if (instr->IsVFPDataProcessingOrSingleTransfer()) { |
1056 | if (instr->Bit(4) == 0) { |
1057 | // VFP Data Processing |
1058 | switch (instr->Bits(20, 4) & 0xb) { |
1059 | case 0: { // vmla, vmls floating-point |
1060 | if (instr->Bit(8) == 0) { |
1061 | if (instr->Bit(6) == 0) { |
1062 | Format(instr, "vmlas'cond 'sd, 'sn, 'sm" ); |
1063 | } else { |
1064 | Format(instr, "vmlss'cond 'sd, 'sn, 'sm" ); |
1065 | } |
1066 | } else { |
1067 | if (instr->Bit(6) == 0) { |
1068 | Format(instr, "vmlad'cond 'dd, 'dn, 'dm" ); |
1069 | } else { |
1070 | Format(instr, "vmlsd'cond 'dd, 'dn, 'dm" ); |
1071 | } |
1072 | } |
1073 | break; |
1074 | } |
1075 | case 1: // vnmla, vnmls, vnmul |
1076 | default: { |
1077 | Unknown(instr); |
1078 | break; |
1079 | } |
1080 | case 2: { // vmul |
1081 | if (instr->Bit(8) == 0) { |
1082 | Format(instr, "vmuls'cond 'sd, 'sn, 'sm" ); |
1083 | } else { |
1084 | Format(instr, "vmuld'cond 'dd, 'dn, 'dm" ); |
1085 | } |
1086 | break; |
1087 | } |
1088 | case 8: { // vdiv |
1089 | if (instr->Bit(8) == 0) { |
1090 | Format(instr, "vdivs'cond 'sd, 'sn, 'sm" ); |
1091 | } else { |
1092 | Format(instr, "vdivd'cond 'dd, 'dn, 'dm" ); |
1093 | } |
1094 | break; |
1095 | } |
1096 | case 3: { // vadd, vsub floating-point |
1097 | if (instr->Bit(8) == 0) { |
1098 | if (instr->Bit(6) == 0) { |
1099 | Format(instr, "vadds'cond 'sd, 'sn, 'sm" ); |
1100 | } else { |
1101 | Format(instr, "vsubs'cond 'sd, 'sn, 'sm" ); |
1102 | } |
1103 | } else { |
1104 | if (instr->Bit(6) == 0) { |
1105 | Format(instr, "vaddd'cond 'dd, 'dn, 'dm" ); |
1106 | } else { |
1107 | Format(instr, "vsubd'cond 'dd, 'dn, 'dm" ); |
1108 | } |
1109 | } |
1110 | break; |
1111 | } |
1112 | case 0xb: { // Other VFP data-processing instructions |
1113 | if (instr->Bit(6) == 0) { // vmov immediate |
1114 | if (instr->Bit(8) == 0) { |
1115 | Format(instr, "vmovs'cond 'sd, #'immf" ); |
1116 | } else { |
1117 | Format(instr, "vmovd'cond 'dd, #'immd" ); |
1118 | } |
1119 | break; |
1120 | } |
1121 | switch (instr->Bits(16, 4)) { |
1122 | case 0: { // vmov register, vabs |
1123 | switch (instr->Bits(6, 2)) { |
1124 | case 1: { // vmov register |
1125 | if (instr->Bit(8) == 0) { |
1126 | Format(instr, "vmovs'cond 'sd, 'sm" ); |
1127 | } else { |
1128 | Format(instr, "vmovd'cond 'dd, 'dm" ); |
1129 | } |
1130 | break; |
1131 | } |
1132 | case 3: { // vabs |
1133 | if (instr->Bit(8) == 0) { |
1134 | Format(instr, "vabss'cond 'sd, 'sm" ); |
1135 | } else { |
1136 | Format(instr, "vabsd'cond 'dd, 'dm" ); |
1137 | } |
1138 | break; |
1139 | } |
1140 | default: { |
1141 | Unknown(instr); |
1142 | break; |
1143 | } |
1144 | } |
1145 | break; |
1146 | } |
1147 | case 1: { // vneg, vsqrt |
1148 | switch (instr->Bits(6, 2)) { |
1149 | case 1: { // vneg |
1150 | if (instr->Bit(8) == 0) { |
1151 | Format(instr, "vnegs'cond 'sd, 'sm" ); |
1152 | } else { |
1153 | Format(instr, "vnegd'cond 'dd, 'dm" ); |
1154 | } |
1155 | break; |
1156 | } |
1157 | case 3: { // vsqrt |
1158 | if (instr->Bit(8) == 0) { |
1159 | Format(instr, "vsqrts'cond 'sd, 'sm" ); |
1160 | } else { |
1161 | Format(instr, "vsqrtd'cond 'dd, 'dm" ); |
1162 | } |
1163 | break; |
1164 | } |
1165 | default: { |
1166 | Unknown(instr); |
1167 | break; |
1168 | } |
1169 | } |
1170 | break; |
1171 | } |
1172 | case 4: // vcmp, vcmpe |
1173 | case 5: { // vcmp #0.0, vcmpe #0.0 |
1174 | if (instr->Bit(7) == 1) { // vcmpe |
1175 | Unknown(instr); |
1176 | } else { |
1177 | if (instr->Bit(8) == 0) { // vcmps |
1178 | if (instr->Bit(16) == 0) { |
1179 | Format(instr, "vcmps'cond 'sd, 'sm" ); |
1180 | } else { |
1181 | Format(instr, "vcmps'cond 'sd, #0.0" ); |
1182 | } |
1183 | } else { // vcmpd |
1184 | if (instr->Bit(16) == 0) { |
1185 | Format(instr, "vcmpd'cond 'dd, 'dm" ); |
1186 | } else { |
1187 | Format(instr, "vcmpd'cond 'dd, #0.0" ); |
1188 | } |
1189 | } |
1190 | } |
1191 | break; |
1192 | } |
1193 | case 7: { // vcvt between double-precision and single-precision |
1194 | if (instr->Bit(8) == 0) { |
1195 | Format(instr, "vcvtds'cond 'dd, 'sm" ); |
1196 | } else { |
1197 | Format(instr, "vcvtsd'cond 'sd, 'dm" ); |
1198 | } |
1199 | break; |
1200 | } |
1201 | case 8: { // vcvt, vcvtr between floating-point and integer |
1202 | if (instr->Bit(8) == 0) { |
1203 | if (instr->Bit(7) == 0) { |
1204 | Format(instr, "vcvtsu'cond 'sd, 'sm" ); |
1205 | } else { |
1206 | Format(instr, "vcvtsi'cond 'sd, 'sm" ); |
1207 | } |
1208 | } else { |
1209 | if (instr->Bit(7) == 0) { |
1210 | Format(instr, "vcvtdu'cond 'dd, 'sm" ); |
1211 | } else { |
1212 | Format(instr, "vcvtdi'cond 'dd, 'sm" ); |
1213 | } |
1214 | } |
1215 | break; |
1216 | } |
1217 | case 12: |
1218 | case 13: { // vcvt, vcvtr between floating-point and integer |
1219 | if (instr->Bit(7) == 0) { |
1220 | // We only support round-to-zero mode |
1221 | Unknown(instr); |
1222 | break; |
1223 | } |
1224 | if (instr->Bit(8) == 0) { |
1225 | if (instr->Bit(16) == 0) { |
1226 | Format(instr, "vcvtus'cond 'sd, 'sm" ); |
1227 | } else { |
1228 | Format(instr, "vcvtis'cond 'sd, 'sm" ); |
1229 | } |
1230 | } else { |
1231 | if (instr->Bit(16) == 0) { |
1232 | Format(instr, "vcvtud'cond 'sd, 'dm" ); |
1233 | } else { |
1234 | Format(instr, "vcvtid'cond 'sd, 'dm" ); |
1235 | } |
1236 | } |
1237 | break; |
1238 | } |
1239 | case 2: // vcvtb, vcvtt |
1240 | case 3: // vcvtb, vcvtt |
1241 | case 9: // undefined |
1242 | case 10: // vcvt between floating-point and fixed-point |
1243 | case 11: // vcvt between floating-point and fixed-point |
1244 | case 14: // vcvt between floating-point and fixed-point |
1245 | case 15: // vcvt between floating-point and fixed-point |
1246 | default: { |
1247 | Unknown(instr); |
1248 | break; |
1249 | } |
1250 | } |
1251 | } break; |
1252 | } |
1253 | } else { |
1254 | // 8, 16, or 32-bit Transfer between ARM Core and VFP |
1255 | if ((instr->Bits(21, 3) == 0) && (instr->Bit(8) == 0)) { |
1256 | if (instr->Bit(20) == 0) { |
1257 | Format(instr, "vmovs'cond 'sn, 'rd" ); |
1258 | } else { |
1259 | Format(instr, "vmovr'cond 'rd, 'sn" ); |
1260 | } |
1261 | } else if ((instr->Bits(22, 3) == 0) && (instr->Bit(20) == 0) && |
1262 | (instr->Bit(8) == 1) && (instr->Bits(5, 2) == 0)) { |
1263 | if (instr->Bit(21) == 0) { |
1264 | Format(instr, "vmovd'cond 'dn[0], 'rd" ); |
1265 | } else { |
1266 | Format(instr, "vmovd'cond 'dn[1], 'rd" ); |
1267 | } |
1268 | } else if ((instr->Bits(20, 4) == 0xf) && (instr->Bit(8) == 0)) { |
1269 | if (instr->Bits(12, 4) == 0xf) { |
1270 | Format(instr, "vmrs'cond APSR, FPSCR" ); |
1271 | } else { |
1272 | Format(instr, "vmrs'cond 'rd, FPSCR" ); |
1273 | } |
1274 | } else { |
1275 | Unknown(instr); |
1276 | } |
1277 | } |
1278 | } else { |
1279 | Unknown(instr); |
1280 | } |
1281 | } |
1282 | |
1283 | void ARMDecoder::DecodeSIMDDataProcessing(Instr* instr) { |
1284 | ASSERT(instr->ConditionField() == kSpecialCondition); |
1285 | if (instr->Bit(6) == 1) { |
1286 | if ((instr->Bits(8, 4) == 8) && (instr->Bit(4) == 0) && |
1287 | (instr->Bits(23, 2) == 0)) { |
1288 | Format(instr, "vaddq'sz 'qd, 'qn, 'qm" ); |
1289 | } else if ((instr->Bits(8, 4) == 13) && (instr->Bit(4) == 0) && |
1290 | (instr->Bits(23, 2) == 0) && (instr->Bit(21) == 0)) { |
1291 | Format(instr, "vaddqs 'qd, 'qn, 'qm" ); |
1292 | } else if ((instr->Bits(8, 4) == 8) && (instr->Bit(4) == 0) && |
1293 | (instr->Bits(23, 2) == 2)) { |
1294 | Format(instr, "vsubq'sz 'qd, 'qn, 'qm" ); |
1295 | } else if ((instr->Bits(8, 4) == 13) && (instr->Bit(4) == 0) && |
1296 | (instr->Bits(23, 2) == 0) && (instr->Bit(21) == 1)) { |
1297 | Format(instr, "vsubqs 'qd, 'qn, 'qm" ); |
1298 | } else if ((instr->Bits(8, 4) == 9) && (instr->Bit(4) == 1) && |
1299 | (instr->Bits(23, 2) == 0)) { |
1300 | Format(instr, "vmulq'sz 'qd, 'qn, 'qm" ); |
1301 | } else if ((instr->Bits(8, 4) == 13) && (instr->Bit(4) == 1) && |
1302 | (instr->Bits(23, 2) == 2) && (instr->Bit(21) == 0)) { |
1303 | Format(instr, "vmulqs 'qd, 'qn, 'qm" ); |
1304 | } else if ((instr->Bits(8, 4) == 4) && (instr->Bit(4) == 0) && |
1305 | (instr->Bits(23, 5) == 4)) { |
1306 | Format(instr, "vshlqi'sz 'qd, 'qm, 'qn" ); |
1307 | } else if ((instr->Bits(8, 4) == 4) && (instr->Bit(4) == 0) && |
1308 | (instr->Bits(23, 5) == 6)) { |
1309 | Format(instr, "vshlqu'sz 'qd, 'qm, 'qn" ); |
1310 | } else if ((instr->Bits(8, 4) == 1) && (instr->Bit(4) == 1) && |
1311 | (instr->Bits(20, 2) == 0) && (instr->Bits(23, 2) == 2)) { |
1312 | Format(instr, "veorq 'qd, 'qn, 'qm" ); |
1313 | } else if ((instr->Bits(8, 4) == 1) && (instr->Bit(4) == 1) && |
1314 | (instr->Bits(20, 2) == 3) && (instr->Bits(23, 2) == 0)) { |
1315 | Format(instr, "vornq 'qd, 'qn, 'qm" ); |
1316 | } else if ((instr->Bits(8, 4) == 1) && (instr->Bit(4) == 1) && |
1317 | (instr->Bits(20, 2) == 2) && (instr->Bits(23, 2) == 0)) { |
1318 | if (instr->QmField() == instr->QnField()) { |
1319 | Format(instr, "vmovq 'qd, 'qm" ); |
1320 | } else { |
1321 | Format(instr, "vorrq 'qd, 'qm" ); |
1322 | } |
1323 | } else if ((instr->Bits(8, 4) == 1) && (instr->Bit(4) == 1) && |
1324 | (instr->Bits(20, 2) == 0) && (instr->Bits(23, 2) == 0)) { |
1325 | Format(instr, "vandq 'qd, 'qn, 'qm" ); |
1326 | } else if ((instr->Bits(7, 5) == 11) && (instr->Bit(4) == 0) && |
1327 | (instr->Bits(20, 2) == 3) && (instr->Bits(23, 5) == 7) && |
1328 | (instr->Bits(16, 4) == 0)) { |
1329 | Format(instr, "vmvnq 'qd, 'qm" ); |
1330 | } else if ((instr->Bits(8, 4) == 15) && (instr->Bit(4) == 0) && |
1331 | (instr->Bits(20, 2) == 2) && (instr->Bits(23, 2) == 0)) { |
1332 | Format(instr, "vminqs 'qd, 'qn, 'qm" ); |
1333 | } else if ((instr->Bits(8, 4) == 15) && (instr->Bit(4) == 0) && |
1334 | (instr->Bits(20, 2) == 0) && (instr->Bits(23, 2) == 0)) { |
1335 | Format(instr, "vmaxqs 'qd, 'qn, 'qm" ); |
1336 | } else if ((instr->Bits(8, 4) == 7) && (instr->Bit(4) == 0) && |
1337 | (instr->Bits(20, 2) == 3) && (instr->Bits(23, 2) == 3) && |
1338 | (instr->Bit(7) == 0) && (instr->Bits(16, 4) == 9)) { |
1339 | Format(instr, "vabsqs 'qd, 'qm" ); |
1340 | } else if ((instr->Bits(8, 4) == 7) && (instr->Bit(4) == 0) && |
1341 | (instr->Bits(20, 2) == 3) && (instr->Bits(23, 2) == 3) && |
1342 | (instr->Bit(7) == 1) && (instr->Bits(16, 4) == 9)) { |
1343 | Format(instr, "vnegqs 'qd, 'qm" ); |
1344 | } else if ((instr->Bits(7, 5) == 10) && (instr->Bit(4) == 0) && |
1345 | (instr->Bits(20, 2) == 3) && (instr->Bits(23, 2) == 3) && |
1346 | (instr->Bits(16, 4) == 11)) { |
1347 | Format(instr, "vrecpeqs 'qd, 'qm" ); |
1348 | } else if ((instr->Bits(8, 4) == 15) && (instr->Bit(4) == 1) && |
1349 | (instr->Bits(20, 2) == 0) && (instr->Bits(23, 2) == 0)) { |
1350 | Format(instr, "vrecpsqs 'qd, 'qn, 'qm" ); |
1351 | } else if ((instr->Bits(8, 4) == 5) && (instr->Bit(4) == 0) && |
1352 | (instr->Bits(20, 2) == 3) && (instr->Bits(23, 2) == 3) && |
1353 | (instr->Bit(7) == 1) && (instr->Bits(16, 4) == 11)) { |
1354 | Format(instr, "vrsqrteqs 'qd, 'qm" ); |
1355 | } else if ((instr->Bits(8, 4) == 15) && (instr->Bit(4) == 1) && |
1356 | (instr->Bits(20, 2) == 2) && (instr->Bits(23, 2) == 0)) { |
1357 | Format(instr, "vrsqrtsqs 'qd, 'qn, 'qm" ); |
1358 | } else if ((instr->Bits(8, 4) == 12) && (instr->Bit(4) == 0) && |
1359 | (instr->Bits(20, 2) == 3) && (instr->Bits(23, 2) == 3) && |
1360 | (instr->Bit(7) == 0)) { |
1361 | int32_t imm4 = instr->Bits(16, 4); |
1362 | if (imm4 & 1) { |
1363 | Format(instr, "vdupb 'qd, 'dm['imm4_vdup]" ); |
1364 | } else if (imm4 & 2) { |
1365 | Format(instr, "vduph 'qd, 'dm['imm4_vdup]" ); |
1366 | } else if (imm4 & 4) { |
1367 | Format(instr, "vdupw 'qd, 'dm['imm4_vdup]" ); |
1368 | } else { |
1369 | Unknown(instr); |
1370 | } |
1371 | } else if ((instr->Bits(8, 4) == 1) && (instr->Bit(4) == 0) && |
1372 | (instr->Bits(20, 2) == 3) && (instr->Bits(23, 2) == 3) && |
1373 | (instr->Bit(7) == 1) && (instr->Bits(16, 4) == 10)) { |
1374 | Format(instr, "vzipqw 'qd, 'qm" ); |
1375 | } else if ((instr->Bits(8, 4) == 8) && (instr->Bit(4) == 1) && |
1376 | (instr->Bits(23, 2) == 2)) { |
1377 | Format(instr, "vceqq'sz 'qd, 'qn, 'qm" ); |
1378 | } else if ((instr->Bits(8, 4) == 14) && (instr->Bit(4) == 0) && |
1379 | (instr->Bits(20, 2) == 0) && (instr->Bits(23, 2) == 0)) { |
1380 | Format(instr, "vceqqs 'qd, 'qn, 'qm" ); |
1381 | } else if ((instr->Bits(8, 4) == 3) && (instr->Bit(4) == 1) && |
1382 | (instr->Bits(23, 2) == 0)) { |
1383 | Format(instr, "vcgeq'sz 'qd, 'qn, 'qm" ); |
1384 | } else if ((instr->Bits(8, 4) == 3) && (instr->Bit(4) == 1) && |
1385 | (instr->Bits(23, 2) == 2)) { |
1386 | Format(instr, "vcugeq'sz 'qd, 'qn, 'qm" ); |
1387 | } else if ((instr->Bits(8, 4) == 14) && (instr->Bit(4) == 0) && |
1388 | (instr->Bits(20, 2) == 0) && (instr->Bits(23, 2) == 2)) { |
1389 | Format(instr, "vcgeqs 'qd, 'qn, 'qm" ); |
1390 | } else if ((instr->Bits(8, 4) == 3) && (instr->Bit(4) == 0) && |
1391 | (instr->Bits(23, 2) == 0)) { |
1392 | Format(instr, "vcgtq'sz 'qd, 'qn, 'qm" ); |
1393 | } else if ((instr->Bits(8, 4) == 3) && (instr->Bit(4) == 0) && |
1394 | (instr->Bits(23, 2) == 2)) { |
1395 | Format(instr, "vcugtq'sz 'qd, 'qn, 'qm" ); |
1396 | } else if ((instr->Bits(8, 4) == 14) && (instr->Bit(4) == 0) && |
1397 | (instr->Bits(20, 2) == 2) && (instr->Bits(23, 2) == 2)) { |
1398 | Format(instr, "vcgtqs 'qd, 'qn, 'qm" ); |
1399 | } else { |
1400 | Unknown(instr); |
1401 | } |
1402 | } else { |
1403 | if ((instr->Bits(23, 2) == 3) && (instr->Bits(20, 2) == 3) && |
1404 | (instr->Bits(10, 2) == 2) && (instr->Bit(4) == 0)) { |
1405 | Format(instr, "vtbl 'dd, 'dtbllist, 'dm" ); |
1406 | } else { |
1407 | Unknown(instr); |
1408 | } |
1409 | } |
1410 | } |
1411 | |
1412 | void ARMDecoder::InstructionDecode(uword pc) { |
1413 | Instr* instr = Instr::At(pc); |
1414 | |
1415 | if (instr->ConditionField() == kSpecialCondition) { |
1416 | if (instr->InstructionBits() == static_cast<int32_t>(0xf57ff01f)) { |
1417 | Format(instr, "clrex" ); |
1418 | } else if (instr->InstructionBits() == |
1419 | static_cast<int32_t>(kDataMemoryBarrier)) { |
1420 | Format(instr, "dmb ish" ); |
1421 | } else { |
1422 | if (instr->IsSIMDDataProcessing()) { |
1423 | DecodeSIMDDataProcessing(instr); |
1424 | } else { |
1425 | Unknown(instr); |
1426 | } |
1427 | } |
1428 | } else { |
1429 | switch (instr->TypeField()) { |
1430 | case 0: |
1431 | case 1: { |
1432 | DecodeType01(instr); |
1433 | break; |
1434 | } |
1435 | case 2: { |
1436 | DecodeType2(instr); |
1437 | break; |
1438 | } |
1439 | case 3: { |
1440 | DecodeType3(instr); |
1441 | break; |
1442 | } |
1443 | case 4: { |
1444 | DecodeType4(instr); |
1445 | break; |
1446 | } |
1447 | case 5: { |
1448 | DecodeType5(instr); |
1449 | break; |
1450 | } |
1451 | case 6: { |
1452 | DecodeType6(instr); |
1453 | break; |
1454 | } |
1455 | case 7: { |
1456 | DecodeType7(instr); |
1457 | break; |
1458 | } |
1459 | default: { |
1460 | // The type field is 3-bits in the ARM encoding. |
1461 | UNREACHABLE(); |
1462 | break; |
1463 | } |
1464 | } |
1465 | } |
1466 | } |
1467 | |
1468 | void Disassembler::DecodeInstruction(char* hex_buffer, |
1469 | intptr_t hex_size, |
1470 | char* human_buffer, |
1471 | intptr_t human_size, |
1472 | int* out_instr_size, |
1473 | const Code& code, |
1474 | Object** object, |
1475 | uword pc) { |
1476 | ARMDecoder decoder(human_buffer, human_size); |
1477 | decoder.InstructionDecode(pc); |
1478 | int32_t instruction_bits = Instr::At(pc)->InstructionBits(); |
1479 | Utils::SNPrint(hex_buffer, hex_size, "%08x" , instruction_bits); |
1480 | if (out_instr_size) { |
1481 | *out_instr_size = Instr::kInstrSize; |
1482 | } |
1483 | |
1484 | *object = NULL; |
1485 | // TODO(36839): Make DecodeLoadObjectFromPoolOrThread work on simarm_x64. |
1486 | #if !defined(IS_SIMARM_X64) |
1487 | if (!code.IsNull()) { |
1488 | *object = &Object::Handle(); |
1489 | if (!DecodeLoadObjectFromPoolOrThread(pc, code, *object)) { |
1490 | *object = NULL; |
1491 | } |
1492 | } |
1493 | #endif // !defined(IS_SIMARM_X64) |
1494 | } |
1495 | |
1496 | #endif // !defined(PRODUCT) || defined(FORCE_INCLUDE_DISASSEMBLER) |
1497 | |
1498 | } // namespace dart |
1499 | |
1500 | #endif // defined(TARGET_ARCH_ARM) |
1501 | |