1/*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "disassembler_arm.h"
18
19#include <iostream>
20
21#include "base/logging.h"
22#include "base/stringprintf.h"
23#include "thread.h"
24
25namespace art {
26namespace arm {
27
28DisassemblerArm::DisassemblerArm() {
29}
30
31size_t DisassemblerArm::Dump(std::ostream& os, const uint8_t* begin) {
32  if ((reinterpret_cast<intptr_t>(begin) & 1) == 0) {
33    DumpArm(os, begin);
34    return 4;
35  } else {
36    // remove thumb specifier bits
37    begin = reinterpret_cast<const uint8_t*>(reinterpret_cast<uintptr_t>(begin) & ~1);
38    return DumpThumb16(os, begin);
39  }
40}
41
42void DisassemblerArm::Dump(std::ostream& os, const uint8_t* begin, const uint8_t* end) {
43  if ((reinterpret_cast<intptr_t>(begin) & 1) == 0) {
44    for (const uint8_t* cur = begin; cur < end; cur += 4) {
45      DumpArm(os, cur);
46    }
47  } else {
48    // remove thumb specifier bits
49    begin = reinterpret_cast<const uint8_t*>(reinterpret_cast<uintptr_t>(begin) & ~1);
50    end = reinterpret_cast<const uint8_t*>(reinterpret_cast<uintptr_t>(end) & ~1);
51    for (const uint8_t* cur = begin; cur < end;) {
52      cur += DumpThumb16(os, cur);
53    }
54  }
55}
56
57static const char* kConditionCodeNames[] = {
58  "eq",  // 0000 - equal
59  "ne",  // 0001 - not-equal
60  "cs",  // 0010 - carry-set, greater than, equal or unordered
61  "cc",  // 0011 - carry-clear, less than
62  "mi",  // 0100 - minus, negative
63  "pl",  // 0101 - plus, positive or zero
64  "vs",  // 0110 - overflow
65  "vc",  // 0111 - no overflow
66  "hi",  // 1000 - unsigned higher
67  "ls",  // 1001 - unsigned lower or same
68  "ge",  // 1010 - signed greater than or equal
69  "lt",  // 1011 - signed less than
70  "gt",  // 1100 - signed greater than
71  "le",  // 1101 - signed less than or equal
72  "",    // 1110 - always
73  "nv",  // 1111 - never (mostly obsolete, but might be a clue that we're mistranslating)
74};
75
76void DisassemblerArm::DumpCond(std::ostream& os, uint32_t cond) {
77  if (cond < 15) {
78    os << kConditionCodeNames[cond];
79  } else {
80    os << "Unexpected condition: " << cond;
81  }
82}
83
84void DisassemblerArm::DumpBranchTarget(std::ostream& os, const uint8_t* instr_ptr, int32_t imm32) {
85  os << StringPrintf("%+d (%p)", imm32, instr_ptr + imm32);
86}
87
88static uint32_t ReadU16(const uint8_t* ptr) {
89  return ptr[0] | (ptr[1] << 8);
90}
91
92static uint32_t ReadU32(const uint8_t* ptr) {
93  return ptr[0] | (ptr[1] << 8) | (ptr[2] << 16) | (ptr[3] << 24);
94}
95
96static const char* kDataProcessingOperations[] = {
97  "and", "eor", "sub", "rsb", "add", "adc", "sbc", "rsc",
98  "tst", "teq", "cmp", "cmn", "orr", "mov", "bic", "mvn",
99};
100
101static const char* kThumbDataProcessingOperations[] = {
102  "and", "eor", "lsl", "lsr", "asr", "adc", "sbc", "ror",
103  "tst", "rsb", "cmp", "cmn", "orr", "mul", "bic", "mvn",
104};
105
106struct ArmRegister {
107  explicit ArmRegister(uint32_t r) : r(r) { CHECK_LE(r, 15U); }
108  ArmRegister(uint32_t instruction, uint32_t at_bit) : r((instruction >> at_bit) & 0xf) { CHECK_LE(r, 15U); }
109  uint32_t r;
110};
111std::ostream& operator<<(std::ostream& os, const ArmRegister& r) {
112  if (r.r == 13) {
113    os << "sp";
114  } else if (r.r == 14) {
115    os << "lr";
116  } else if (r.r == 15) {
117    os << "pc";
118  } else {
119    os << "r" << r.r;
120  }
121  return os;
122}
123
124struct ThumbRegister : ArmRegister {
125  ThumbRegister(uint16_t instruction, uint16_t at_bit) : ArmRegister((instruction >> at_bit) & 0x7) {}
126};
127
128struct Rm {
129  explicit Rm(uint32_t instruction) : shift((instruction >> 4) & 0xff), rm(instruction & 0xf) {}
130  uint32_t shift;
131  ArmRegister rm;
132};
133std::ostream& operator<<(std::ostream& os, const Rm& r) {
134  os << r.rm;
135  if (r.shift != 0) {
136    os << "-shift-" << r.shift;  // TODO
137  }
138  return os;
139}
140
141struct ShiftedImmediate {
142  explicit ShiftedImmediate(uint32_t instruction) {
143    uint32_t rotate = ((instruction >> 8) & 0xf);
144    uint32_t imm = (instruction & 0xff);
145    value = (imm >> (2 * rotate)) | (imm << (32 - (2 * rotate)));
146  }
147  uint32_t value;
148};
149std::ostream& operator<<(std::ostream& os, const ShiftedImmediate& rhs) {
150  os << "#" << rhs.value;
151  return os;
152}
153
154struct RegisterList {
155  explicit RegisterList(uint32_t instruction) : register_list(instruction & 0xffff) {}
156  uint32_t register_list;
157};
158std::ostream& operator<<(std::ostream& os, const RegisterList& rhs) {
159  if (rhs.register_list == 0) {
160    os << "<no register list?>";
161    return os;
162  }
163  os << "{";
164  bool first = true;
165  for (size_t i = 0; i < 16; i++) {
166    if ((rhs.register_list & (1 << i)) != 0) {
167      if (first) {
168        first = false;
169      } else {
170        os << ", ";
171      }
172      os << ArmRegister(i);
173    }
174  }
175  os << "}";
176  return os;
177}
178
179void DisassemblerArm::DumpArm(std::ostream& os, const uint8_t* instr_ptr) {
180  uint32_t instruction = ReadU32(instr_ptr);
181  uint32_t cond = (instruction >> 28) & 0xf;
182  uint32_t op1 = (instruction >> 25) & 0x7;
183  std::string opcode;
184  std::string suffixes;
185  std::ostringstream args;
186  switch (op1) {
187    case 0:
188    case 1:  // Data processing instructions.
189      {
190        if ((instruction & 0x0ff000f0) == 0x01200070) {  // BKPT
191          opcode = "bkpt";
192          uint32_t imm12 = (instruction >> 8) & 0xfff;
193          uint32_t imm4 = (instruction & 0xf);
194          args << '#' << ((imm12 << 4) | imm4);
195          break;
196        }
197        if ((instruction & 0x0fffffd0) == 0x012fff10) {  // BX and BLX (register)
198          opcode = (((instruction >> 5) & 1) ? "blx" : "bx");
199          args << ArmRegister(instruction & 0xf);
200          break;
201        }
202        bool i = (instruction & (1 << 25)) != 0;
203        bool s = (instruction & (1 << 20)) != 0;
204        uint32_t op = (instruction >> 21) & 0xf;
205        opcode = kDataProcessingOperations[op];
206        bool implicit_s = ((op & ~3) == 8);  // TST, TEQ, CMP, and CMN.
207        if (implicit_s) {
208          // Rd is unused (and not shown), and we don't show the 's' suffix either.
209        } else {
210          if (s) {
211            suffixes += 's';
212          }
213          args << ArmRegister(instruction, 12) << ", ";
214        }
215        if (i) {
216          args << ArmRegister(instruction, 16) << ", " << ShiftedImmediate(instruction);
217        } else {
218          args << Rm(instruction);
219        }
220      }
221      break;
222    case 2:  // Load/store word and unsigned byte.
223      {
224        bool p = (instruction & (1 << 24)) != 0;
225        bool b = (instruction & (1 << 22)) != 0;
226        bool w = (instruction & (1 << 21)) != 0;
227        bool l = (instruction & (1 << 20)) != 0;
228        opcode = StringPrintf("%s%s", (l ? "ldr" : "str"), (b ? "b" : ""));
229        args << ArmRegister(instruction, 12) << ", ";
230        ArmRegister rn(instruction, 16);
231        if (rn.r == 0xf) {
232          UNIMPLEMENTED(FATAL) << "literals";
233        } else {
234          bool wback = !p || w;
235          uint32_t offset = (instruction & 0xfff);
236          if (p && !wback) {
237            args << "[" << rn << ", #" << offset << "]";
238          } else if (p && wback) {
239            args << "[" << rn << ", #" << offset << "]!";
240          } else if (!p && wback) {
241            args << "[" << rn << "], #" << offset;
242          } else {
243            LOG(FATAL) << p << " " << w;
244          }
245          if (rn.r == 9) {
246            args << "  ; ";
247            Thread::DumpThreadOffset(args, offset, 4);
248          }
249        }
250      }
251      break;
252    case 4:  // Load/store multiple.
253      {
254        bool p = (instruction & (1 << 24)) != 0;
255        bool u = (instruction & (1 << 23)) != 0;
256        bool w = (instruction & (1 << 21)) != 0;
257        bool l = (instruction & (1 << 20)) != 0;
258        opcode = StringPrintf("%s%c%c", (l ? "ldm" : "stm"), (u ? 'i' : 'd'), (p ? 'b' : 'a'));
259        args << ArmRegister(instruction, 16) << (w ? "!" : "") << ", " << RegisterList(instruction);
260      }
261      break;
262    case 5:  // Branch/branch with link.
263      {
264        bool bl = (instruction & (1 << 24)) != 0;
265        opcode = (bl ? "bl" : "b");
266        int32_t imm26 = (instruction & 0xffffff) << 2;
267        int32_t imm32 = (imm26 << 6) >> 6;  // Sign extend.
268        DumpBranchTarget(args, instr_ptr + 8, imm32);
269      }
270      break;
271    default:
272      opcode = "???";
273      break;
274    }
275    opcode += kConditionCodeNames[cond];
276    opcode += suffixes;
277    // TODO: a more complete ARM disassembler could generate wider opcodes.
278    os << StringPrintf("%p: %08x\t%-7s ", instr_ptr, instruction, opcode.c_str()) << args.str() << '\n';
279}
280
281size_t DisassemblerArm::DumpThumb32(std::ostream& os, const uint8_t* instr_ptr) {
282  uint32_t instr = (ReadU16(instr_ptr) << 16) | ReadU16(instr_ptr + 2);
283  // |111|1 1|1000000|0000|1111110000000000|
284  // |5 3|2 1|0987654|3  0|5    0    5    0|
285  // |---|---|-------|----|----------------|
286  // |332|2 2|2222222|1111|1111110000000000|
287  // |1 9|8 7|6543210|9  6|5    0    5    0|
288  // |---|---|-------|----|----------------|
289  // |111|op1| op2   |    |                |
290  uint32_t op1 = (instr >> 27) & 3;
291  if (op1 == 0) {
292    return DumpThumb16(os, instr_ptr);
293  }
294
295  uint32_t op2 = (instr >> 20) & 0x7F;
296  std::ostringstream opcode;
297  std::ostringstream args;
298  switch (op1) {
299    case 0:
300      break;
301    case 1:
302      if ((op2 & 0x64) == 0) {  // 00x x0xx
303        // |111|11|10|00|0|00|0000|1111110000000000|
304        // |5 3|21|09|87|6|54|3  0|5    0    5    0|
305        // |---|--|--|--|-|--|----|----------------|
306        // |332|22|22|22|2|22|1111|1111110000000000|
307        // |1 9|87|65|43|2|10|9  6|5    0    5    0|
308        // |---|--|--|--|-|--|----|----------------|
309        // |111|01|00|op|0|WL| Rn |                |
310        // |111|01| op2      |    |                |
311        // STM - 111 01 00-01-0-W0 nnnn rrrrrrrrrrrrrrrr
312        // LDM - 111 01 00-01-0-W1 nnnn rrrrrrrrrrrrrrrr
313        // PUSH- 111 01 00-01-0-10 1101 0M0rrrrrrrrrrrrr
314        // POP - 111 01 00-01-0-11 1101 PM0rrrrrrrrrrrrr
315        uint32_t op = (instr >> 23) & 3;
316        uint32_t W = (instr >> 21) & 1;
317        uint32_t L = (instr >> 20) & 1;
318        ArmRegister Rn(instr, 16);
319        if (op == 1 || op == 2) {
320          if (op == 1) {
321            if (L == 0) {
322              opcode << "stm";
323              args << Rn << (W == 0 ? "" : "!") << ", ";
324            } else {
325              if (Rn.r != 13) {
326                opcode << "ldm";
327                args << Rn << (W == 0 ? "" : "!") << ", ";
328              } else {
329                opcode << "pop";
330              }
331            }
332          } else {
333            if (L == 0) {
334              if (Rn.r != 13) {
335                opcode << "stmdb";
336                args << Rn << (W == 0 ? "" : "!") << ", ";
337              } else {
338                opcode << "push";
339              }
340            } else {
341              opcode << "ldmdb";
342              args << Rn << (W == 0 ? "" : "!") << ", ";
343            }
344          }
345          args << RegisterList(instr);
346        }
347      } else if ((op2 & 0x64) == 4) {  // 00x x1xx
348        uint32_t op3 = (instr >> 23) & 3;
349        uint32_t op4 = (instr >> 20) & 3;
350        // uint32_t op5 = (instr >> 4) & 0xF;
351        ArmRegister Rn(instr, 16);
352        ArmRegister Rt(instr, 12);
353        uint32_t imm8 = instr & 0xFF;
354        if (op3 == 0 && op4 == 0) {  // STREX
355          ArmRegister Rd(instr, 8);
356          opcode << "strex";
357          args << Rd << ", " << Rt << ", [" << Rn << ", #" << (imm8 << 2) << "]";
358        } else if (op3 == 0 && op4 == 1) {  // LDREX
359          opcode << "ldrex";
360          args << Rt << ", [" << Rn << ", #" << (imm8 << 2) << "]";
361        }
362      } else if ((op2 & 0x60) == 0x20) {  // 01x xxxx
363        // Data-processing (shifted register)
364        // |111|1110|0000|0|0000|1111|1100|00|00|0000|
365        // |5 3|2109|8765|4|3  0|5   |10 8|7 |5 |3  0|
366        // |---|----|----|-|----|----|----|--|--|----|
367        // |332|2222|2222|2|1111|1111|1100|00|00|0000|
368        // |1 9|8765|4321|0|9  6|5   |10 8|7 |5 |3  0|
369        // |---|----|----|-|----|----|----|--|--|----|
370        // |111|0101| op3|S| Rn |imm3| Rd |i2|ty| Rm |
371        uint32_t op3 = (instr >> 21) & 0xF;
372        uint32_t S = (instr >> 20) & 1;
373        uint32_t imm3 = ((instr >> 12) & 0x7);
374        uint32_t imm2 = ((instr >> 6) & 0x3);
375        uint32_t imm5 = ((imm3 << 3) | imm2) & 0x1F;
376        uint32_t shift_type = ((instr >> 4) & 0x2);
377        ArmRegister Rd(instr, 8);
378        ArmRegister Rn(instr, 16);
379        ArmRegister Rm(instr, 0);
380        switch (op3) {
381          case 0x0:
382            if (Rd.r != 0xF) {
383              opcode << "and";
384            } else {
385              if (S != 1U) {
386                opcode << "UNKNOWN TST-" << S;
387                break;
388              }
389              opcode << "tst";
390              S = 0;  // don't print 's'
391            }
392            break;
393          case 0x1: opcode << "bic"; break;
394          case 0x2:
395            if (Rn.r != 0xF) {
396              opcode << "orr";
397            } else {
398              // TODO: use canonical form if there is a shift (lsl, ...).
399              opcode << "mov";
400            }
401            break;
402          case 0x3:
403            if (Rn.r != 0xF) {
404              opcode << "orn";
405            } else {
406              opcode << "mvn";
407            }
408            break;
409          case 0x4:
410            if (Rd.r != 0xF) {
411              opcode << "eor";
412            } else {
413              if (S != 1U) {
414                opcode << "UNKNOWN TEQ-" << S;
415                break;
416              }
417              opcode << "teq";
418              S = 0;  // don't print 's'
419            }
420            break;
421          case 0x6: opcode << "pkh"; break;
422          case 0x8:
423            if (Rd.r != 0xF) {
424              opcode << "add";
425            } else {
426              if (S != 1U) {
427                opcode << "UNKNOWN CMN-" << S;
428                break;
429              }
430              opcode << "cmn";
431              S = 0;  // don't print 's'
432            }
433            break;
434          case 0xA: opcode << "adc"; break;
435          case 0xB: opcode << "sbc"; break;
436          case 0xD:
437            if (Rd.r != 0xF) {
438              opcode << "sub";
439            } else {
440              if (S != 1U) {
441                opcode << "UNKNOWN CMP-" << S;
442                break;
443              }
444              opcode << "cmp";
445              S = 0;  // don't print 's'
446            }
447            break;
448          case 0xE: opcode << "rsb"; break;
449          default: opcode << "UNKNOWN DPSR-" << op3; break;
450        }
451
452        if (S == 1) {
453          opcode << "s";
454        }
455        opcode << ".w";
456
457        if (Rd.r != 0xF) {
458          args << Rd << ", ";
459        }
460        if (Rn.r != 0xF) {
461          args << Rn << ", ";
462        }
463        args << Rm;
464
465        // Shift operand.
466        bool noShift = (imm5 == 0 && shift_type != 0x3);
467        if (!noShift) {
468          args << ", ";
469          switch (shift_type) {
470            case 0x0: args << "lsl"; break;
471            case 0x1: args << "lsr"; break;
472            case 0x2: args << "asr"; break;
473            case 0x3:
474              if (imm5 == 0) {
475                args << "rrx";
476              } else {
477                args << "ror";
478              }
479              break;
480          }
481          if (shift_type != 0x3 /* rrx */) {
482            args << StringPrintf(" #%d", imm5);
483          }
484        }
485
486      } else if ((op2 & 0x40) == 0x40) {  // 1xx xxxx
487        // Co-processor instructions
488        // |111|1|11|000000|0000|1111|1100|000|0  |0000|
489        // |5 3|2|10|987654|3  0|54 2|10 8|7 5|4  |   0|
490        // |---|-|--|------|----|----|----|---|---|----|
491        // |332|2|22|222222|1111|1111|1100|000|0  |0000|
492        // |1 9|8|76|543210|9  6|54 2|10 8|7 5|4  |   0|
493        // |---|-|--|------|----|----|----|---|---|----|
494        // |111| |11| op3  | Rn |    |copr|   |op4|    |
495        uint32_t op3 = (instr >> 20) & 0x3F;
496        uint32_t coproc = (instr >> 8) & 0xF;
497        uint32_t op4 = (instr >> 4) & 0x1;
498        if ((op3 == 2 || op3 == 2 || op3 == 6 || op3 == 7) ||  // 00x1x
499            (op3 >= 8 && op3 <= 15) || (op3 >= 16 && op3 <= 31)) {  // 001xxx, 01xxxx
500          // Extension register load/store instructions
501          // |111|1|110|00000|0000|1111|110|000000000|
502          // |5 3|2|109|87654|3  0|54 2|10 |87 54   0|
503          // |---|-|---|-----|----|----|---|---------|
504          // |332|2|222|22222|1111|1111|110|000000000|
505          // |1 9|8|765|43210|9  6|54 2|10 |87 54   0|
506          // |---|-|---|-----|----|----|---|---------|
507          // |111|T|110| op3 | Rn |    |101|         |
508          //  111 0 110 01001 0011 0000 101 000000011 - ec930a03
509          if (op3 == 9 || op3 == 0xD) {  // VLDM
510            //  1110 110 PUDW1 nnnn dddd 101S iiii iiii
511            uint32_t P = (instr >> 24) & 1;
512            uint32_t U = (instr >> 23) & 1;
513            uint32_t D = (instr >> 22) & 1;
514            uint32_t W = (instr >> 21) & 1;
515            uint32_t S = (instr >> 8) & 1;
516            ArmRegister Rn(instr, 16);
517            uint32_t Vd = (instr >> 12) & 0xF;
518            uint32_t imm8 = instr & 0xFF;
519            uint32_t d = (S == 0 ? ((Vd << 1) | D) : (Vd | (D << 4)));
520            if (P == 0 && U == 0 && W == 0) {
521              // TODO: 64bit transfers between ARM core and extension registers.
522            } else if (P == 0 && U == 1 && Rn.r == 13) {  // VPOP
523              opcode << "vpop" << (S == 0 ? ".f64" : ".f32");
524              args << d << " .. " << (d + imm8);
525            } else if (P == 1 && W == 0) {  // VLDR
526              opcode << "vldr" << (S == 0 ? ".f64" : ".f32");
527              args << d << ", [" << Rn << ", #" << imm8 << "]";
528            } else {  // VLDM
529              opcode << "vldm" << (S == 0 ? ".f64" : ".f32");
530              args << Rn << ", " << d << " .. " << (d + imm8);
531            }
532          }
533        } else if ((op3 & 0x30) == 0x20 && op4 == 0) {  // 10 xxxx ... 0
534          if ((coproc & 0xE) == 0xA) {
535            // VFP data-processing instructions
536            // |111|1|1100|0000|0000|1111|110|0|00  |0|0|0000|
537            // |5 3|2|1098|7654|3  0|54 2|10 |8|76  |5|4|3  0|
538            // |---|-|----|----|----|----|---|-|----|-|-|----|
539            // |332|2|2222|2222|1111|1111|110|0|00  |0|0|0000|
540            // |1 9|8|7654|3210|9  6|54 2|109|8|76  |5|4|3  0|
541            // |---|-|----|----|----|----|---|-|----|-|-|----|
542            // |111|T|1110|opc1|opc2|    |101| |opc3| | |    |
543            //  111 0 1110|1111 0100 1110 101 0 01   1 0 1001 - eef4ea69
544            uint32_t opc1 = (instr >> 20) & 0xF;
545            uint32_t opc2 = (instr >> 16) & 0xF;
546            uint32_t opc3 = (instr >> 6) & 0x3;
547            if ((opc1 & 0xB) == 0xB) {  // 1x11
548              // Other VFP data-processing instructions.
549              uint32_t D  = (instr >> 22) & 0x1;
550              uint32_t Vd = (instr >> 12) & 0xF;
551              uint32_t sz = (instr >> 8) & 1;
552              uint32_t M  = (instr >> 5) & 1;
553              uint32_t Vm = instr & 0xF;
554              bool dp_operation = sz == 1;
555              switch (opc2) {
556                case 0x1:  // Vneg/Vsqrt
557                  //  1110 11101 D 11 0001 dddd 101s o1M0 mmmm
558                  opcode << (opc3 == 1 ? "vneg" : "vsqrt") << (dp_operation ? ".f64" : ".f32");
559                  if (dp_operation) {
560                    args << "f" << ((D << 4) | Vd) << ", " << "f" << ((M << 4) | Vm);
561                  } else {
562                    args << "f" << ((Vd << 1) | D) << ", " << "f" << ((Vm << 1) | M);
563                  }
564                  break;
565                case 0x4: case 0x5:  {  // Vector compare
566                  // 1110 11101 D 11 0100 dddd 101 sE1M0 mmmm
567                  opcode << (opc3 == 1 ? "vcmp" : "vcmpe") << (dp_operation ? ".f64" : ".f32");
568                  if (dp_operation) {
569                    args << "f" << ((D << 4) | Vd) << ", " << "f" << ((M << 4) | Vm);
570                  } else {
571                    args << "f" << ((Vd << 1) | D) << ", " << "f" << ((Vm << 1) | M);
572                  }
573                  break;
574                }
575              }
576            }
577          }
578        } else if ((op3 & 0x30) == 0x30) {  // 11 xxxx
579          // Advanced SIMD
580          if ((instr & 0xFFBF0ED0) == 0xeeb10ac0) {  // Vsqrt
581            //  1110 11101 D 11 0001 dddd 101S 11M0 mmmm
582            //  1110 11101 0 11 0001 1101 1011 1100 1000 - eeb1dbc8
583            uint32_t D = (instr >> 22) & 1;
584            uint32_t Vd = (instr >> 12) & 0xF;
585            uint32_t sz = (instr >> 8) & 1;
586            uint32_t M = (instr >> 5) & 1;
587            uint32_t Vm = instr & 0xF;
588            bool dp_operation = sz == 1;
589            opcode << "vsqrt" << (dp_operation ? ".f64" : ".f32");
590            if (dp_operation) {
591              args << "f" << ((D << 4) | Vd) << ", " << "f" << ((M << 4) | Vm);
592            } else {
593              args << "f" << ((Vd << 1) | D) << ", " << "f" << ((Vm << 1) | M);
594            }
595          }
596        }
597      }
598      break;
599    case 2:
600      if ((instr & 0x8000) == 0 && (op2 & 0x20) == 0) {
601        // Data-processing (modified immediate)
602        // |111|11|10|0000|0|0000|1|111|1100|00000000|
603        // |5 3|21|09|8765|4|3  0|5|4 2|10 8|7 5    0|
604        // |---|--|--|----|-|----|-|---|----|--------|
605        // |332|22|22|2222|2|1111|1|111|1100|00000000|
606        // |1 9|87|65|4321|0|9  6|5|4 2|10 8|7 5    0|
607        // |---|--|--|----|-|----|-|---|----|--------|
608        // |111|10|i0| op3|S| Rn |0|iii| Rd |iiiiiiii|
609        //  111 10 x0 xxxx x xxxx opxxx xxxx xxxxxxxx
610        uint32_t i = (instr >> 26) & 1;
611        uint32_t op3 = (instr >> 21) & 0xF;
612        uint32_t S = (instr >> 20) & 1;
613        ArmRegister Rn(instr, 16);
614        uint32_t imm3 = (instr >> 12) & 7;
615        ArmRegister Rd(instr, 8);
616        uint32_t imm8 = instr & 0xFF;
617        int32_t imm32 = (i << 11) | (imm3 << 8) | imm8;
618        if (Rn.r == 0xF && (op3 == 0x2 || op3 == 0x3)) {
619          if (op3 == 0x2) {
620            opcode << "mov";
621            if (S == 1) {
622              opcode << "s";
623            }
624            opcode << ".w";
625          } else {
626            opcode << "mvn";
627            if (S == 1) {
628              opcode << "s";
629            }
630          }
631          args << Rd << ", ThumbExpand(" << imm32 << ")";
632        } else if (Rd.r == 0xF && S == 1 &&
633                   (op3 == 0x0 || op3 == 0x4 || op3 == 0x8 || op3 == 0xD)) {
634          if (op3 == 0x0) {
635            opcode << "tst";
636          } else if (op3 == 0x4) {
637            opcode << "teq";
638          } else if (op3 == 0x8) {
639            opcode << "cmw";
640          } else {
641            opcode << "cmp.w";
642          }
643          args << Rn << ", ThumbExpand(" << imm32 << ")";
644        } else {
645          switch (op3) {
646            case 0x0: opcode << "and"; break;
647            case 0x1: opcode << "bic"; break;
648            case 0x2: opcode << "orr"; break;
649            case 0x3: opcode << "orn"; break;
650            case 0x4: opcode << "eor"; break;
651            case 0x8: opcode << "add"; break;
652            case 0xA: opcode << "adc"; break;
653            case 0xB: opcode << "sbc"; break;
654            case 0xD: opcode << "sub"; break;
655            case 0xE: opcode << "rsb"; break;
656            default: opcode << "UNKNOWN DPMI-" << op3; break;
657          }
658          if (S == 1) {
659            opcode << "s";
660          }
661          args << Rd << ", " << Rn << ", ThumbExpand(" << imm32 << ")";
662        }
663      } else if ((instr & 0x8000) == 0 && (op2 & 0x20) != 0) {
664        // Data-processing (plain binary immediate)
665        // |111|11|10|00000|0000|1|111110000000000|
666        // |5 3|21|09|87654|3  0|5|4   0    5    0|
667        // |---|--|--|-----|----|-|---------------|
668        // |332|22|22|22222|1111|1|111110000000000|
669        // |1 9|87|65|43210|9  6|5|4   0    5    0|
670        // |---|--|--|-----|----|-|---------------|
671        // |111|10|x1| op3 | Rn |0|xxxxxxxxxxxxxxx|
672        uint32_t op3 = (instr >> 20) & 0x1F;
673        switch (op3) {
674          case 0x00: case 0x0A: {
675            // ADD/SUB.W Rd, Rn #imm12 - 111 10 i1 0101 0 nnnn 0 iii dddd iiiiiiii
676            ArmRegister Rd(instr, 8);
677            ArmRegister Rn(instr, 16);
678            uint32_t i = (instr >> 26) & 1;
679            uint32_t imm3 = (instr >> 12) & 0x7;
680            uint32_t imm8 = instr & 0xFF;
681            uint32_t imm12 = (i << 11) | (imm3 << 8) | imm8;
682            if (Rn.r != 0xF) {
683              opcode << (op3 == 0 ? "addw" : "subw");
684              args << Rd << ", " << Rn << ", #" << imm12;
685            } else {
686              opcode << "adr";
687              args << Rd << ", ";
688              DumpBranchTarget(args, instr_ptr + 4, (op3 == 0) ? imm12 : -imm12);
689            }
690            break;
691          }
692          case 0x04: case 0x0C: {
693            // MOVW/T Rd, #imm16     - 111 10 i0 0010 0 iiii 0 iii dddd iiiiiiii
694            ArmRegister Rd(instr, 8);
695            uint32_t i = (instr >> 26) & 1;
696            uint32_t imm3 = (instr >> 12) & 0x7;
697            uint32_t imm8 = instr & 0xFF;
698            uint32_t Rn = (instr >> 16) & 0xF;
699            uint32_t imm16 = (Rn << 12) | (i << 11) | (imm3 << 8) | imm8;
700            opcode << (op3 == 0x04 ? "movw" : "movt");
701            args << Rd << ", #" << imm16;
702            break;
703          }
704          case 0x16: {
705            // BFI Rd, Rn, #lsb, #width - 111 10 0 11 011 0 nnnn 0 iii dddd ii 0 iiiii
706            ArmRegister Rd(instr, 8);
707            ArmRegister Rn(instr, 16);
708            uint32_t msb = instr & 0x1F;
709            uint32_t imm2 = (instr >> 6) & 0x3;
710            uint32_t imm3 = (instr >> 12) & 0x7;
711            uint32_t lsb = (imm3 << 2) | imm2;
712            uint32_t width = msb - lsb + 1;
713            if (Rn.r != 0xF) {
714              opcode << "bfi";
715              args << Rd << ", " << Rn << ", #" << lsb << ", #" << width;
716            } else {
717              opcode << "bfc";
718              args << Rd << ", #" << lsb << ", #" << width;
719            }
720            break;
721          }
722          default:
723            break;
724        }
725      } else {
726        // Branches and miscellaneous control
727        // |111|11|1000000|0000|1|111|1100|00000000|
728        // |5 3|21|0987654|3  0|5|4 2|10 8|7 5    0|
729        // |---|--|-------|----|-|---|----|--------|
730        // |332|22|2222222|1111|1|111|1100|00000000|
731        // |1 9|87|6543210|9  6|5|4 2|10 8|7 5    0|
732        // |---|--|-------|----|-|---|----|--------|
733        // |111|10| op2   |    |1|op3|op4 |        |
734
735        uint32_t op3 = (instr >> 12) & 7;
736        // uint32_t op4 = (instr >> 8) & 0xF;
737        switch (op3) {
738          case 0:
739            if ((op2 & 0x38) != 0x38) {
740              // Conditional branch
741              // |111|11|1|0000|000000|1|1|1 |1|1 |10000000000|
742              // |5 3|21|0|9876|543  0|5|4|3 |2|1 |0    5    0|
743              // |---|--|-|----|------|-|-|--|-|--|-----------|
744              // |332|22|2|2222|221111|1|1|1 |1|1 |10000000000|
745              // |1 9|87|6|5432|109  6|5|4|3 |2|1 |0    5    0|
746              // |---|--|-|----|------|-|-|--|-|--|-----------|
747              // |111|10|S|cond| imm6 |1|0|J1|0|J2| imm11     |
748              uint32_t S = (instr >> 26) & 1;
749              uint32_t J2 = (instr >> 11) & 1;
750              uint32_t J1 = (instr >> 13) & 1;
751              uint32_t imm6 = (instr >> 16) & 0x3F;
752              uint32_t imm11 = instr & 0x7FF;
753              uint32_t cond = (instr >> 22) & 0xF;
754              int32_t imm32 = (S << 20) |  (J2 << 19) | (J1 << 18) | (imm6 << 12) | (imm11 << 1);
755              imm32 = (imm32 << 11) >> 11;  // sign extend 21bit immediate
756              opcode << "b";
757              DumpCond(opcode, cond);
758              opcode << ".w";
759              DumpBranchTarget(args, instr_ptr + 4, imm32);
760            } else if (op2 == 0x3B) {
761              // Miscellaneous control instructions
762              uint32_t op5 = (instr >> 4) & 0xF;
763              switch (op5) {
764                case 4: opcode << "dsb"; break;
765                case 5: opcode << "dmb"; break;
766                case 6: opcode << "isb"; break;
767              }
768            }
769            break;
770          case 2:
771            if ((op2 & 0x38) == 0x38) {
772              if (op2 == 0x7F) {
773                opcode << "udf";
774              }
775              break;
776            }
777            // Else deliberate fall-through to B.
778          case 1: case 3: {
779            // B
780            // |111|11|1|0000|000000|11|1 |1|1 |10000000000|
781            // |5 3|21|0|9876|543  0|54|3 |2|1 |0    5    0|
782            // |---|--|-|----|------|--|--|-|--|-----------|
783            // |332|22|2|2222|221111|11|1 |1|1 |10000000000|
784            // |1 9|87|6|5  2|10   6|54|3 |2|1 |0    5    0|
785            // |---|--|-|----|------|--|--|-|--|-----------|
786            // |111|10|S|cond| imm6 |10|J1|0|J2| imm11     |
787            // |111|10|S| imm10     |10|J1|1|J2| imm11     |
788            uint32_t S = (instr >> 26) & 1;
789            uint32_t cond = (instr >> 22) & 0xF;
790            uint32_t J2 = (instr >> 11) & 1;
791            uint32_t form = (instr >> 12) & 1;
792            uint32_t J1 = (instr >> 13) & 1;
793            uint32_t imm10 = (instr >> 16) & 0x3FF;
794            uint32_t imm6  = (instr >> 16) & 0x3F;
795            uint32_t imm11 = instr & 0x7FF;
796            opcode << "b";
797            int32_t imm32;
798            if (form == 0) {
799              DumpCond(opcode, cond);
800              imm32 = (S << 20) | (J2 << 19) | (J1 << 18) | (imm6 << 12) | (imm11 << 1);
801              imm32 = (imm32 << 11) >> 11;  // sign extend 21 bit immediate.
802            } else {
803              uint32_t I1 = ~(J1 ^ S);
804              uint32_t I2 = ~(J2 ^ S);
805              imm32 = (S << 24) | (I1 << 23) | (I2 << 22) | (imm10 << 12) | (imm11 << 1);
806              imm32 = (imm32 << 8) >> 8;  // sign extend 24 bit immediate.
807            }
808            opcode << ".w";
809            DumpBranchTarget(args, instr_ptr + 4, imm32);
810            break;
811          }
812          case 4: case 6: case 5: case 7: {
813            // BL, BLX (immediate)
814            // |111|11|1|0000000000|11|1 |1|1 |10000000000|
815            // |5 3|21|0|9876543  0|54|3 |2|1 |0    5    0|
816            // |---|--|-|----------|--|--|-|--|-----------|
817            // |332|22|2|2222221111|11|1 |1|1 |10000000000|
818            // |1 9|87|6|5    0   6|54|3 |2|1 |0    5    0|
819            // |---|--|-|----------|--|--|-|--|-----------|
820            // |111|10|S| imm10    |11|J1|L|J2| imm11     |
821            uint32_t S = (instr >> 26) & 1;
822            uint32_t J2 = (instr >> 11) & 1;
823            uint32_t L = (instr >> 12) & 1;
824            uint32_t J1 = (instr >> 13) & 1;
825            uint32_t imm10 = (instr >> 16) & 0x3FF;
826            uint32_t imm11 = instr & 0x7FF;
827            if (L == 0) {
828              opcode << "bx";
829            } else {
830              opcode << "blx";
831            }
832            uint32_t I1 = ~(J1 ^ S);
833            uint32_t I2 = ~(J2 ^ S);
834            int32_t imm32 = (S << 24) | (I1 << 23) | (I2 << 22) | (imm10 << 12) | (imm11 << 1);
835            imm32 = (imm32 << 8) >> 8;  // sign extend 24 bit immediate.
836            DumpBranchTarget(args, instr_ptr + 4, imm32);
837            break;
838          }
839        }
840      }
841      break;
842    case 3:
843      switch (op2) {
844        case 0x00: case 0x02: case 0x04: case 0x06:  // 000xxx0
845        case 0x08: case 0x0A: case 0x0C: case 0x0E: {
846          // Store single data item
847          // |111|11|100|000|0|0000|1111|110000|000000|
848          // |5 3|21|098|765|4|3  0|5  2|10   6|5    0|
849          // |---|--|---|---|-|----|----|------|------|
850          // |332|22|222|222|2|1111|1111|110000|000000|
851          // |1 9|87|654|321|0|9  6|5  2|10   6|5    0|
852          // |---|--|---|---|-|----|----|------|------|
853          // |111|11|000|op3|0|    |    |  op4 |      |
854          uint32_t op3 = (instr >> 21) & 7;
855          // uint32_t op4 = (instr >> 6) & 0x3F;
856          switch (op3) {
857            case 0x0: case 0x4: {
858              // STRB Rt,[Rn,#+/-imm8]     - 111 11 00 0 0 00 0 nnnn tttt 1 PUWii ii iiii
859              // STRB Rt,[Rn,Rm,lsl #imm2] - 111 11 00 0 0 00 0 nnnn tttt 0 00000 ii mmmm
860              ArmRegister Rn(instr, 16);
861              ArmRegister Rt(instr, 12);
862              opcode << "strb";
863              if ((instr & 0x800) != 0) {
864                uint32_t imm8 = instr & 0xFF;
865                args << Rt << ", [" << Rn << ",#" << imm8 << "]";
866              } else {
867                uint32_t imm2 = (instr >> 4) & 3;
868                ArmRegister Rm(instr, 0);
869                args << Rt << ", [" << Rn << ", " << Rm;
870                if (imm2 != 0) {
871                  args << ", " << "lsl #" << imm2;
872                }
873                args << "]";
874              }
875              break;
876            }
877            case 0x2: case 0x6: {
878              ArmRegister Rn(instr, 16);
879              ArmRegister Rt(instr, 12);
880              if (op3 == 2) {
881                if ((instr & 0x800) != 0) {
882                  // STR Rt, [Rn, #imm8] - 111 11 000 010 0 nnnn tttt 1PUWiiiiiiii
883                  uint32_t P = (instr >> 10) & 1;
884                  uint32_t U = (instr >> 9) & 1;
885                  uint32_t W = (instr >> 8) & 1;
886                  uint32_t imm8 = instr & 0xFF;
887                  int32_t imm32 = (imm8 << 24) >> 24;  // sign-extend imm8
888                  if (Rn.r == 13 && P == 1 && U == 0 && W == 1 && imm32 == 4) {
889                    opcode << "push";
890                    args << Rt;
891                  } else if (Rn.r == 15 || (P == 0 && W == 0)) {
892                    opcode << "UNDEFINED";
893                  } else {
894                    if (P == 1 && U == 1 && W == 0) {
895                      opcode << "strt";
896                    } else {
897                      opcode << "str";
898                    }
899                    args << Rt << ", [" << Rn;
900                    if (P == 0 && W == 1) {
901                      args << "], #" << imm32;
902                    } else {
903                      args << ", #" << imm32 << "]";
904                      if (W == 1) {
905                        args << "!";
906                      }
907                    }
908                  }
909                } else {
910                  // STR Rt, [Rn, Rm, LSL #imm2] - 111 11 000 010 0 nnnn tttt 000000iimmmm
911                  ArmRegister Rn(instr, 16);
912                  ArmRegister Rt(instr, 12);
913                  ArmRegister Rm(instr, 0);
914                  uint32_t imm2 = (instr >> 4) & 3;
915                  opcode << "str.w";
916                  args << Rt << ", [" << Rn << ", " << Rm;
917                  if (imm2 != 0) {
918                    args << ", lsl #" << imm2;
919                  }
920                  args << "]";
921                }
922              } else if (op3 == 6) {
923                // STR.W Rt, [Rn, #imm12] - 111 11 000 110 0 nnnn tttt iiiiiiiiiiii
924                uint32_t imm12 = instr & 0xFFF;
925                opcode << "str.w";
926                args << Rt << ", [" << Rn << ", #" << imm12 << "]";
927              }
928              break;
929            }
930          }
931
932          break;
933        }
934        case 0x03: case 0x0B: case 0x13: case 0x1B: {  // 00xx011
935          // Load halfword
936          // |111|11|10|0 0|00|0|0000|1111|110000|000000|
937          // |5 3|21|09|8 7|65|4|3  0|5  2|10   6|5    0|
938          // |---|--|--|---|--|-|----|----|------|------|
939          // |332|22|22|2 2|22|2|1111|1111|110000|000000|
940          // |1 9|87|65|4 3|21|0|9  6|5  2|10   6|5    0|
941          // |---|--|--|---|--|-|----|----|------|------|
942          // |111|11|00|op3|01|1| Rn | Rt | op4  |      |
943          // |111|11| op2       |    |    | imm12       |
944          uint32_t op3 = (instr >> 23) & 3;
945          ArmRegister Rn(instr, 16);
946          ArmRegister Rt(instr, 12);
947          if (Rt.r != 15) {
948            if (op3 == 1) {
949              // LDRH.W Rt, [Rn, #imm12]       - 111 11 00 01 011 nnnn tttt iiiiiiiiiiii
950              uint32_t imm12 = instr & 0xFFF;
951              opcode << "ldrh.w";
952              args << Rt << ", [" << Rn << ", #" << imm12 << "]";
953              if (Rn.r == 9) {
954                args << "  ; ";
955                Thread::DumpThreadOffset(args, imm12, 4);
956              } else if (Rn.r == 15) {
957                intptr_t lit_adr = reinterpret_cast<intptr_t>(instr_ptr);
958                lit_adr = RoundDown(lit_adr, 4) + 4 + imm12;
959                args << "  ; " << reinterpret_cast<void*>(*reinterpret_cast<int32_t*>(lit_adr));
960              }
961            } else if (op3 == 3) {
962              // LDRSH.W Rt, [Rn, #imm12]      - 111 11 00 11 011 nnnn tttt iiiiiiiiiiii
963              uint32_t imm12 = instr & 0xFFF;
964              opcode << "ldrsh.w";
965              args << Rt << ", [" << Rn << ", #" << imm12 << "]";
966              if (Rn.r == 9) {
967                args << "  ; ";
968                Thread::DumpThreadOffset(args, imm12, 4);
969              } else if (Rn.r == 15) {
970                intptr_t lit_adr = reinterpret_cast<intptr_t>(instr_ptr);
971                lit_adr = RoundDown(lit_adr, 4) + 4 + imm12;
972                args << "  ; " << reinterpret_cast<void*>(*reinterpret_cast<int32_t*>(lit_adr));
973              }
974            }
975          }
976          break;
977        }
978        case 0x05: case 0x0D: case 0x15: case 0x1D: {  // 00xx101
979          // Load word
980          // |111|11|10|0 0|00|0|0000|1111|110000|000000|
981          // |5 3|21|09|8 7|65|4|3  0|5  2|10   6|5    0|
982          // |---|--|--|---|--|-|----|----|------|------|
983          // |332|22|22|2 2|22|2|1111|1111|110000|000000|
984          // |1 9|87|65|4 3|21|0|9  6|5  2|10   6|5    0|
985          // |---|--|--|---|--|-|----|----|------|------|
986          // |111|11|00|op3|10|1| Rn | Rt | op4  |      |
987          // |111|11| op2       |    |    | imm12       |
988          uint32_t op3 = (instr >> 23) & 3;
989          uint32_t op4 = (instr >> 6) & 0x3F;
990          ArmRegister Rn(instr, 16);
991          ArmRegister Rt(instr, 12);
992          if (op3 == 1 || Rn.r == 15) {
993            // LDR.W Rt, [Rn, #imm12]          - 111 11 00 00 101 nnnn tttt iiiiiiiiiiii
994            // LDR.W Rt, [PC, #imm12]          - 111 11 00 0x 101 1111 tttt iiiiiiiiiiii
995            uint32_t imm12 = instr & 0xFFF;
996            opcode << "ldr.w";
997            args << Rt << ", [" << Rn << ", #" << imm12 << "]";
998            if (Rn.r == 9) {
999              args << "  ; ";
1000              Thread::DumpThreadOffset(args, imm12, 4);
1001            } else if (Rn.r == 15) {
1002              intptr_t lit_adr = reinterpret_cast<intptr_t>(instr_ptr);
1003              lit_adr = RoundDown(lit_adr, 4) + 4 + imm12;
1004              args << "  ; " << reinterpret_cast<void*>(*reinterpret_cast<int32_t*>(lit_adr));
1005            }
1006          } else if (op4 == 0) {
1007            // LDR.W Rt, [Rn, Rm{, LSL #imm2}] - 111 11 00 00 101 nnnn tttt 000000iimmmm
1008            uint32_t imm2 = (instr >> 4) & 0xF;
1009            ArmRegister rm(instr, 0);
1010            opcode << "ldr.w";
1011            args << Rt << ", [" << Rn << ", " << rm;
1012            if (imm2 != 0) {
1013              args << ", lsl #" << imm2;
1014            }
1015            args << "]";
1016          } else {
1017            // LDRT Rt, [Rn, #imm8]            - 111 11 00 00 101 nnnn tttt 1110iiiiiiii
1018            uint32_t imm8 = instr & 0xFF;
1019            opcode << "ldrt";
1020            args << Rt << ", [" << Rn << ", #" << imm8 << "]";
1021          }
1022          break;
1023        }
1024      }
1025    default:
1026      break;
1027  }
1028
1029  // Apply any IT-block conditions to the opcode if necessary.
1030  if (!it_conditions_.empty()) {
1031    opcode << it_conditions_.back();
1032    it_conditions_.pop_back();
1033  }
1034
1035  os << StringPrintf("%p: %08x\t%-7s ", instr_ptr, instr, opcode.str().c_str()) << args.str() << '\n';
1036  return 4;
1037}  // NOLINT(readability/fn_size)
1038
1039size_t DisassemblerArm::DumpThumb16(std::ostream& os, const uint8_t* instr_ptr) {
1040  uint16_t instr = ReadU16(instr_ptr);
1041  bool is_32bit = ((instr & 0xF000) == 0xF000) || ((instr & 0xF800) == 0xE800);
1042  if (is_32bit) {
1043    return DumpThumb32(os, instr_ptr);
1044  } else {
1045    std::ostringstream opcode;
1046    std::ostringstream args;
1047    uint16_t opcode1 = instr >> 10;
1048    if (opcode1 < 0x10) {
1049      // shift (immediate), add, subtract, move, and compare
1050      uint16_t opcode2 = instr >> 9;
1051      switch (opcode2) {
1052        case 0x0: case 0x1: case 0x2: case 0x3: case 0x4: case 0x5: case 0x6: case 0x7:
1053        case 0x8: case 0x9: case 0xA: case 0xB: {
1054          // Logical shift left     - 00 000xx iii mmm ddd
1055          // Logical shift right    - 00 001xx iii mmm ddd
1056          // Arithmetic shift right - 00 010xx iii mmm ddd
1057          uint16_t imm5 = (instr >> 6) & 0x1F;
1058          ThumbRegister rm(instr, 3);
1059          ThumbRegister Rd(instr, 0);
1060          if (opcode2 <= 3) {
1061            opcode << "lsls";
1062          } else if (opcode2 <= 7) {
1063            opcode << "lsrs";
1064          } else {
1065            opcode << "asrs";
1066          }
1067          args << Rd << ", " << rm << ", #" << imm5;
1068          break;
1069        }
1070        case 0xC: case 0xD: case 0xE: case 0xF: {
1071          // Add register        - 00 01100 mmm nnn ddd
1072          // Sub register        - 00 01101 mmm nnn ddd
1073          // Add 3-bit immediate - 00 01110 iii nnn ddd
1074          // Sub 3-bit immediate - 00 01111 iii nnn ddd
1075          uint16_t imm3_or_Rm = (instr >> 6) & 7;
1076          ThumbRegister Rn(instr, 3);
1077          ThumbRegister Rd(instr, 0);
1078          if ((opcode2 & 2) != 0 && imm3_or_Rm == 0) {
1079            opcode << "mov";
1080          } else {
1081            if ((opcode2 & 1) == 0) {
1082              opcode << "adds";
1083            } else {
1084              opcode << "subs";
1085            }
1086          }
1087          args << Rd << ", " << Rn;
1088          if ((opcode2 & 2) == 0) {
1089            ArmRegister Rm(imm3_or_Rm);
1090            args << ", " << Rm;
1091          } else if (imm3_or_Rm != 0) {
1092            args << ", #" << imm3_or_Rm;
1093          }
1094          break;
1095        }
1096        case 0x10: case 0x11: case 0x12: case 0x13:
1097        case 0x14: case 0x15: case 0x16: case 0x17:
1098        case 0x18: case 0x19: case 0x1A: case 0x1B:
1099        case 0x1C: case 0x1D: case 0x1E: case 0x1F: {
1100          // MOVS Rd, #imm8 - 00100 ddd iiiiiiii
1101          // CMP  Rn, #imm8 - 00101 nnn iiiiiiii
1102          // ADDS Rn, #imm8 - 00110 nnn iiiiiiii
1103          // SUBS Rn, #imm8 - 00111 nnn iiiiiiii
1104          ThumbRegister Rn(instr, 8);
1105          uint16_t imm8 = instr & 0xFF;
1106          switch (opcode2 >> 2) {
1107            case 4: opcode << "movs"; break;
1108            case 5: opcode << "cmp"; break;
1109            case 6: opcode << "adds"; break;
1110            case 7: opcode << "subs"; break;
1111          }
1112          args << Rn << ", #" << imm8;
1113          break;
1114        }
1115        default:
1116          break;
1117      }
1118    } else if (opcode1 == 0x10) {
1119      // Data-processing
1120      uint16_t opcode2 = (instr >> 6) & 0xF;
1121      ThumbRegister rm(instr, 3);
1122      ThumbRegister rdn(instr, 0);
1123      opcode << kThumbDataProcessingOperations[opcode2];
1124      args << rdn << ", " << rm;
1125    } else if (opcode1 == 0x11) {
1126      // Special data instructions and branch and exchange
1127      uint16_t opcode2 = (instr >> 6) & 0x0F;
1128      switch (opcode2) {
1129        case 0x0: case 0x1: case 0x2: case 0x3: {
1130          // Add low registers  - 010001 0000 xxxxxx
1131          // Add high registers - 010001 0001/001x xxxxxx
1132          uint16_t DN = (instr >> 7) & 1;
1133          ArmRegister rm(instr, 3);
1134          uint16_t Rdn = instr & 7;
1135          ArmRegister DN_Rdn((DN << 3) | Rdn);
1136          opcode << "add";
1137          args << DN_Rdn << ", " << rm;
1138          break;
1139        }
1140        case 0x8: case 0x9: case 0xA: case 0xB: {
1141          // Move low registers  - 010001 1000 xxxxxx
1142          // Move high registers - 010001 1001/101x xxxxxx
1143          uint16_t DN = (instr >> 7) & 1;
1144          ArmRegister rm(instr, 3);
1145          uint16_t Rdn = instr & 7;
1146          ArmRegister DN_Rdn((DN << 3) | Rdn);
1147          opcode << "mov";
1148          args << DN_Rdn << ", " << rm;
1149          break;
1150        }
1151        case 0x5: case 0x6: case 0x7: {
1152          // Compare high registers - 010001 0101/011x xxxxxx
1153          uint16_t N = (instr >> 7) & 1;
1154          ArmRegister rm(instr, 3);
1155          uint16_t Rn = instr & 7;
1156          ArmRegister N_Rn((N << 3) | Rn);
1157          opcode << "cmp";
1158          args << N_Rn << ", " << rm;
1159          break;
1160        }
1161        case 0xC: case 0xD: case 0xE: case 0xF: {
1162          // Branch and exchange           - 010001 110x xxxxxx
1163          // Branch with link and exchange - 010001 111x xxxxxx
1164          ArmRegister rm(instr, 3);
1165          opcode << ((opcode2 & 0x2) == 0 ? "bx" : "blx");
1166          args << rm;
1167          break;
1168        }
1169        default:
1170          break;
1171      }
1172    } else if (opcode1 == 0x12 || opcode1 == 0x13) {  // 01001x
1173      ThumbRegister Rt(instr, 8);
1174      uint16_t imm8 = instr & 0xFF;
1175      opcode << "ldr";
1176      args << Rt << ", [pc, #" << (imm8 << 2) << "]";
1177    } else if ((opcode1 >= 0x14 && opcode1 <= 0x17) ||  // 0101xx
1178               (opcode1 >= 0x18 && opcode1 <= 0x1f) ||  // 011xxx
1179               (opcode1 >= 0x20 && opcode1 <= 0x27)) {  // 100xxx
1180      // Load/store single data item
1181      uint16_t opA = (instr >> 12) & 0xF;
1182      if (opA == 0x5) {
1183        uint16_t opB = (instr >> 9) & 0x7;
1184        ThumbRegister Rm(instr, 6);
1185        ThumbRegister Rn(instr, 3);
1186        ThumbRegister Rt(instr, 0);
1187        switch (opB) {
1188          case 0: opcode << "str"; break;
1189          case 1: opcode << "strh"; break;
1190          case 2: opcode << "strb"; break;
1191          case 3: opcode << "ldrsb"; break;
1192          case 4: opcode << "ldr"; break;
1193          case 5: opcode << "ldrh"; break;
1194          case 6: opcode << "ldrb"; break;
1195          case 7: opcode << "ldrsh"; break;
1196        }
1197        args << Rt << ", [" << Rn << ", " << Rm << "]";
1198      } else if (opA == 9) {
1199        uint16_t opB = (instr >> 11) & 1;
1200        ThumbRegister Rt(instr, 8);
1201        uint16_t imm8 = instr & 0xFF;
1202        opcode << (opB == 0 ? "str" : "ldr");
1203        args << Rt << ", [sp, #" << (imm8 << 2) << "]";
1204      } else {
1205        uint16_t imm5 = (instr >> 6) & 0x1F;
1206        uint16_t opB = (instr >> 11) & 1;
1207        ThumbRegister Rn(instr, 3);
1208        ThumbRegister Rt(instr, 0);
1209        switch (opA) {
1210          case 6:
1211            imm5 <<= 2;
1212            opcode << (opB == 0 ? "str" : "ldr");
1213            break;
1214          case 7:
1215            imm5 <<= 0;
1216            opcode << (opB == 0 ? "strb" : "ldrb");
1217            break;
1218          case 8:
1219            imm5 <<= 1;
1220            opcode << (opB == 0 ? "strh" : "ldrh");
1221            break;
1222        }
1223        args << Rt << ", [" << Rn << ", #" << imm5 << "]";
1224      }
1225    } else if (opcode1 >= 0x34 && opcode1 <= 0x37) {  // 1101xx
1226      int8_t imm8 = instr & 0xFF;
1227      uint32_t cond = (instr >> 8) & 0xF;
1228      opcode << "b";
1229      DumpCond(opcode, cond);
1230      DumpBranchTarget(args, instr_ptr + 4, (imm8 << 1));
1231    } else if ((instr & 0xF800) == 0xA800) {
1232      // Generate SP-relative address
1233      ThumbRegister rd(instr, 8);
1234      int imm8 = instr & 0xFF;
1235      opcode << "add";
1236      args << rd << ", sp, #" << (imm8 << 2);
1237    } else if ((instr & 0xF000) == 0xB000) {
1238      // Miscellaneous 16-bit instructions
1239      uint16_t opcode2 = (instr >> 5) & 0x7F;
1240      switch (opcode2) {
1241        case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07: {
1242          // Add immediate to SP        - 1011 00000 ii iiiii
1243          // Subtract immediate from SP - 1011 00001 ii iiiii
1244          int imm7 = instr & 0x7F;
1245          opcode << ((opcode2 & 4) == 0 ? "add" : "sub");
1246          args << "sp, sp, #" << (imm7 << 2);
1247          break;
1248        }
1249        case 0x08: case 0x09: case 0x0A: case 0x0B:  // 0001xxx
1250        case 0x0C: case 0x0D: case 0x0E: case 0x0F:
1251        case 0x18: case 0x19: case 0x1A: case 0x1B:  // 0011xxx
1252        case 0x1C: case 0x1D: case 0x1E: case 0x1F:
1253        case 0x48: case 0x49: case 0x4A: case 0x4B:  // 1001xxx
1254        case 0x4C: case 0x4D: case 0x4E: case 0x4F:
1255        case 0x58: case 0x59: case 0x5A: case 0x5B:  // 1011xxx
1256        case 0x5C: case 0x5D: case 0x5E: case 0x5F: {
1257          // CBNZ, CBZ
1258          uint16_t op = (instr >> 11) & 1;
1259          uint16_t i = (instr >> 9) & 1;
1260          uint16_t imm5 = (instr >> 3) & 0x1F;
1261          ThumbRegister Rn(instr, 0);
1262          opcode << (op != 0 ? "cbnz" : "cbz");
1263          uint32_t imm32 = (i << 6) | (imm5 << 1);
1264          args << Rn << ", ";
1265          DumpBranchTarget(args, instr_ptr + 4, imm32);
1266          break;
1267        }
1268        case 0x78: case 0x79: case 0x7A: case 0x7B:  // 1111xxx
1269        case 0x7C: case 0x7D: case 0x7E: case 0x7F: {
1270          // If-Then, and hints
1271          uint16_t opA = (instr >> 4) & 0xF;
1272          uint16_t opB = instr & 0xF;
1273          if (opB == 0) {
1274            switch (opA) {
1275              case 0: opcode << "nop"; break;
1276              case 1: opcode << "yield"; break;
1277              case 2: opcode << "wfe";  break;
1278              case 3: opcode << "sev"; break;
1279              default: break;
1280            }
1281          } else {
1282            uint32_t first_cond = opA;
1283            uint32_t mask = opB;
1284            opcode << "it";
1285
1286            // Flesh out the base "it" opcode with the specific collection of 't's and 'e's,
1287            // and store up the actual condition codes we'll want to add to the next few opcodes.
1288            size_t count = 3 - CTZ(mask);
1289            it_conditions_.resize(count + 2);  // Plus the implicit 't', plus the "" for the IT itself.
1290            for (size_t i = 0; i < count; ++i) {
1291              bool positive_cond = ((first_cond & 1) != 0);
1292              bool positive_mask = ((mask & (1 << (3 - i))) != 0);
1293              if (positive_mask == positive_cond) {
1294                opcode << 't';
1295                it_conditions_[i] = kConditionCodeNames[first_cond];
1296              } else {
1297                opcode << 'e';
1298                it_conditions_[i] = kConditionCodeNames[first_cond ^ 1];
1299              }
1300            }
1301            it_conditions_[count] = kConditionCodeNames[first_cond];  // The implicit 't'.
1302
1303            it_conditions_[count + 1] = "";  // No condition code for the IT itself...
1304            DumpCond(args, first_cond);  // ...because it's considered an argument.
1305          }
1306          break;
1307        }
1308        default:
1309          break;
1310      }
1311    } else if (((instr & 0xF000) == 0x5000) || ((instr & 0xE000) == 0x6000) ||
1312        ((instr & 0xE000) == 0x8000)) {
1313      // Load/store single data item
1314      uint16_t opA = instr >> 12;
1315      // uint16_t opB = (instr >> 9) & 7;
1316      switch (opA) {
1317        case 0x6: {
1318          // STR Rt, [Rn, #imm] - 01100 iiiii nnn ttt
1319          // LDR Rt, [Rn, #imm] - 01101 iiiii nnn ttt
1320          uint16_t imm5 = (instr >> 6) & 0x1F;
1321          ThumbRegister Rn(instr, 3);
1322          ThumbRegister Rt(instr, 0);
1323          opcode << ((instr & 0x800) == 0 ? "str" : "ldr");
1324          args << Rt << ", [" << Rn << ", #" << (imm5 << 2) << "]";
1325          break;
1326        }
1327        case 0x9: {
1328          // STR Rt, [SP, #imm] - 01100 ttt iiiiiiii
1329          // LDR Rt, [SP, #imm] - 01101 ttt iiiiiiii
1330          uint16_t imm8 = instr & 0xFF;
1331          ThumbRegister Rt(instr, 8);
1332          opcode << ((instr & 0x800) == 0 ? "str" : "ldr");
1333          args << Rt << ", [sp, #" << (imm8 << 2) << "]";
1334          break;
1335        }
1336        default:
1337          break;
1338      }
1339    } else if (opcode1 == 0x38 || opcode1 == 0x39) {
1340      uint16_t imm11 = instr & 0x7FFF;
1341      int32_t imm32 = imm11 << 1;
1342      imm32 = (imm32 << 20) >> 20;  // sign extend 12 bit immediate
1343      opcode << "b";
1344      DumpBranchTarget(args, instr_ptr + 4, imm32);
1345    }
1346
1347    // Apply any IT-block conditions to the opcode if necessary.
1348    if (!it_conditions_.empty()) {
1349      opcode << it_conditions_.back();
1350      it_conditions_.pop_back();
1351    }
1352
1353    os << StringPrintf("%p: %04x    \t%-7s ", instr_ptr, instr, opcode.str().c_str()) << args.str() << '\n';
1354  }
1355  return 2;
1356}
1357
1358}  // namespace arm
1359}  // namespace art
1360