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 <inttypes.h>
20
21 #include <iostream>
22
23 #include "base/logging.h"
24 #include "base/stringprintf.h"
25 #include "thread.h"
26
27 namespace art {
28 namespace arm {
29
Dump(std::ostream & os,const uint8_t * begin)30 size_t DisassemblerArm::Dump(std::ostream& os, const uint8_t* begin) {
31 if ((reinterpret_cast<intptr_t>(begin) & 1) == 0) {
32 DumpArm(os, begin);
33 return 4;
34 } else {
35 // remove thumb specifier bits
36 begin = reinterpret_cast<const uint8_t*>(reinterpret_cast<uintptr_t>(begin) & ~1);
37 return DumpThumb16(os, begin);
38 }
39 }
40
Dump(std::ostream & os,const uint8_t * begin,const uint8_t * end)41 void DisassemblerArm::Dump(std::ostream& os, const uint8_t* begin, const uint8_t* end) {
42 if ((reinterpret_cast<intptr_t>(begin) & 1) == 0) {
43 for (const uint8_t* cur = begin; cur < end; cur += 4) {
44 DumpArm(os, cur);
45 }
46 } else {
47 // remove thumb specifier bits
48 begin = reinterpret_cast<const uint8_t*>(reinterpret_cast<uintptr_t>(begin) & ~1);
49 end = reinterpret_cast<const uint8_t*>(reinterpret_cast<uintptr_t>(end) & ~1);
50 for (const uint8_t* cur = begin; cur < end;) {
51 cur += DumpThumb16(os, cur);
52 }
53 }
54 }
55
56 static const char* kConditionCodeNames[] = {
57 "eq", // 0000 - equal
58 "ne", // 0001 - not-equal
59 "cs", // 0010 - carry-set, greater than, equal or unordered
60 "cc", // 0011 - carry-clear, less than
61 "mi", // 0100 - minus, negative
62 "pl", // 0101 - plus, positive or zero
63 "vs", // 0110 - overflow
64 "vc", // 0111 - no overflow
65 "hi", // 1000 - unsigned higher
66 "ls", // 1001 - unsigned lower or same
67 "ge", // 1010 - signed greater than or equal
68 "lt", // 1011 - signed less than
69 "gt", // 1100 - signed greater than
70 "le", // 1101 - signed less than or equal
71 "", // 1110 - always
72 "nv", // 1111 - never (mostly obsolete, but might be a clue that we're mistranslating)
73 };
74
DumpCond(std::ostream & os,uint32_t cond)75 void DisassemblerArm::DumpCond(std::ostream& os, uint32_t cond) {
76 if (cond < 15) {
77 os << kConditionCodeNames[cond];
78 } else {
79 os << "Unexpected condition: " << cond;
80 }
81 }
82
DumpMemoryDomain(std::ostream & os,uint32_t domain)83 void DisassemblerArm::DumpMemoryDomain(std::ostream& os, uint32_t domain) {
84 switch (domain) {
85 case 0b1111: os << "sy"; break;
86 case 0b1110: os << "st"; break;
87 case 0b1011: os << "ish"; break;
88 case 0b1010: os << "ishst"; break;
89 case 0b0111: os << "nsh"; break;
90 case 0b0110: os << "nshst"; break;
91 case 0b0011: os << "osh"; break;
92 case 0b0010: os << "oshst"; break;
93 }
94 }
95
DumpBranchTarget(std::ostream & os,const uint8_t * instr_ptr,int32_t imm32)96 void DisassemblerArm::DumpBranchTarget(std::ostream& os, const uint8_t* instr_ptr, int32_t imm32) {
97 os << StringPrintf("%+d (", imm32) << FormatInstructionPointer(instr_ptr + imm32) << ")";
98 }
99
ReadU16(const uint8_t * ptr)100 static uint32_t ReadU16(const uint8_t* ptr) {
101 return ptr[0] | (ptr[1] << 8);
102 }
103
ReadU32(const uint8_t * ptr)104 static uint32_t ReadU32(const uint8_t* ptr) {
105 return ptr[0] | (ptr[1] << 8) | (ptr[2] << 16) | (ptr[3] << 24);
106 }
107
108 static const char* kDataProcessingOperations[] = {
109 "and", "eor", "sub", "rsb", "add", "adc", "sbc", "rsc",
110 "tst", "teq", "cmp", "cmn", "orr", "mov", "bic", "mvn",
111 };
112
113 static const char* kThumbDataProcessingOperations[] = {
114 "and", "eor", "lsl", "lsr", "asr", "adc", "sbc", "ror",
115 "tst", "rsb", "cmp", "cmn", "orr", "mul", "bic", "mvn",
116 };
117
118 static const char* const kThumb2ShiftOperations[] = {
119 "lsl", "lsr", "asr", "ror"
120 };
121
122 static const char* kThumbReverseOperations[] = {
123 "rev", "rev16", "rbit", "revsh"
124 };
125
126 struct ArmRegister {
ArmRegisterart::arm::ArmRegister127 explicit ArmRegister(uint32_t r) : r(r) { CHECK_LE(r, 15U); }
ArmRegisterart::arm::ArmRegister128 ArmRegister(uint32_t instruction, uint32_t at_bit) : r((instruction >> at_bit) & 0xf) { CHECK_LE(r, 15U); }
129 uint32_t r;
130 };
operator <<(std::ostream & os,const ArmRegister & r)131 std::ostream& operator<<(std::ostream& os, const ArmRegister& r) {
132 if (r.r == 13) {
133 os << "sp";
134 } else if (r.r == 14) {
135 os << "lr";
136 } else if (r.r == 15) {
137 os << "pc";
138 } else {
139 os << "r" << r.r;
140 }
141 return os;
142 }
143
144 struct ThumbRegister : ArmRegister {
ThumbRegisterart::arm::ThumbRegister145 ThumbRegister(uint16_t instruction, uint16_t at_bit) : ArmRegister((instruction >> at_bit) & 0x7) {}
146 };
147
148 struct Rm {
Rmart::arm::Rm149 explicit Rm(uint32_t instruction) : shift((instruction >> 4) & 0xff), rm(instruction & 0xf) {}
150 uint32_t shift;
151 ArmRegister rm;
152 };
operator <<(std::ostream & os,const Rm & r)153 std::ostream& operator<<(std::ostream& os, const Rm& r) {
154 os << r.rm;
155 if (r.shift != 0) {
156 os << "-shift-" << r.shift; // TODO
157 }
158 return os;
159 }
160
161 struct ShiftedImmediate {
ShiftedImmediateart::arm::ShiftedImmediate162 explicit ShiftedImmediate(uint32_t instruction) {
163 uint32_t rotate = ((instruction >> 8) & 0xf);
164 uint32_t imm = (instruction & 0xff);
165 value = (imm >> (2 * rotate)) | (imm << (32 - (2 * rotate)));
166 }
167 uint32_t value;
168 };
operator <<(std::ostream & os,const ShiftedImmediate & rhs)169 std::ostream& operator<<(std::ostream& os, const ShiftedImmediate& rhs) {
170 os << "#" << rhs.value;
171 return os;
172 }
173
174 struct RegisterList {
RegisterListart::arm::RegisterList175 explicit RegisterList(uint32_t instruction) : register_list(instruction & 0xffff) {}
176 uint32_t register_list;
177 };
operator <<(std::ostream & os,const RegisterList & rhs)178 std::ostream& operator<<(std::ostream& os, const RegisterList& rhs) {
179 if (rhs.register_list == 0) {
180 os << "<no register list?>";
181 return os;
182 }
183 os << "{";
184 bool first = true;
185 for (size_t i = 0; i < 16; i++) {
186 if ((rhs.register_list & (1 << i)) != 0) {
187 if (first) {
188 first = false;
189 } else {
190 os << ", ";
191 }
192 os << ArmRegister(i);
193 }
194 }
195 os << "}";
196 return os;
197 }
198
199 struct FpRegister {
FpRegisterart::arm::FpRegister200 explicit FpRegister(uint32_t instr, uint16_t at_bit, uint16_t extra_at_bit) {
201 size = (instr >> 8) & 1;
202 uint32_t Vn = (instr >> at_bit) & 0xF;
203 uint32_t N = (instr >> extra_at_bit) & 1;
204 r = (size != 0 ? ((N << 4) | Vn) : ((Vn << 1) | N));
205 }
FpRegisterart::arm::FpRegister206 explicit FpRegister(uint32_t instr, uint16_t at_bit, uint16_t extra_at_bit,
207 uint32_t forced_size) {
208 size = forced_size;
209 uint32_t Vn = (instr >> at_bit) & 0xF;
210 uint32_t N = (instr >> extra_at_bit) & 1;
211 r = (size != 0 ? ((N << 4) | Vn) : ((Vn << 1) | N));
212 }
FpRegisterart::arm::FpRegister213 FpRegister(const FpRegister& other, uint32_t offset)
214 : size(other.size), r(other.r + offset) {}
215
216 uint32_t size; // 0 = f32, 1 = f64
217 uint32_t r;
218 };
operator <<(std::ostream & os,const FpRegister & rhs)219 std::ostream& operator<<(std::ostream& os, const FpRegister& rhs) {
220 return os << ((rhs.size != 0) ? "d" : "s") << rhs.r;
221 }
222
223 struct FpRegisterRange {
FpRegisterRangeart::arm::FpRegisterRange224 explicit FpRegisterRange(uint32_t instr)
225 : first(instr, 12, 22), imm8(instr & 0xFF) {}
226 FpRegister first;
227 uint32_t imm8;
228 };
operator <<(std::ostream & os,const FpRegisterRange & rhs)229 std::ostream& operator<<(std::ostream& os, const FpRegisterRange& rhs) {
230 os << "{" << rhs.first;
231 int count = (rhs.first.size != 0 ? ((rhs.imm8 + 1u) >> 1) : rhs.imm8);
232 if (count > 1) {
233 os << "-" << FpRegister(rhs.first, count - 1);
234 }
235 if (rhs.imm8 == 0) {
236 os << " (EMPTY)";
237 } else if (rhs.first.size != 0 && (rhs.imm8 & 1) != 0) {
238 os << rhs.first << " (HALF)";
239 }
240 os << "}";
241 return os;
242 }
243
DumpArm(std::ostream & os,const uint8_t * instr_ptr)244 void DisassemblerArm::DumpArm(std::ostream& os, const uint8_t* instr_ptr) {
245 uint32_t instruction = ReadU32(instr_ptr);
246 uint32_t cond = (instruction >> 28) & 0xf;
247 uint32_t op1 = (instruction >> 25) & 0x7;
248 std::string opcode;
249 std::string suffixes;
250 std::ostringstream args;
251 switch (op1) {
252 case 0:
253 case 1: // Data processing instructions.
254 {
255 if ((instruction & 0x0ff000f0) == 0x01200070) { // BKPT
256 opcode = "bkpt";
257 uint32_t imm12 = (instruction >> 8) & 0xfff;
258 uint32_t imm4 = (instruction & 0xf);
259 args << '#' << ((imm12 << 4) | imm4);
260 break;
261 }
262 if ((instruction & 0x0fffffd0) == 0x012fff10) { // BX and BLX (register)
263 opcode = (((instruction >> 5) & 1) ? "blx" : "bx");
264 args << ArmRegister(instruction & 0xf);
265 break;
266 }
267 bool i = (instruction & (1 << 25)) != 0;
268 bool s = (instruction & (1 << 20)) != 0;
269 uint32_t op = (instruction >> 21) & 0xf;
270 opcode = kDataProcessingOperations[op];
271 bool implicit_s = ((op & ~3) == 8); // TST, TEQ, CMP, and CMN.
272 bool is_mov = op == 0b1101 || op == 0b1111;
273 if (is_mov) {
274 // Show only Rd and Rm.
275 if (s) {
276 suffixes += 's';
277 }
278 args << ArmRegister(instruction, 12) << ", ";
279 if (i) {
280 args << ShiftedImmediate(instruction);
281 } else {
282 // TODO: Shifted register.
283 args << ArmRegister(instruction, 16) << ", " << ArmRegister(instruction, 0);
284 }
285 } else {
286 if (implicit_s) {
287 // Rd is unused (and not shown), and we don't show the 's' suffix either.
288 } else {
289 if (s) {
290 suffixes += 's';
291 }
292 args << ArmRegister(instruction, 12) << ", ";
293 }
294 if (i) {
295 args << ArmRegister(instruction, 16) << ", " << ShiftedImmediate(instruction);
296 } else {
297 // TODO: Shifted register.
298 args << ArmRegister(instruction, 16) << ", " << ArmRegister(instruction, 0);
299 }
300 }
301 }
302 break;
303 case 2: // Load/store word and unsigned byte.
304 {
305 bool p = (instruction & (1 << 24)) != 0;
306 bool b = (instruction & (1 << 22)) != 0;
307 bool w = (instruction & (1 << 21)) != 0;
308 bool l = (instruction & (1 << 20)) != 0;
309 opcode = StringPrintf("%s%s", (l ? "ldr" : "str"), (b ? "b" : ""));
310 args << ArmRegister(instruction, 12) << ", ";
311 ArmRegister rn(instruction, 16);
312 if (rn.r == 0xf) {
313 UNIMPLEMENTED(FATAL) << "literals";
314 } else {
315 bool wback = !p || w;
316 uint32_t offset = (instruction & 0xfff);
317 if (p && !wback) {
318 args << "[" << rn << ", #" << offset << "]";
319 } else if (p && wback) {
320 args << "[" << rn << ", #" << offset << "]!";
321 } else if (!p && wback) {
322 args << "[" << rn << "], #" << offset;
323 } else {
324 LOG(FATAL) << p << " " << w;
325 }
326 if (rn.r == 9) {
327 args << " ; ";
328 Thread::DumpThreadOffset<4>(args, offset);
329 }
330 }
331 }
332 break;
333 case 4: // Load/store multiple.
334 {
335 bool p = (instruction & (1 << 24)) != 0;
336 bool u = (instruction & (1 << 23)) != 0;
337 bool w = (instruction & (1 << 21)) != 0;
338 bool l = (instruction & (1 << 20)) != 0;
339 opcode = StringPrintf("%s%c%c", (l ? "ldm" : "stm"), (u ? 'i' : 'd'), (p ? 'b' : 'a'));
340 args << ArmRegister(instruction, 16) << (w ? "!" : "") << ", " << RegisterList(instruction);
341 }
342 break;
343 case 5: // Branch/branch with link.
344 {
345 bool bl = (instruction & (1 << 24)) != 0;
346 opcode = (bl ? "bl" : "b");
347 int32_t imm26 = (instruction & 0xffffff) << 2;
348 int32_t imm32 = (imm26 << 6) >> 6; // Sign extend.
349 DumpBranchTarget(args, instr_ptr + 8, imm32);
350 }
351 break;
352 default:
353 opcode = "???";
354 break;
355 }
356 opcode += kConditionCodeNames[cond];
357 opcode += suffixes;
358 // TODO: a more complete ARM disassembler could generate wider opcodes.
359 os << FormatInstructionPointer(instr_ptr)
360 << StringPrintf(": %08x\t%-7s ", instruction, opcode.c_str())
361 << args.str() << '\n';
362 }
363
ThumbExpand(int32_t imm12)364 int32_t ThumbExpand(int32_t imm12) {
365 if ((imm12 & 0xC00) == 0) {
366 switch ((imm12 >> 8) & 3) {
367 case 0:
368 return imm12 & 0xFF;
369 case 1:
370 return ((imm12 & 0xFF) << 16) | (imm12 & 0xFF);
371 case 2:
372 return ((imm12 & 0xFF) << 24) | ((imm12 & 0xFF) << 8);
373 default: // 3
374 return ((imm12 & 0xFF) << 24) | ((imm12 & 0xFF) << 16) | ((imm12 & 0xFF) << 8) |
375 (imm12 & 0xFF);
376 }
377 } else {
378 uint32_t val = 0x80 | (imm12 & 0x7F);
379 int32_t rotate = (imm12 >> 7) & 0x1F;
380 return (val >> rotate) | (val << (32 - rotate));
381 }
382 }
383
VFPExpand32(uint32_t imm8)384 uint32_t VFPExpand32(uint32_t imm8) {
385 CHECK_EQ(imm8 & 0xffu, imm8);
386 uint32_t bit_a = (imm8 >> 7) & 1;
387 uint32_t bit_b = (imm8 >> 6) & 1;
388 uint32_t slice = imm8 & 0x3f;
389 return (bit_a << 31) | ((1 << 30) - (bit_b << 25)) | (slice << 19);
390 }
391
VFPExpand64(uint32_t imm8)392 uint64_t VFPExpand64(uint32_t imm8) {
393 CHECK_EQ(imm8 & 0xffu, imm8);
394 uint64_t bit_a = (imm8 >> 7) & 1;
395 uint64_t bit_b = (imm8 >> 6) & 1;
396 uint64_t slice = imm8 & 0x3f;
397 return (bit_a << 31) | ((UINT64_C(1) << 62) - (bit_b << 54)) | (slice << 48);
398 }
399
AdvSIMDExpand(uint32_t op,uint32_t cmode,uint32_t imm8)400 uint64_t AdvSIMDExpand(uint32_t op, uint32_t cmode, uint32_t imm8) {
401 CHECK_EQ(op & 1, op);
402 CHECK_EQ(cmode & 0xf, cmode);
403 CHECK_EQ(imm8 & 0xff, imm8);
404 int32_t cmode321 = cmode >> 1;
405 if (imm8 == 0 && cmode321 != 0 && cmode321 != 4 && cmode321 != 7) {
406 return INT64_C(0x00000000deadbeef); // UNPREDICTABLE
407 }
408 uint64_t imm = imm8;
409 switch (cmode321) {
410 case 3: imm <<= 8; // Fall through.
411 case 2: imm <<= 8; // Fall through.
412 case 1: imm <<= 8; // Fall through.
413 case 0: return static_cast<int64_t>((imm << 32) | imm);
414 case 5: imm <<= 8; // Fall through.
415 case 4: return static_cast<int64_t>((imm << 48) | (imm << 32) | (imm << 16) | imm);
416 case 6:
417 imm = ((imm + 1u) << ((cmode & 1) != 0 ? 16 : 8)) - 1u; // Add 8 or 16 ones.
418 return static_cast<int64_t>((imm << 32) | imm);
419 default:
420 CHECK_EQ(cmode321, 7);
421 if ((cmode & 1) == 0 && op == 0) {
422 imm = (imm << 8) | imm;
423 return static_cast<int64_t>((imm << 48) | (imm << 32) | (imm << 16) | imm);
424 } else if ((cmode & 1) == 0 && op != 0) {
425 for (int i = 1; i != 8; ++i) {
426 imm |= ((imm >> i) & UINT64_C(1)) << (i * 8);
427 }
428 imm = imm & ~UINT64_C(0xfe);
429 return static_cast<int64_t>((imm << 8) - imm);
430 } else if ((cmode & 1) != 0 && op == 0) {
431 imm = static_cast<uint32_t>(VFPExpand32(imm8));
432 return static_cast<int64_t>((imm << 32) | imm);
433 } else {
434 return INT64_C(0xdeadbeef00000000); // UNDEFINED
435 }
436 }
437 }
438
DumpThumb32(std::ostream & os,const uint8_t * instr_ptr)439 size_t DisassemblerArm::DumpThumb32(std::ostream& os, const uint8_t* instr_ptr) {
440 uint32_t instr = (ReadU16(instr_ptr) << 16) | ReadU16(instr_ptr + 2);
441 // |111|1 1|1000000|0000|1111110000000000|
442 // |5 3|2 1|0987654|3 0|5 0 5 0|
443 // |---|---|-------|----|----------------|
444 // |332|2 2|2222222|1111|1111110000000000|
445 // |1 9|8 7|6543210|9 6|5 0 5 0|
446 // |---|---|-------|----|----------------|
447 // |111|op1| op2 | | |
448 uint32_t op1 = (instr >> 27) & 3;
449 if (op1 == 0) {
450 return DumpThumb16(os, instr_ptr);
451 }
452
453 uint32_t op2 = (instr >> 20) & 0x7F;
454 std::ostringstream opcode;
455 std::ostringstream args;
456 switch (op1) {
457 case 0:
458 break;
459 case 1:
460 if ((op2 & 0x64) == 0) { // 00x x0xx
461 // |111|11|10|00|0|00|0000|1111110000000000|
462 // |5 3|21|09|87|6|54|3 0|5 0 5 0|
463 // |---|--|--|--|-|--|----|----------------|
464 // |332|22|22|22|2|22|1111|1111110000000000|
465 // |1 9|87|65|43|2|10|9 6|5 0 5 0|
466 // |---|--|--|--|-|--|----|----------------|
467 // |111|01|00|op|0|WL| Rn | |
468 // |111|01| op2 | | |
469 // STM - 111 01 00-01-0-W0 nnnn rrrrrrrrrrrrrrrr
470 // LDM - 111 01 00-01-0-W1 nnnn rrrrrrrrrrrrrrrr
471 // PUSH- 111 01 00-01-0-10 1101 0M0rrrrrrrrrrrrr
472 // POP - 111 01 00-01-0-11 1101 PM0rrrrrrrrrrrrr
473 uint32_t op = (instr >> 23) & 3;
474 uint32_t W = (instr >> 21) & 1;
475 uint32_t L = (instr >> 20) & 1;
476 ArmRegister Rn(instr, 16);
477 if (op == 1 || op == 2) {
478 if (op == 1) {
479 if (L == 0) {
480 opcode << "stm";
481 args << Rn << (W == 0 ? "" : "!") << ", ";
482 } else {
483 if (Rn.r != 13) {
484 opcode << "ldm";
485 args << Rn << (W == 0 ? "" : "!") << ", ";
486 } else {
487 opcode << "pop";
488 }
489 }
490 } else {
491 if (L == 0) {
492 if (Rn.r != 13) {
493 opcode << "stmdb";
494 args << Rn << (W == 0 ? "" : "!") << ", ";
495 } else {
496 opcode << "push";
497 }
498 } else {
499 opcode << "ldmdb";
500 args << Rn << (W == 0 ? "" : "!") << ", ";
501 }
502 }
503 args << RegisterList(instr);
504 }
505 } else if ((op2 & 0x64) == 4) { // 00x x1xx
506 uint32_t op3 = (instr >> 23) & 3;
507 uint32_t op4 = (instr >> 20) & 3;
508 // uint32_t op5 = (instr >> 4) & 0xF;
509 ArmRegister Rn(instr, 16);
510 ArmRegister Rt(instr, 12);
511 ArmRegister Rd(instr, 8);
512 uint32_t imm8 = instr & 0xFF;
513 if ((op3 & 2) == 2) { // 1x
514 int W = (instr >> 21) & 1;
515 int U = (instr >> 23) & 1;
516 int P = (instr >> 24) & 1;
517
518 if ((op4 & 1) == 1) {
519 opcode << "ldrd";
520 } else {
521 opcode << "strd";
522 }
523 args << Rt << "," << Rd << ", [" << Rn;
524 const char *sign = U ? "+" : "-";
525 if (P == 0 && W == 1) {
526 args << "], #" << sign << (imm8 << 2);
527 } else {
528 args << ", #" << sign << (imm8 << 2) << "]";
529 if (W == 1) {
530 args << "!";
531 }
532 }
533 } else { // 0x
534 switch (op4) {
535 case 0:
536 if (op3 == 0) { // op3 is 00, op4 is 00
537 opcode << "strex";
538 args << Rd << ", " << Rt << ", [" << Rn << ", #" << (imm8 << 2) << "]";
539 if (Rd.r == 13 || Rd.r == 15 || Rt.r == 13 || Rt.r == 15 || Rn.r == 15 ||
540 Rd.r == Rn.r || Rd.r == Rt.r) {
541 args << " (UNPREDICTABLE)";
542 }
543 } else { // op3 is 01, op4 is 00
544 // this is one of strexb, strexh or strexd
545 int op5 = (instr >> 4) & 0xf;
546 switch (op5) {
547 case 4:
548 case 5:
549 opcode << ((op5 == 4) ? "strexb" : "strexh");
550 Rd = ArmRegister(instr, 0);
551 args << Rd << ", " << Rt << ", [" << Rn << "]";
552 if (Rd.r == 13 || Rd.r == 15 || Rt.r == 13 || Rt.r == 15 || Rn.r == 15 ||
553 Rd.r == Rn.r || Rd.r == Rt.r || (instr & 0xf00) != 0xf00) {
554 args << " (UNPREDICTABLE)";
555 }
556 break;
557 case 7:
558 opcode << "strexd";
559 ArmRegister Rt2 = Rd;
560 Rd = ArmRegister(instr, 0);
561 args << Rd << ", " << Rt << ", " << Rt2 << ", [" << Rn << "]";
562 if (Rd.r == 13 || Rd.r == 15 || Rt.r == 13 || Rt.r == 15 ||
563 Rt2.r == 13 || Rt2.r == 15 || Rn.r == 15 ||
564 Rd.r == Rn.r || Rd.r == Rt.r || Rd.r == Rt2.r) {
565 args << " (UNPREDICTABLE)";
566 }
567 break;
568 }
569 }
570 break;
571 case 1:
572 if (op3 == 0) { // op3 is 00, op4 is 01
573 opcode << "ldrex";
574 args << Rt << ", [" << Rn << ", #" << (imm8 << 2) << "]";
575 if (Rt.r == 13 || Rt.r == 15 || Rn.r == 15 || (instr & 0xf00) != 0xf00) {
576 args << " (UNPREDICTABLE)";
577 }
578 } else { // op3 is 01, op4 is 01
579 // this is one of strexb, strexh or strexd
580 int op5 = (instr >> 4) & 0xf;
581 switch (op5) {
582 case 0:
583 opcode << "tbb";
584 break;
585 case 1:
586 opcode << "tbh";
587 break;
588 case 4:
589 case 5:
590 opcode << ((op5 == 4) ? "ldrexb" : "ldrexh");
591 args << Rt << ", [" << Rn << "]";
592 if (Rt.r == 13 || Rt.r == 15 || Rn.r == 15 || (instr & 0xf0f) != 0xf0f) {
593 args << " (UNPREDICTABLE)";
594 }
595 break;
596 case 7:
597 opcode << "ldrexd";
598 args << Rt << ", " << Rd /* Rt2 */ << ", [" << Rn << "]";
599 if (Rt.r == 13 || Rt.r == 15 || Rd.r == 13 /* Rt2 */ || Rd.r == 15 /* Rt2 */ ||
600 Rn.r == 15 || (instr & 0x00f) != 0x00f) {
601 args << " (UNPREDICTABLE)";
602 }
603 break;
604 }
605 }
606 break;
607 case 2: // op3 is 0x, op4 is 10
608 case 3: // op3 is 0x, op4 is 11
609 if (op4 == 2) {
610 opcode << "strd";
611 } else {
612 opcode << "ldrd";
613 }
614 int W = (instr >> 21) & 1;
615 int U = (instr >> 23) & 1;
616 int P = (instr >> 24) & 1;
617
618 args << Rt << "," << Rd << ", [" << Rn;
619 const char *sign = U ? "+" : "-";
620 if (P == 0 && W == 1) {
621 args << "], #" << sign << imm8;
622 } else {
623 args << ", #" << sign << imm8 << "]";
624 if (W == 1) {
625 args << "!";
626 }
627 }
628 break;
629 }
630 }
631
632 } else if ((op2 & 0x60) == 0x20) { // 01x xxxx
633 // Data-processing (shifted register)
634 // |111|1110|0000|0|0000|1111|1100|00|00|0000|
635 // |5 3|2109|8765|4|3 0|5 |10 8|7 |5 |3 0|
636 // |---|----|----|-|----|----|----|--|--|----|
637 // |332|2222|2222|2|1111|1111|1100|00|00|0000|
638 // |1 9|8765|4321|0|9 6|5 |10 8|7 |5 |3 0|
639 // |---|----|----|-|----|----|----|--|--|----|
640 // |111|0101| op3|S| Rn |imm3| Rd |i2|ty| Rm |
641 uint32_t op3 = (instr >> 21) & 0xF;
642 uint32_t S = (instr >> 20) & 1;
643 uint32_t imm3 = ((instr >> 12) & 0x7);
644 uint32_t imm2 = ((instr >> 6) & 0x3);
645 uint32_t imm5 = ((imm3 << 2) | imm2);
646 uint32_t shift_type = ((instr >> 4) & 0x3);
647 ArmRegister Rd(instr, 8);
648 ArmRegister Rn(instr, 16);
649 ArmRegister Rm(instr, 0);
650 switch (op3) {
651 case 0x0:
652 if (Rd.r != 0xF) {
653 opcode << "and";
654 } else {
655 if (S != 1U) {
656 opcode << "UNKNOWN TST-" << S;
657 break;
658 }
659 opcode << "tst";
660 S = 0; // don't print 's'
661 }
662 break;
663 case 0x1: opcode << "bic"; break;
664 case 0x2:
665 if (Rn.r != 0xF) {
666 opcode << "orr";
667 } else {
668 // TODO: use canonical form if there is a shift (lsl, ...).
669 opcode << "mov";
670 }
671 break;
672 case 0x3:
673 if (Rn.r != 0xF) {
674 opcode << "orn";
675 } else {
676 opcode << "mvn";
677 }
678 break;
679 case 0x4:
680 if (Rd.r != 0xF) {
681 opcode << "eor";
682 } else {
683 if (S != 1U) {
684 opcode << "UNKNOWN TEQ-" << S;
685 break;
686 }
687 opcode << "teq";
688 S = 0; // don't print 's'
689 }
690 break;
691 case 0x6: opcode << "pkh"; break;
692 case 0x8:
693 if (Rd.r != 0xF) {
694 opcode << "add";
695 } else {
696 if (S != 1U) {
697 opcode << "UNKNOWN CMN-" << S;
698 break;
699 }
700 opcode << "cmn";
701 S = 0; // don't print 's'
702 }
703 break;
704 case 0xA: opcode << "adc"; break;
705 case 0xB: opcode << "sbc"; break;
706 case 0xD:
707 if (Rd.r != 0xF) {
708 opcode << "sub";
709 } else {
710 if (S != 1U) {
711 opcode << "UNKNOWN CMP-" << S;
712 break;
713 }
714 opcode << "cmp";
715 S = 0; // don't print 's'
716 }
717 break;
718 case 0xE: opcode << "rsb"; break;
719 default: opcode << "UNKNOWN DPSR-" << op3; break;
720 }
721
722 if (S == 1) {
723 opcode << "s";
724 }
725 opcode << ".w";
726
727 if (Rd.r != 0xF) {
728 args << Rd << ", ";
729 }
730 if (Rn.r != 0xF) {
731 args << Rn << ", ";
732 }
733 args << Rm;
734
735 // Shift operand.
736 bool noShift = (imm5 == 0 && shift_type != 0x3);
737 if (!noShift) {
738 args << ", ";
739 switch (shift_type) {
740 case 0x0: args << "lsl"; break;
741 case 0x1: args << "lsr"; break;
742 case 0x2: args << "asr"; break;
743 case 0x3:
744 if (imm5 == 0) {
745 args << "rrx";
746 } else {
747 args << "ror";
748 }
749 break;
750 }
751 if (shift_type != 0x3 /* rrx */) {
752 args << StringPrintf(" #%d", (0 != imm5 || 0 == shift_type) ? imm5 : 32);
753 }
754 }
755
756 } else if ((op2 & 0x40) == 0x40) { // 1xx xxxx
757 // Co-processor instructions
758 // |111|1|11|000000|0000|1111|1100|000|0 |0000|
759 // |5 3|2|10|987654|3 0|54 2|10 8|7 5|4 | 0|
760 // |---|-|--|------|----|----|----|---|---|----|
761 // |332|2|22|222222|1111|1111|1100|000|0 |0000|
762 // |1 9|8|76|543210|9 6|54 2|10 8|7 5|4 | 0|
763 // |---|-|--|------|----|----|----|---|---|----|
764 // |111| |11| op3 | Rn | |copr| |op4| |
765 uint32_t op3 = (instr >> 20) & 0x3F;
766 uint32_t coproc = (instr >> 8) & 0xF;
767 uint32_t op4 = (instr >> 4) & 0x1;
768
769 if (coproc == 0xA || coproc == 0xB) { // 101x
770 if (op3 < 0x20 && (op3 & ~5) != 0) { // 0xxxxx and not 000x0x
771 // Extension register load/store instructions
772 // |1111|110|00000|0000|1111|110|0|00000000|
773 // |5 2|1 9|87654|3 0|5 2|1 9|8|7 0|
774 // |----|---|-----|----|----|---|-|--------|
775 // |3322|222|22222|1111|1111|110|0|00000000|
776 // |1 8|7 5|4 0|9 6|5 2|1 9|8|7 0|
777 // |----|---|-----|----|----|---|-|--------|
778 // |1110|110|PUDWL| Rn | Vd |101|S| imm8 |
779 uint32_t P = (instr >> 24) & 1;
780 uint32_t U = (instr >> 23) & 1;
781 uint32_t W = (instr >> 21) & 1;
782 if (P == U && W == 1) {
783 opcode << "UNDEFINED";
784 } else {
785 uint32_t L = (instr >> 20) & 1;
786 uint32_t S = (instr >> 8) & 1;
787 ArmRegister Rn(instr, 16);
788 if (P == 1 && W == 0) { // VLDR
789 FpRegister d(instr, 12, 22);
790 uint32_t imm8 = instr & 0xFF;
791 opcode << (L == 1 ? "vldr" : "vstr");
792 args << d << ", [" << Rn << ", #" << ((U == 1) ? "" : "-")
793 << (imm8 << 2) << "]";
794 if (Rn.r == 15 && U == 1) {
795 intptr_t lit_adr = reinterpret_cast<intptr_t>(instr_ptr);
796 lit_adr = RoundDown(lit_adr, 4) + 4 + (imm8 << 2);
797 typedef const int64_t unaligned_int64_t __attribute__ ((aligned (2)));
798 args << StringPrintf(" ; 0x%" PRIx64, *reinterpret_cast<unaligned_int64_t*>(lit_adr));
799 }
800 } else if (Rn.r == 13 && W == 1 && U == L) { // VPUSH/VPOP
801 opcode << (L == 1 ? "vpop" : "vpush");
802 args << FpRegisterRange(instr);
803 } else { // VLDM
804 opcode << (L == 1 ? "vldm" : "vstm");
805 args << Rn << ((W == 1) ? "!" : "") << ", "
806 << FpRegisterRange(instr);
807 }
808 opcode << (S == 1 ? ".f64" : ".f32");
809 }
810 } else if ((op3 >> 1) == 2) { // 00010x
811 if ((instr & 0xD0) == 0x10) {
812 // 64bit transfers between ARM core and extension registers.
813 uint32_t L = (instr >> 20) & 1;
814 uint32_t S = (instr >> 8) & 1;
815 ArmRegister Rt2(instr, 16);
816 ArmRegister Rt(instr, 12);
817 FpRegister m(instr, 0, 5);
818 opcode << "vmov" << (S ? ".f64" : ".f32");
819 if (L == 1) {
820 args << Rt << ", " << Rt2 << ", ";
821 }
822 if (S) {
823 args << m;
824 } else {
825 args << m << ", " << FpRegister(m, 1);
826 }
827 if (L == 0) {
828 args << ", " << Rt << ", " << Rt2;
829 }
830 if (Rt.r == 15 || Rt.r == 13 || Rt2.r == 15 || Rt2.r == 13 ||
831 (S == 0 && m.r == 31) || (L == 1 && Rt.r == Rt2.r)) {
832 args << " (UNPREDICTABLE)";
833 }
834 }
835 } else if ((op3 >> 4) == 2 && op4 == 0) { // 10xxxx, op = 0
836 // fp data processing
837 // VMLA, VMLS, VMUL, VNMUL, VADD, VSUB, VDIV, VMOV, ...
838 // |1111|1100|0|0|00|0000|1111|110|0|0|0|0|0|0000|
839 // |5 2|1 8|7|6|54|3 0|5 2|1 9|8|7|6|5|4|3 0|
840 // |----|----|-|-|--|----|----|---|-|-|-|-|-|----|
841 // |3322|2222|2|2|22|1111|1111|110|0|0|0|0|0|0000|
842 // |1 8|7 4|3|2|10|9 6|5 2|1 9|8|7|6|5|4|3 0|
843 // |----|----|-|-|--|----|----|---|-|-|-|-|-|----|
844 // |1110|1110| op3 | Vn | Vd |101|S|N|Q|M|0| Vm |
845 // |1110|1110|0|D|00| Vn | Vd |101|S|N|0|M|0| Vm | VMLA
846 // |1110|1110|0|D|00| Vn | Vd |101|S|N|1|M|0| Vm | VMLS
847 // |1110|1110|0|D|10| Vn | Vd |101|S|N|0|M|0| Vm | VMUL
848 // |1110|1110|0|D|10| Vn | Vd |101|S|N|1|M|0| Vm | VNMUL
849 // |1110|1110|0|D|11| Vn | Vd |101|S|N|0|M|0| Vm | VADD
850 // |1110|1110|0|D|11| Vn | Vd |101|S|N|1|M|0| Vm | VSUB
851 // |1110|1110|1|D|00| Vn | Vd |101|S|N|0|M|0| Vm | VDIV
852 // |1110|1110|1|D|11| iH | Vd |101|S|0|0|0|0| iL | VMOV (imm)
853 // |1110|1110|1|D|11|op5 | Vd |101|S|.|1|M|0| Vm | ... (see below)
854 uint32_t S = (instr >> 8) & 1;
855 uint32_t Q = (instr >> 6) & 1;
856 FpRegister d(instr, 12, 22);
857 FpRegister n(instr, 16, 7);
858 FpRegister m(instr, 0, 5);
859 if ((op3 & 0xB) == 0) { // 100x00
860 opcode << (Q == 0 ? "vmla" : "vmls") << (S != 0 ? ".f64" : ".f32");
861 args << d << ", " << n << ", " << m;
862 } else if ((op3 & 0xB) == 0x2) { // 100x10
863 opcode << (Q == 0 ? "vmul" : "vnmul") << (S != 0 ? ".f64" : ".f32");
864 args << d << ", " << n << ", " << m;
865 } else if ((op3 & 0xB) == 0x3) { // 100x11
866 opcode << (Q == 0 ? "vadd" : "vsub") << (S != 0 ? ".f64" : ".f32");
867 args << d << ", " << n << ", " << m;
868 } else if ((op3 & 0xB) == 0x8 && Q == 0) { // 101x00, Q == 0
869 opcode << "vdiv" << (S != 0 ? ".f64" : ".f32");
870 args << d << ", " << n << ", " << m;
871 } else if ((op3 & 0xB) == 0xB && Q == 0) { // 101x11, Q == 0
872 uint32_t imm8 = ((instr & 0xf0000u) >> 12) | (instr & 0xfu);
873 opcode << "vmov" << (S != 0 ? ".f64" : ".f32");
874 args << d << ", " << (S != 0 ? StringPrintf("0x%016" PRIx64, VFPExpand64(imm8))
875 : StringPrintf("0x%08x", VFPExpand32(imm8)));
876 if ((instr & 0xa0) != 0) {
877 args << " (UNPREDICTABLE)";
878 }
879 } else if ((op3 & 0xB) == 0xB && Q == 1) { // 101x11, Q == 1
880 // VNEG, VSQRT, VCMP, VCMPE, VCVT (floating-point conversion)
881 // |1111|1100|0|0|00|0000|1111|110|0|0 |0|0|0|0000|
882 // |5 2|1 8|7|6|54|3 0|5 2|1 9|8|7 |6|5|4|3 0|
883 // |----|----|-|-|--|----|----|---|-|- |-|-|-|----|
884 // |3322|2222|2|2|22|1111|1111|110|0|0 |0|0|0|0000|
885 // |1 8|7 4|3|2|10|9 6|5 2|1 9|8|7 |6|5|4|3 0|
886 // |----|----|-|-|--|----|----|---|-|- |-|-|-|----|
887 // |1110|1110|1|D|11|0000| Vd |101|S|0 |1|M|0| Vm | VMOV (reg)
888 // |1110|1110|1|D|11|0000| Vd |101|S|1 |1|M|0| Vm | VABS
889 // |1110|1110|1|D|11|0001| Vd |101|S|0 |1|M|0| Vm | VNEG
890 // |1110|1110|1|D|11|0001| Vd |101|S|1 |1|M|0| Vm | VSQRT
891 // |1110|1110|1|D|11|0100| Vd |101|S|op|1|M|0| Vm | VCMP
892 // |1110|1110|1|D|11|0101| Vd |101|S|op|1|0|0|0000| VCMPE
893 // |1110|1110|1|D|11|op5 | Vd |101|S|op|1|M|0| Vm | VCVT
894 uint32_t op5 = (instr >> 16) & 0xF;
895 uint32_t op = (instr >> 7) & 1;
896 // Register types in VCVT instructions rely on the combination of op5 and S.
897 FpRegister Dd(instr, 12, 22, 1);
898 FpRegister Sd(instr, 12, 22, 0);
899 FpRegister Dm(instr, 0, 5, 1);
900 FpRegister Sm(instr, 0, 5, 0);
901 if (op5 == 0) {
902 opcode << (op == 0 ? "vmov" : "vabs") << (S != 0 ? ".f64" : ".f32");
903 args << d << ", " << m;
904 } else if (op5 == 1) {
905 opcode << (op != 0 ? "vsqrt" : "vneg") << (S != 0 ? ".f64" : ".f32");
906 args << d << ", " << m;
907 } else if (op5 == 4) {
908 opcode << "vcmp" << (S != 0 ? ".f64" : ".f32");
909 args << d << ", " << m;
910 if (op != 0) {
911 args << " (quiet nan)";
912 }
913 } else if (op5 == 5) {
914 opcode << "vcmpe" << (S != 0 ? ".f64" : ".f32");
915 args << d << ", #0.0";
916 if (op != 0) {
917 args << " (quiet nan)";
918 }
919 if ((instr & 0x2f) != 0) {
920 args << " (UNPREDICTABLE)";
921 }
922 } else if (op5 == 0xD) {
923 if (S == 1) {
924 // vcvt{r}.s32.f64
925 opcode << "vcvt" << (op == 0 ? "r" : "") << ".s32.f64";
926 args << Sd << ", " << Dm;
927 } else {
928 // vcvt{r}.s32.f32
929 opcode << "vcvt" << (op == 0 ? "r" : "") << ".s32.f32";
930 args << Sd << ", " << Sm;
931 }
932 } else if (op5 == 0xC) {
933 if (S == 1) {
934 // vcvt{r}.u32.f64
935 opcode << "vcvt" << (op == 0 ? "r" : "") << ".u32.f64";
936 args << Sd << ", " << Dm;
937 } else {
938 // vcvt{r}.u32.f32
939 opcode << "vcvt" << (op == 0 ? "r" : "") << ".u32.f32";
940 args << Sd << ", " << Sm;
941 }
942 } else if (op5 == 0x8) {
943 if (S == 1) {
944 // vcvt.f64.<Tm>
945 opcode << "vcvt.f64." << (op == 0 ? "u" : "s") << "32";
946 args << Dd << ", " << Sm;
947 } else {
948 // vcvt.f32.<Tm>
949 opcode << "vcvt.f32." << (op == 0 ? "u" : "s") << "32";
950 args << Sd << ", " << Sm;
951 }
952 } else if (op5 == 0x7) {
953 if (op == 1) {
954 if (S == 1) {
955 // vcvt.f64.f32
956 opcode << "vcvt.f64.f32";
957 args << Dd << ", " << Sm;
958 } else {
959 // vcvt.f32.f64
960 opcode << "vcvt.f32.f64";
961 args << Sd << ", " << Dm;
962 }
963 }
964 } else if ((op5 & 0xa) == 0xa) {
965 opcode << "vcvt";
966 args << "[undecoded: floating <-> fixed]";
967 }
968 }
969 } else if ((op3 >> 4) == 2 && op4 == 1) { // 10xxxx, op = 1
970 if (coproc == 10 && (op3 & 0xE) == 0) {
971 // VMOV (between ARM core register and single-precision register)
972 // |1111|1100|000|0 |0000|1111|1100|0|00|0|0000|
973 // |5 |1 8|7 5|4 |3 0|5 2|1 8|7|65|4|3 0|
974 // |----|----|---|- |----|----|----|-|--|-|----|
975 // |3322|2222|222|2 |1111|1111|1100|0|00|0|0000|
976 // |1 8|7 4|3 1|0 |9 6|5 2|1 8|7|65|4|3 0|
977 // |----|----|---|- |----|----|----|-|--|-|----|
978 // |1110|1110|000|op| Vn | Rt |1010|N|00|1|0000|
979 uint32_t op = op3 & 1;
980 ArmRegister Rt(instr, 12);
981 FpRegister n(instr, 16, 7);
982 opcode << "vmov.f32";
983 if (op) {
984 args << Rt << ", " << n;
985 } else {
986 args << n << ", " << Rt;
987 }
988 if (Rt.r == 13 || Rt.r == 15 || (instr & 0x6F) != 0) {
989 args << " (UNPREDICTABLE)";
990 }
991 } else if (coproc == 10 && op3 == 0x2F) {
992 // VMRS
993 // |1111|11000000|0000|1111|1100|000|0|0000|
994 // |5 |1 4|3 0|5 2|1 8|7 5|4|3 0|
995 // |----|--------|----|----|----|---|-|----|
996 // |3322|22222222|1111|1111|1100|000|0|0000|
997 // |1 8|7 0|9 6|5 2|1 8|7 5|4|3 0|
998 // |----|--------|----|----|----|---|-|----|
999 // |1110|11101111|reg | Rt |1010|000|1|0000| - last 7 0s are (0)
1000 uint32_t spec_reg = (instr >> 16) & 0xF;
1001 ArmRegister Rt(instr, 12);
1002 opcode << "vmrs";
1003 if (spec_reg == 1) {
1004 if (Rt.r == 15) {
1005 args << "APSR_nzcv, FPSCR";
1006 } else if (Rt.r == 13) {
1007 args << Rt << ", FPSCR (UNPREDICTABLE)";
1008 } else {
1009 args << Rt << ", FPSCR";
1010 }
1011 } else {
1012 args << "(PRIVILEGED)";
1013 }
1014 } else if (coproc == 11 && (op3 & 0x9) != 8) {
1015 // VMOV (ARM core register to scalar or vice versa; 8/16/32-bit)
1016 }
1017 }
1018 }
1019 }
1020 break;
1021 case 2:
1022 if ((instr & 0x8000) == 0 && (op2 & 0x20) == 0) {
1023 // Data-processing (modified immediate)
1024 // |111|11|10|0000|0|0000|1|111|1100|00000000|
1025 // |5 3|21|09|8765|4|3 0|5|4 2|10 8|7 5 0|
1026 // |---|--|--|----|-|----|-|---|----|--------|
1027 // |332|22|22|2222|2|1111|1|111|1100|00000000|
1028 // |1 9|87|65|4321|0|9 6|5|4 2|10 8|7 5 0|
1029 // |---|--|--|----|-|----|-|---|----|--------|
1030 // |111|10|i0| op3|S| Rn |0|iii| Rd |iiiiiiii|
1031 // 111 10 x0 xxxx x xxxx opxxx xxxx xxxxxxxx
1032 uint32_t i = (instr >> 26) & 1;
1033 uint32_t op3 = (instr >> 21) & 0xF;
1034 uint32_t S = (instr >> 20) & 1;
1035 ArmRegister Rn(instr, 16);
1036 uint32_t imm3 = (instr >> 12) & 7;
1037 ArmRegister Rd(instr, 8);
1038 uint32_t imm8 = instr & 0xFF;
1039 int32_t imm32 = (i << 11) | (imm3 << 8) | imm8;
1040 if (Rn.r == 0xF && (op3 == 0x2 || op3 == 0x3)) {
1041 if (op3 == 0x2) {
1042 opcode << "mov";
1043 if (S == 1) {
1044 opcode << "s";
1045 }
1046 opcode << ".w";
1047 } else {
1048 opcode << "mvn";
1049 if (S == 1) {
1050 opcode << "s";
1051 }
1052 }
1053 args << Rd << ", #" << ThumbExpand(imm32);
1054 } else if (Rd.r == 0xF && S == 1 &&
1055 (op3 == 0x0 || op3 == 0x4 || op3 == 0x8 || op3 == 0xD)) {
1056 if (op3 == 0x0) {
1057 opcode << "tst";
1058 } else if (op3 == 0x4) {
1059 opcode << "teq";
1060 } else if (op3 == 0x8) {
1061 opcode << "cmn.w";
1062 } else {
1063 opcode << "cmp.w";
1064 }
1065 args << Rn << ", #" << ThumbExpand(imm32);
1066 } else {
1067 switch (op3) {
1068 case 0x0: opcode << "and"; break;
1069 case 0x1: opcode << "bic"; break;
1070 case 0x2: opcode << "orr"; break;
1071 case 0x3: opcode << "orn"; break;
1072 case 0x4: opcode << "eor"; break;
1073 case 0x8: opcode << "add"; break;
1074 case 0xA: opcode << "adc"; break;
1075 case 0xB: opcode << "sbc"; break;
1076 case 0xD: opcode << "sub"; break;
1077 case 0xE: opcode << "rsb"; break;
1078 default: opcode << "UNKNOWN DPMI-" << op3; break;
1079 }
1080 if (S == 1) {
1081 opcode << "s";
1082 }
1083 args << Rd << ", " << Rn << ", #" << ThumbExpand(imm32);
1084 }
1085 } else if ((instr & 0x8000) == 0 && (op2 & 0x20) != 0) {
1086 // Data-processing (plain binary immediate)
1087 // |111|11|10|00000|0000|1|111110000000000|
1088 // |5 3|21|09|87654|3 0|5|4 0 5 0|
1089 // |---|--|--|-----|----|-|---------------|
1090 // |332|22|22|22222|1111|1|111110000000000|
1091 // |1 9|87|65|43210|9 6|5|4 0 5 0|
1092 // |---|--|--|-----|----|-|---------------|
1093 // |111|10|x1| op3 | Rn |0|xxxxxxxxxxxxxxx|
1094 uint32_t op3 = (instr >> 20) & 0x1F;
1095 switch (op3) {
1096 case 0x00: case 0x0A: {
1097 // ADD/SUB.W Rd, Rn #imm12 - 111 10 i1 0101 0 nnnn 0 iii dddd iiiiiiii
1098 ArmRegister Rd(instr, 8);
1099 ArmRegister Rn(instr, 16);
1100 uint32_t i = (instr >> 26) & 1;
1101 uint32_t imm3 = (instr >> 12) & 0x7;
1102 uint32_t imm8 = instr & 0xFF;
1103 uint32_t imm12 = (i << 11) | (imm3 << 8) | imm8;
1104 if (Rn.r != 0xF) {
1105 opcode << (op3 == 0 ? "addw" : "subw");
1106 args << Rd << ", " << Rn << ", #" << imm12;
1107 } else {
1108 opcode << "adr";
1109 args << Rd << ", ";
1110 DumpBranchTarget(args, instr_ptr + 4, (op3 == 0) ? imm12 : -imm12);
1111 }
1112 break;
1113 }
1114 case 0x04: case 0x0C: {
1115 // MOVW/T Rd, #imm16 - 111 10 i0 0010 0 iiii 0 iii dddd iiiiiiii
1116 ArmRegister Rd(instr, 8);
1117 uint32_t i = (instr >> 26) & 1;
1118 uint32_t imm3 = (instr >> 12) & 0x7;
1119 uint32_t imm8 = instr & 0xFF;
1120 uint32_t Rn = (instr >> 16) & 0xF;
1121 uint32_t imm16 = (Rn << 12) | (i << 11) | (imm3 << 8) | imm8;
1122 opcode << (op3 == 0x04 ? "movw" : "movt");
1123 args << Rd << ", #" << imm16;
1124 break;
1125 }
1126 case 0x16: {
1127 // BFI Rd, Rn, #lsb, #width - 111 10 0 11 011 0 nnnn 0 iii dddd ii 0 iiiii
1128 ArmRegister Rd(instr, 8);
1129 ArmRegister Rn(instr, 16);
1130 uint32_t msb = instr & 0x1F;
1131 uint32_t imm2 = (instr >> 6) & 0x3;
1132 uint32_t imm3 = (instr >> 12) & 0x7;
1133 uint32_t lsb = (imm3 << 2) | imm2;
1134 uint32_t width = msb - lsb + 1;
1135 if (Rn.r != 0xF) {
1136 opcode << "bfi";
1137 args << Rd << ", " << Rn << ", #" << lsb << ", #" << width;
1138 } else {
1139 opcode << "bfc";
1140 args << Rd << ", #" << lsb << ", #" << width;
1141 }
1142 break;
1143 }
1144 default:
1145 break;
1146 }
1147 } else {
1148 // Branches and miscellaneous control
1149 // |111|11|1000000|0000|1|111|1100|00000000|
1150 // |5 3|21|0987654|3 0|5|4 2|10 8|7 5 0|
1151 // |---|--|-------|----|-|---|----|--------|
1152 // |332|22|2222222|1111|1|111|1100|00000000|
1153 // |1 9|87|6543210|9 6|5|4 2|10 8|7 5 0|
1154 // |---|--|-------|----|-|---|----|--------|
1155 // |111|10| op2 | |1|op3|op4 | |
1156
1157 uint32_t op3 = (instr >> 12) & 7;
1158 // uint32_t op4 = (instr >> 8) & 0xF;
1159 switch (op3) {
1160 case 0:
1161 if ((op2 & 0x38) != 0x38) {
1162 // Conditional branch
1163 // |111|11|1|0000|000000|1|1|1 |1|1 |10000000000|
1164 // |5 3|21|0|9876|543 0|5|4|3 |2|1 |0 5 0|
1165 // |---|--|-|----|------|-|-|--|-|--|-----------|
1166 // |332|22|2|2222|221111|1|1|1 |1|1 |10000000000|
1167 // |1 9|87|6|5432|109 6|5|4|3 |2|1 |0 5 0|
1168 // |---|--|-|----|------|-|-|--|-|--|-----------|
1169 // |111|10|S|cond| imm6 |1|0|J1|0|J2| imm11 |
1170 uint32_t S = (instr >> 26) & 1;
1171 uint32_t J2 = (instr >> 11) & 1;
1172 uint32_t J1 = (instr >> 13) & 1;
1173 uint32_t imm6 = (instr >> 16) & 0x3F;
1174 uint32_t imm11 = instr & 0x7FF;
1175 uint32_t cond = (instr >> 22) & 0xF;
1176 int32_t imm32 = (S << 20) | (J2 << 19) | (J1 << 18) | (imm6 << 12) | (imm11 << 1);
1177 imm32 = (imm32 << 11) >> 11; // sign extend 21bit immediate
1178 opcode << "b";
1179 DumpCond(opcode, cond);
1180 opcode << ".w";
1181 DumpBranchTarget(args, instr_ptr + 4, imm32);
1182 } else if (op2 == 0x3B) {
1183 // Miscellaneous control instructions
1184 uint32_t op5 = (instr >> 4) & 0xF;
1185 switch (op5) {
1186 case 4: opcode << "dsb"; DumpMemoryDomain(args, instr & 0xF); break;
1187 case 5: opcode << "dmb"; DumpMemoryDomain(args, instr & 0xF); break;
1188 case 6: opcode << "isb"; DumpMemoryDomain(args, instr & 0xF); break;
1189 }
1190 }
1191 break;
1192 case 2:
1193 if ((op2 & 0x38) == 0x38) {
1194 if (op2 == 0x7F) {
1195 opcode << "udf";
1196 }
1197 break;
1198 }
1199 // Else deliberate fall-through to B.
1200 case 1: case 3: {
1201 // B
1202 // |111|11|1|0000|000000|11|1 |1|1 |10000000000|
1203 // |5 3|21|0|9876|543 0|54|3 |2|1 |0 5 0|
1204 // |---|--|-|----|------|--|--|-|--|-----------|
1205 // |332|22|2|2222|221111|11|1 |1|1 |10000000000|
1206 // |1 9|87|6|5 2|10 6|54|3 |2|1 |0 5 0|
1207 // |---|--|-|----|------|--|--|-|--|-----------|
1208 // |111|10|S|cond| imm6 |10|J1|0|J2| imm11 |
1209 // |111|10|S| imm10 |10|J1|1|J2| imm11 |
1210 uint32_t S = (instr >> 26) & 1;
1211 uint32_t cond = (instr >> 22) & 0xF;
1212 uint32_t J2 = (instr >> 11) & 1;
1213 uint32_t form = (instr >> 12) & 1;
1214 uint32_t J1 = (instr >> 13) & 1;
1215 uint32_t imm10 = (instr >> 16) & 0x3FF;
1216 uint32_t imm6 = (instr >> 16) & 0x3F;
1217 uint32_t imm11 = instr & 0x7FF;
1218 opcode << "b";
1219 int32_t imm32;
1220 if (form == 0) {
1221 DumpCond(opcode, cond);
1222 imm32 = (S << 20) | (J2 << 19) | (J1 << 18) | (imm6 << 12) | (imm11 << 1);
1223 imm32 = (imm32 << 11) >> 11; // sign extend 21 bit immediate.
1224 } else {
1225 uint32_t I1 = ~(J1 ^ S);
1226 uint32_t I2 = ~(J2 ^ S);
1227 imm32 = (S << 24) | (I1 << 23) | (I2 << 22) | (imm10 << 12) | (imm11 << 1);
1228 imm32 = (imm32 << 8) >> 8; // sign extend 24 bit immediate.
1229 }
1230 opcode << ".w";
1231 DumpBranchTarget(args, instr_ptr + 4, imm32);
1232 break;
1233 }
1234 case 4: case 6: case 5: case 7: {
1235 // BL, BLX (immediate)
1236 // |111|11|1|0000000000|11|1 |1|1 |10000000000|
1237 // |5 3|21|0|9876543 0|54|3 |2|1 |0 5 0|
1238 // |---|--|-|----------|--|--|-|--|-----------|
1239 // |332|22|2|2222221111|11|1 |1|1 |10000000000|
1240 // |1 9|87|6|5 0 6|54|3 |2|1 |0 5 0|
1241 // |---|--|-|----------|--|--|-|--|-----------|
1242 // |111|10|S| imm10 |11|J1|L|J2| imm11 |
1243 uint32_t S = (instr >> 26) & 1;
1244 uint32_t J2 = (instr >> 11) & 1;
1245 uint32_t L = (instr >> 12) & 1;
1246 uint32_t J1 = (instr >> 13) & 1;
1247 uint32_t imm10 = (instr >> 16) & 0x3FF;
1248 uint32_t imm11 = instr & 0x7FF;
1249 if (L == 0) {
1250 opcode << "bx";
1251 } else {
1252 opcode << "blx";
1253 }
1254 uint32_t I1 = ~(J1 ^ S);
1255 uint32_t I2 = ~(J2 ^ S);
1256 int32_t imm32 = (S << 24) | (I1 << 23) | (I2 << 22) | (imm10 << 12) | (imm11 << 1);
1257 imm32 = (imm32 << 8) >> 8; // sign extend 24 bit immediate.
1258 DumpBranchTarget(args, instr_ptr + 4, imm32);
1259 break;
1260 }
1261 }
1262 }
1263 break;
1264 case 3:
1265 switch (op2) {
1266 case 0x00: case 0x02: case 0x04: case 0x06: // 000xxx0
1267 case 0x08: case 0x09: case 0x0A: case 0x0C: case 0x0E: {
1268 // Store single data item
1269 // |111|11|100|000|0|0000|1111|110000|000000|
1270 // |5 3|21|098|765|4|3 0|5 2|10 6|5 0|
1271 // |---|--|---|---|-|----|----|------|------|
1272 // |332|22|222|222|2|1111|1111|110000|000000|
1273 // |1 9|87|654|321|0|9 6|5 2|10 6|5 0|
1274 // |---|--|---|---|-|----|----|------|------|
1275 // |111|11|000|op3|0| | | op4 | |
1276 uint32_t op3 = (instr >> 21) & 7;
1277 // uint32_t op4 = (instr >> 6) & 0x3F;
1278 switch (op3) {
1279 case 0x0: case 0x4: {
1280 // {ST,LD}RB Rt,[Rn,#+/-imm12] - 111 11 00 0 1 00 0 nnnn tttt 1 PUWii ii iiii
1281 // {ST,LD}RB Rt,[Rn,#+/-imm8] - 111 11 00 0 0 00 0 nnnn tttt 1 PUWii ii iiii
1282 // {ST,LD}RB Rt,[Rn,Rm,lsl #imm2] - 111 11 00 0 0 00 0 nnnn tttt 0 00000 ii mmmm
1283 ArmRegister Rn(instr, 16);
1284 ArmRegister Rt(instr, 12);
1285 opcode << (HasBitSet(instr, 20) ? "ldrb" : "strb");
1286 if (HasBitSet(instr, 23)) {
1287 uint32_t imm12 = instr & 0xFFF;
1288 args << Rt << ", [" << Rn << ",#" << imm12 << "]";
1289 } else if ((instr & 0x800) != 0) {
1290 uint32_t imm8 = instr & 0xFF;
1291 args << Rt << ", [" << Rn << ",#" << imm8 << "]";
1292 } else {
1293 uint32_t imm2 = (instr >> 4) & 3;
1294 ArmRegister Rm(instr, 0);
1295 args << Rt << ", [" << Rn << ", " << Rm;
1296 if (imm2 != 0) {
1297 args << ", " << "lsl #" << imm2;
1298 }
1299 args << "]";
1300 }
1301 break;
1302 }
1303 case 0x1: case 0x5: {
1304 // STRH Rt,[Rn,#+/-imm12] - 111 11 00 0 1 01 0 nnnn tttt 1 PUWii ii iiii
1305 // STRH Rt,[Rn,#+/-imm8] - 111 11 00 0 0 01 0 nnnn tttt 1 PUWii ii iiii
1306 // STRH Rt,[Rn,Rm,lsl #imm2] - 111 11 00 0 0 01 0 nnnn tttt 0 00000 ii mmmm
1307 ArmRegister Rn(instr, 16);
1308 ArmRegister Rt(instr, 12);
1309 opcode << "strh";
1310 if (HasBitSet(instr, 23)) {
1311 uint32_t imm12 = instr & 0xFFF;
1312 args << Rt << ", [" << Rn << ",#" << imm12 << "]";
1313 } else if ((instr & 0x800) != 0) {
1314 uint32_t imm8 = instr & 0xFF;
1315 args << Rt << ", [" << Rn << ",#" << imm8 << "]";
1316 } else {
1317 uint32_t imm2 = (instr >> 4) & 3;
1318 ArmRegister Rm(instr, 0);
1319 args << Rt << ", [" << Rn << ", " << Rm;
1320 if (imm2 != 0) {
1321 args << ", " << "lsl #" << imm2;
1322 }
1323 args << "]";
1324 }
1325 break;
1326 }
1327 case 0x2: case 0x6: {
1328 ArmRegister Rn(instr, 16);
1329 ArmRegister Rt(instr, 12);
1330 if (op3 == 2) {
1331 if ((instr & 0x800) != 0) {
1332 // STR Rt, [Rn, #imm8] - 111 11 000 010 0 nnnn tttt 1PUWiiiiiiii
1333 uint32_t P = (instr >> 10) & 1;
1334 uint32_t U = (instr >> 9) & 1;
1335 uint32_t W = (instr >> 8) & 1;
1336 uint32_t imm8 = instr & 0xFF;
1337 int32_t imm32 = (imm8 << 24) >> 24; // sign-extend imm8
1338 if (Rn.r == 13 && P == 1 && U == 0 && W == 1 && imm32 == 4) {
1339 opcode << "push";
1340 args << "{" << Rt << "}";
1341 } else if (Rn.r == 15 || (P == 0 && W == 0)) {
1342 opcode << "UNDEFINED";
1343 } else {
1344 if (P == 1 && U == 1 && W == 0) {
1345 opcode << "strt";
1346 } else {
1347 opcode << "str";
1348 }
1349 args << Rt << ", [" << Rn;
1350 if (P == 0 && W == 1) {
1351 args << "], #" << imm32;
1352 } else {
1353 args << ", #" << imm32 << "]";
1354 if (W == 1) {
1355 args << "!";
1356 }
1357 }
1358 }
1359 } else {
1360 // STR Rt, [Rn, Rm, LSL #imm2] - 111 11 000 010 0 nnnn tttt 000000iimmmm
1361 ArmRegister Rn(instr, 16);
1362 ArmRegister Rt(instr, 12);
1363 ArmRegister Rm(instr, 0);
1364 uint32_t imm2 = (instr >> 4) & 3;
1365 opcode << "str.w";
1366 args << Rt << ", [" << Rn << ", " << Rm;
1367 if (imm2 != 0) {
1368 args << ", lsl #" << imm2;
1369 }
1370 args << "]";
1371 }
1372 } else if (op3 == 6) {
1373 // STR.W Rt, [Rn, #imm12] - 111 11 000 110 0 nnnn tttt iiiiiiiiiiii
1374 uint32_t imm12 = instr & 0xFFF;
1375 opcode << "str.w";
1376 args << Rt << ", [" << Rn << ", #" << imm12 << "]";
1377 }
1378 break;
1379 }
1380 }
1381
1382 break;
1383 }
1384 case 0x03: case 0x0B: case 0x11: case 0x13: case 0x19: case 0x1B: { // 00xx011
1385 // Load byte/halfword
1386 // |111|11|10|0 0|00|0|0000|1111|110000|000000|
1387 // |5 3|21|09|8 7|65|4|3 0|5 2|10 6|5 0|
1388 // |---|--|--|---|--|-|----|----|------|------|
1389 // |332|22|22|2 2|22|2|1111|1111|110000|000000|
1390 // |1 9|87|65|4 3|21|0|9 6|5 2|10 6|5 0|
1391 // |---|--|--|---|--|-|----|----|------|------|
1392 // |111|11|00|op3|01|1| Rn | Rt | op4 | |
1393 // |111|11| op2 | | | imm12 |
1394 uint32_t op3 = (instr >> 23) & 3;
1395 ArmRegister Rn(instr, 16);
1396 ArmRegister Rt(instr, 12);
1397 if (Rt.r != 15) {
1398 if (op3 == 1) {
1399 // LDRH.W Rt, [Rn, #imm12] - 111 11 00 01 011 nnnn tttt iiiiiiiiiiii
1400 uint32_t imm12 = instr & 0xFFF;
1401 opcode << "ldrh.w";
1402 args << Rt << ", [" << Rn << ", #" << imm12 << "]";
1403 if (Rn.r == 9) {
1404 args << " ; ";
1405 Thread::DumpThreadOffset<4>(args, imm12);
1406 } else if (Rn.r == 15) {
1407 intptr_t lit_adr = reinterpret_cast<intptr_t>(instr_ptr);
1408 lit_adr = RoundDown(lit_adr, 4) + 4 + imm12;
1409 args << StringPrintf(" ; 0x%08x", *reinterpret_cast<int32_t*>(lit_adr));
1410 }
1411 } else if (op3 == 3) {
1412 // LDRSH.W Rt, [Rn, #imm12] - 111 11 00 11 011 nnnn tttt iiiiiiiiiiii
1413 // LDRSB.W Rt, [Rn, #imm12] - 111 11 00 11 001 nnnn tttt iiiiiiiiiiii
1414 uint32_t imm12 = instr & 0xFFF;
1415 opcode << (HasBitSet(instr, 20) ? "ldrsb.w" : "ldrsh.w");
1416 args << Rt << ", [" << Rn << ", #" << imm12 << "]";
1417 if (Rn.r == 9) {
1418 args << " ; ";
1419 Thread::DumpThreadOffset<4>(args, imm12);
1420 } else if (Rn.r == 15) {
1421 intptr_t lit_adr = reinterpret_cast<intptr_t>(instr_ptr);
1422 lit_adr = RoundDown(lit_adr, 4) + 4 + imm12;
1423 args << StringPrintf(" ; 0x%08x", *reinterpret_cast<int32_t*>(lit_adr));
1424 }
1425 }
1426 }
1427 break;
1428 }
1429 case 0x29: { // 0101001
1430 // |111|11|1000000|0000|1111|1100|00|0 0|0000|
1431 // |5 3|21|0 4|3 0|5 2|1 8|76|5 4|3 0|
1432 // |---|--|-------|----|----|----|--|---|----|
1433 // |332|22|2222222|1111|1111|1100|00|0 0|0000|
1434 // |1 9|87|6 0|9 6|5 2|1 8|76|5 4|3 0|
1435 // |---|--|-------|----|----|----|--|---|----|
1436 // |111|11|0101001| Rm |1111| Rd |11|op3| Rm |
1437 // REV - 111 11 0101001 mmmm 1111 dddd 1000 mmmm
1438 // REV16 - 111 11 0101001 mmmm 1111 dddd 1001 mmmm
1439 // RBIT - 111 11 0101001 mmmm 1111 dddd 1010 mmmm
1440 // REVSH - 111 11 0101001 mmmm 1111 dddd 1011 mmmm
1441 if ((instr & 0xf0c0) == 0xf080) {
1442 uint32_t op3 = (instr >> 4) & 3;
1443 opcode << kThumbReverseOperations[op3];
1444 ArmRegister Rm(instr, 0);
1445 ArmRegister Rd(instr, 8);
1446 args << Rd << ", " << Rm;
1447 ArmRegister Rm2(instr, 16);
1448 if (Rm.r != Rm2.r || Rm.r == 13 || Rm.r == 15 || Rd.r == 13 || Rd.r == 15) {
1449 args << " (UNPREDICTABLE)";
1450 }
1451 } // else unknown instruction
1452 break;
1453 }
1454 case 0x05: case 0x0D: case 0x15: case 0x1D: { // 00xx101
1455 // Load word
1456 // |111|11|10|0 0|00|0|0000|1111|110000|000000|
1457 // |5 3|21|09|8 7|65|4|3 0|5 2|10 6|5 0|
1458 // |---|--|--|---|--|-|----|----|------|------|
1459 // |332|22|22|2 2|22|2|1111|1111|110000|000000|
1460 // |1 9|87|65|4 3|21|0|9 6|5 2|10 6|5 0|
1461 // |---|--|--|---|--|-|----|----|------|------|
1462 // |111|11|00|op3|10|1| Rn | Rt | op4 | |
1463 // |111|11| op2 | | | imm12 |
1464 uint32_t op3 = (instr >> 23) & 3;
1465 uint32_t op4 = (instr >> 6) & 0x3F;
1466 ArmRegister Rn(instr, 16);
1467 ArmRegister Rt(instr, 12);
1468 if (op3 == 1 || Rn.r == 15) {
1469 // LDR.W Rt, [Rn, #imm12] - 111 11 00 00 101 nnnn tttt iiiiiiiiiiii
1470 // LDR.W Rt, [PC, #imm12] - 111 11 00 0x 101 1111 tttt iiiiiiiiiiii
1471 uint32_t imm12 = instr & 0xFFF;
1472 opcode << "ldr.w";
1473 args << Rt << ", [" << Rn << ", #" << imm12 << "]";
1474 if (Rn.r == 9) {
1475 args << " ; ";
1476 Thread::DumpThreadOffset<4>(args, imm12);
1477 } else if (Rn.r == 15) {
1478 intptr_t lit_adr = reinterpret_cast<intptr_t>(instr_ptr);
1479 lit_adr = RoundDown(lit_adr, 4) + 4 + imm12;
1480 args << StringPrintf(" ; 0x%08x", *reinterpret_cast<int32_t*>(lit_adr));
1481 }
1482 } else if (op4 == 0) {
1483 // LDR.W Rt, [Rn, Rm{, LSL #imm2}] - 111 11 00 00 101 nnnn tttt 000000iimmmm
1484 uint32_t imm2 = (instr >> 4) & 0xF;
1485 ArmRegister rm(instr, 0);
1486 opcode << "ldr.w";
1487 args << Rt << ", [" << Rn << ", " << rm;
1488 if (imm2 != 0) {
1489 args << ", lsl #" << imm2;
1490 }
1491 args << "]";
1492 } else {
1493 bool p = (instr & (1 << 10)) != 0;
1494 bool w = (instr & (1 << 8)) != 0;
1495 bool u = (instr & (1 << 9)) != 0;
1496 if (p && u && !w) {
1497 // LDRT Rt, [Rn, #imm8] - 111 11 00 00 101 nnnn tttt 1110iiiiiiii
1498 uint32_t imm8 = instr & 0xFF;
1499 opcode << "ldrt";
1500 args << Rt << ", [" << Rn << ", #" << imm8 << "]";
1501 } else if (Rn.r == 13 && !p && u && w && (instr & 0xff) == 4) {
1502 // POP
1503 opcode << "pop";
1504 args << "{" << Rt << "}";
1505 } else {
1506 bool wback = !p || w;
1507 uint32_t offset = (instr & 0xff);
1508 opcode << "ldr.w";
1509 args << Rt << ",";
1510 if (p && !wback) {
1511 args << "[" << Rn << ", #" << offset << "]";
1512 } else if (p && wback) {
1513 args << "[" << Rn << ", #" << offset << "]!";
1514 } else if (!p && wback) {
1515 args << "[" << Rn << "], #" << offset;
1516 } else {
1517 LOG(FATAL) << p << " " << w;
1518 }
1519 }
1520 }
1521 break;
1522 }
1523 default: // more formats
1524 if ((op2 >> 4) == 2) { // 010xxxx
1525 // data processing (register)
1526 if ((instr & 0x0080f0f0) == 0x0000f000) {
1527 // LSL, LSR, ASR, ROR
1528 uint32_t shift_op = (instr >> 21) & 3;
1529 uint32_t S = (instr >> 20) & 1;
1530 ArmRegister Rd(instr, 8);
1531 ArmRegister Rn(instr, 16);
1532 ArmRegister Rm(instr, 0);
1533 opcode << kThumb2ShiftOperations[shift_op] << (S != 0 ? "s" : "");
1534 args << Rd << ", " << Rn << ", " << Rm;
1535 }
1536 } else if ((op2 >> 3) == 6) { // 0110xxx
1537 // Multiply, multiply accumulate, and absolute difference
1538 op1 = (instr >> 20) & 0x7;
1539 op2 = (instr >> 4) & 0x2;
1540 ArmRegister Ra(instr, 12);
1541 ArmRegister Rn(instr, 16);
1542 ArmRegister Rm(instr, 0);
1543 ArmRegister Rd(instr, 8);
1544 switch (op1) {
1545 case 0:
1546 if (op2 == 0) {
1547 if (Ra.r == 0xf) {
1548 opcode << "mul";
1549 args << Rd << ", " << Rn << ", " << Rm;
1550 } else {
1551 opcode << "mla";
1552 args << Rd << ", " << Rn << ", " << Rm << ", " << Ra;
1553 }
1554 } else {
1555 opcode << "mls";
1556 args << Rd << ", " << Rn << ", " << Rm << ", " << Ra;
1557 }
1558 break;
1559 case 1:
1560 case 2:
1561 case 3:
1562 case 4:
1563 case 5:
1564 case 6:
1565 break; // do these sometime
1566 }
1567 } else if ((op2 >> 3) == 7) { // 0111xxx
1568 // Long multiply, long multiply accumulate, and divide
1569 op1 = (instr >> 20) & 0x7;
1570 op2 = (instr >> 4) & 0xf;
1571 ArmRegister Rn(instr, 16);
1572 ArmRegister Rm(instr, 0);
1573 ArmRegister Rd(instr, 8);
1574 ArmRegister RdHi(instr, 8);
1575 ArmRegister RdLo(instr, 12);
1576 switch (op1) {
1577 case 0:
1578 opcode << "smull";
1579 args << RdLo << ", " << RdHi << ", " << Rn << ", " << Rm;
1580 break;
1581 case 1:
1582 opcode << "sdiv";
1583 args << Rd << ", " << Rn << ", " << Rm;
1584 break;
1585 case 2:
1586 opcode << "umull";
1587 args << RdLo << ", " << RdHi << ", " << Rn << ", " << Rm;
1588 break;
1589 case 3:
1590 opcode << "udiv";
1591 args << Rd << ", " << Rn << ", " << Rm;
1592 break;
1593 case 4:
1594 case 5:
1595 case 6:
1596 break; // TODO: when we generate these...
1597 }
1598 }
1599 }
1600 default:
1601 break;
1602 }
1603
1604 // Apply any IT-block conditions to the opcode if necessary.
1605 if (!it_conditions_.empty()) {
1606 opcode << it_conditions_.back();
1607 it_conditions_.pop_back();
1608 }
1609 if (opcode.str().size() == 0) {
1610 opcode << "UNKNOWN " << op2;
1611 }
1612
1613 os << FormatInstructionPointer(instr_ptr)
1614 << StringPrintf(": %08x\t%-7s ", instr, opcode.str().c_str())
1615 << args.str() << '\n';
1616 return 4;
1617 } // NOLINT(readability/fn_size)
1618
DumpThumb16(std::ostream & os,const uint8_t * instr_ptr)1619 size_t DisassemblerArm::DumpThumb16(std::ostream& os, const uint8_t* instr_ptr) {
1620 uint16_t instr = ReadU16(instr_ptr);
1621 bool is_32bit = ((instr & 0xF000) == 0xF000) || ((instr & 0xF800) == 0xE800);
1622 if (is_32bit) {
1623 return DumpThumb32(os, instr_ptr);
1624 } else {
1625 std::ostringstream opcode;
1626 std::ostringstream args;
1627 uint16_t opcode1 = instr >> 10;
1628 if (opcode1 < 0x10) {
1629 // shift (immediate), add, subtract, move, and compare
1630 uint16_t opcode2 = instr >> 9;
1631 switch (opcode2) {
1632 case 0x0: case 0x1: case 0x2: case 0x3: case 0x4: case 0x5: case 0x6: case 0x7:
1633 case 0x8: case 0x9: case 0xA: case 0xB: {
1634 // Logical shift left - 00 000xx iii mmm ddd
1635 // Logical shift right - 00 001xx iii mmm ddd
1636 // Arithmetic shift right - 00 010xx iii mmm ddd
1637 uint16_t imm5 = (instr >> 6) & 0x1F;
1638 ThumbRegister rm(instr, 3);
1639 ThumbRegister Rd(instr, 0);
1640 if (opcode2 <= 3) {
1641 opcode << "lsls";
1642 } else if (opcode2 <= 7) {
1643 opcode << "lsrs";
1644 } else {
1645 opcode << "asrs";
1646 }
1647 args << Rd << ", " << rm << ", #" << imm5;
1648 break;
1649 }
1650 case 0xC: case 0xD: case 0xE: case 0xF: {
1651 // Add register - 00 01100 mmm nnn ddd
1652 // Sub register - 00 01101 mmm nnn ddd
1653 // Add 3-bit immediate - 00 01110 iii nnn ddd
1654 // Sub 3-bit immediate - 00 01111 iii nnn ddd
1655 uint16_t imm3_or_Rm = (instr >> 6) & 7;
1656 ThumbRegister Rn(instr, 3);
1657 ThumbRegister Rd(instr, 0);
1658 if ((opcode2 & 2) != 0 && imm3_or_Rm == 0) {
1659 opcode << "mov";
1660 } else {
1661 if ((opcode2 & 1) == 0) {
1662 opcode << "adds";
1663 } else {
1664 opcode << "subs";
1665 }
1666 }
1667 args << Rd << ", " << Rn;
1668 if ((opcode2 & 2) == 0) {
1669 ArmRegister Rm(imm3_or_Rm);
1670 args << ", " << Rm;
1671 } else if (imm3_or_Rm != 0) {
1672 args << ", #" << imm3_or_Rm;
1673 }
1674 break;
1675 }
1676 case 0x10: case 0x11: case 0x12: case 0x13:
1677 case 0x14: case 0x15: case 0x16: case 0x17:
1678 case 0x18: case 0x19: case 0x1A: case 0x1B:
1679 case 0x1C: case 0x1D: case 0x1E: case 0x1F: {
1680 // MOVS Rd, #imm8 - 00100 ddd iiiiiiii
1681 // CMP Rn, #imm8 - 00101 nnn iiiiiiii
1682 // ADDS Rn, #imm8 - 00110 nnn iiiiiiii
1683 // SUBS Rn, #imm8 - 00111 nnn iiiiiiii
1684 ThumbRegister Rn(instr, 8);
1685 uint16_t imm8 = instr & 0xFF;
1686 switch (opcode2 >> 2) {
1687 case 4: opcode << "movs"; break;
1688 case 5: opcode << "cmp"; break;
1689 case 6: opcode << "adds"; break;
1690 case 7: opcode << "subs"; break;
1691 }
1692 args << Rn << ", #" << imm8;
1693 break;
1694 }
1695 default:
1696 break;
1697 }
1698 } else if (opcode1 == 0x10) {
1699 // Data-processing
1700 uint16_t opcode2 = (instr >> 6) & 0xF;
1701 ThumbRegister rm(instr, 3);
1702 ThumbRegister rdn(instr, 0);
1703 opcode << kThumbDataProcessingOperations[opcode2];
1704 args << rdn << ", " << rm;
1705 } else if (opcode1 == 0x11) {
1706 // Special data instructions and branch and exchange
1707 uint16_t opcode2 = (instr >> 6) & 0x0F;
1708 switch (opcode2) {
1709 case 0x0: case 0x1: case 0x2: case 0x3: {
1710 // Add low registers - 010001 0000 xxxxxx
1711 // Add high registers - 010001 0001/001x xxxxxx
1712 uint16_t DN = (instr >> 7) & 1;
1713 ArmRegister rm(instr, 3);
1714 uint16_t Rdn = instr & 7;
1715 ArmRegister DN_Rdn((DN << 3) | Rdn);
1716 opcode << "add";
1717 args << DN_Rdn << ", " << rm;
1718 break;
1719 }
1720 case 0x8: case 0x9: case 0xA: case 0xB: {
1721 // Move low registers - 010001 1000 xxxxxx
1722 // Move high registers - 010001 1001/101x xxxxxx
1723 uint16_t DN = (instr >> 7) & 1;
1724 ArmRegister rm(instr, 3);
1725 uint16_t Rdn = instr & 7;
1726 ArmRegister DN_Rdn((DN << 3) | Rdn);
1727 opcode << "mov";
1728 args << DN_Rdn << ", " << rm;
1729 break;
1730 }
1731 case 0x5: case 0x6: case 0x7: {
1732 // Compare high registers - 010001 0101/011x xxxxxx
1733 uint16_t N = (instr >> 7) & 1;
1734 ArmRegister rm(instr, 3);
1735 uint16_t Rn = instr & 7;
1736 ArmRegister N_Rn((N << 3) | Rn);
1737 opcode << "cmp";
1738 args << N_Rn << ", " << rm;
1739 break;
1740 }
1741 case 0xC: case 0xD: case 0xE: case 0xF: {
1742 // Branch and exchange - 010001 110x xxxxxx
1743 // Branch with link and exchange - 010001 111x xxxxxx
1744 ArmRegister rm(instr, 3);
1745 opcode << ((opcode2 & 0x2) == 0 ? "bx" : "blx");
1746 args << rm;
1747 break;
1748 }
1749 default:
1750 break;
1751 }
1752 } else if (opcode1 == 0x12 || opcode1 == 0x13) { // 01001x
1753 ThumbRegister Rt(instr, 8);
1754 uint16_t imm8 = instr & 0xFF;
1755 opcode << "ldr";
1756 args << Rt << ", [pc, #" << (imm8 << 2) << "]";
1757 } else if ((opcode1 >= 0x14 && opcode1 <= 0x17) || // 0101xx
1758 (opcode1 >= 0x18 && opcode1 <= 0x1f) || // 011xxx
1759 (opcode1 >= 0x20 && opcode1 <= 0x27)) { // 100xxx
1760 // Load/store single data item
1761 uint16_t opA = (instr >> 12) & 0xF;
1762 if (opA == 0x5) {
1763 uint16_t opB = (instr >> 9) & 0x7;
1764 ThumbRegister Rm(instr, 6);
1765 ThumbRegister Rn(instr, 3);
1766 ThumbRegister Rt(instr, 0);
1767 switch (opB) {
1768 case 0: opcode << "str"; break;
1769 case 1: opcode << "strh"; break;
1770 case 2: opcode << "strb"; break;
1771 case 3: opcode << "ldrsb"; break;
1772 case 4: opcode << "ldr"; break;
1773 case 5: opcode << "ldrh"; break;
1774 case 6: opcode << "ldrb"; break;
1775 case 7: opcode << "ldrsh"; break;
1776 }
1777 args << Rt << ", [" << Rn << ", " << Rm << "]";
1778 } else if (opA == 9) {
1779 uint16_t opB = (instr >> 11) & 1;
1780 ThumbRegister Rt(instr, 8);
1781 uint16_t imm8 = instr & 0xFF;
1782 opcode << (opB == 0 ? "str" : "ldr");
1783 args << Rt << ", [sp, #" << (imm8 << 2) << "]";
1784 } else {
1785 uint16_t imm5 = (instr >> 6) & 0x1F;
1786 uint16_t opB = (instr >> 11) & 1;
1787 ThumbRegister Rn(instr, 3);
1788 ThumbRegister Rt(instr, 0);
1789 switch (opA) {
1790 case 6:
1791 imm5 <<= 2;
1792 opcode << (opB == 0 ? "str" : "ldr");
1793 break;
1794 case 7:
1795 imm5 <<= 0;
1796 opcode << (opB == 0 ? "strb" : "ldrb");
1797 break;
1798 case 8:
1799 imm5 <<= 1;
1800 opcode << (opB == 0 ? "strh" : "ldrh");
1801 break;
1802 }
1803 args << Rt << ", [" << Rn << ", #" << imm5 << "]";
1804 }
1805 } else if (opcode1 >= 0x34 && opcode1 <= 0x37) { // 1101xx
1806 int8_t imm8 = instr & 0xFF;
1807 uint32_t cond = (instr >> 8) & 0xF;
1808 opcode << "b";
1809 DumpCond(opcode, cond);
1810 DumpBranchTarget(args, instr_ptr + 4, (imm8 << 1));
1811 } else if ((instr & 0xF800) == 0xA800) {
1812 // Generate SP-relative address
1813 ThumbRegister rd(instr, 8);
1814 int imm8 = instr & 0xFF;
1815 opcode << "add";
1816 args << rd << ", sp, #" << (imm8 << 2);
1817 } else if ((instr & 0xF000) == 0xB000) {
1818 // Miscellaneous 16-bit instructions
1819 uint16_t opcode2 = (instr >> 5) & 0x7F;
1820 switch (opcode2) {
1821 case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07: {
1822 // Add immediate to SP - 1011 00000 ii iiiii
1823 // Subtract immediate from SP - 1011 00001 ii iiiii
1824 int imm7 = instr & 0x7F;
1825 opcode << ((opcode2 & 4) == 0 ? "add" : "sub");
1826 args << "sp, sp, #" << (imm7 << 2);
1827 break;
1828 }
1829 case 0x08: case 0x09: case 0x0A: case 0x0B: // 0001xxx
1830 case 0x0C: case 0x0D: case 0x0E: case 0x0F:
1831 case 0x18: case 0x19: case 0x1A: case 0x1B: // 0011xxx
1832 case 0x1C: case 0x1D: case 0x1E: case 0x1F:
1833 case 0x48: case 0x49: case 0x4A: case 0x4B: // 1001xxx
1834 case 0x4C: case 0x4D: case 0x4E: case 0x4F:
1835 case 0x58: case 0x59: case 0x5A: case 0x5B: // 1011xxx
1836 case 0x5C: case 0x5D: case 0x5E: case 0x5F: {
1837 // CBNZ, CBZ
1838 uint16_t op = (instr >> 11) & 1;
1839 uint16_t i = (instr >> 9) & 1;
1840 uint16_t imm5 = (instr >> 3) & 0x1F;
1841 ThumbRegister Rn(instr, 0);
1842 opcode << (op != 0 ? "cbnz" : "cbz");
1843 uint32_t imm32 = (i << 6) | (imm5 << 1);
1844 args << Rn << ", ";
1845 DumpBranchTarget(args, instr_ptr + 4, imm32);
1846 break;
1847 }
1848 case 0x50: case 0x51: // 101000x
1849 case 0x52: case 0x53: // 101001x
1850 case 0x56: case 0x57: { // 101011x
1851 uint16_t op = (instr >> 6) & 3;
1852 opcode << kThumbReverseOperations[op];
1853 ThumbRegister Rm(instr, 3);
1854 ThumbRegister Rd(instr, 0);
1855 args << Rd << ", " << Rm;
1856 break;
1857 }
1858 case 0x78: case 0x79: case 0x7A: case 0x7B: // 1111xxx
1859 case 0x7C: case 0x7D: case 0x7E: case 0x7F: {
1860 // If-Then, and hints
1861 uint16_t opA = (instr >> 4) & 0xF;
1862 uint16_t opB = instr & 0xF;
1863 if (opB == 0) {
1864 switch (opA) {
1865 case 0: opcode << "nop"; break;
1866 case 1: opcode << "yield"; break;
1867 case 2: opcode << "wfe"; break;
1868 case 3: opcode << "sev"; break;
1869 default: break;
1870 }
1871 } else {
1872 uint32_t first_cond = opA;
1873 uint32_t mask = opB;
1874 opcode << "it";
1875
1876 // Flesh out the base "it" opcode with the specific collection of 't's and 'e's,
1877 // and store up the actual condition codes we'll want to add to the next few opcodes.
1878 size_t count = 3 - CTZ(mask);
1879 it_conditions_.resize(count + 2); // Plus the implicit 't', plus the "" for the IT itself.
1880 for (size_t i = 0; i < count; ++i) {
1881 bool positive_cond = ((first_cond & 1) != 0);
1882 bool positive_mask = ((mask & (1 << (3 - i))) != 0);
1883 if (positive_mask == positive_cond) {
1884 opcode << 't';
1885 it_conditions_[i] = kConditionCodeNames[first_cond];
1886 } else {
1887 opcode << 'e';
1888 it_conditions_[i] = kConditionCodeNames[first_cond ^ 1];
1889 }
1890 }
1891 it_conditions_[count] = kConditionCodeNames[first_cond]; // The implicit 't'.
1892
1893 it_conditions_[count + 1] = ""; // No condition code for the IT itself...
1894 DumpCond(args, first_cond); // ...because it's considered an argument.
1895 }
1896 break;
1897 }
1898 default:
1899 break;
1900 }
1901 } else if (((instr & 0xF000) == 0x5000) || ((instr & 0xE000) == 0x6000) ||
1902 ((instr & 0xE000) == 0x8000)) {
1903 // Load/store single data item
1904 uint16_t opA = instr >> 12;
1905 // uint16_t opB = (instr >> 9) & 7;
1906 switch (opA) {
1907 case 0x6: {
1908 // STR Rt, [Rn, #imm] - 01100 iiiii nnn ttt
1909 // LDR Rt, [Rn, #imm] - 01101 iiiii nnn ttt
1910 uint16_t imm5 = (instr >> 6) & 0x1F;
1911 ThumbRegister Rn(instr, 3);
1912 ThumbRegister Rt(instr, 0);
1913 opcode << ((instr & 0x800) == 0 ? "str" : "ldr");
1914 args << Rt << ", [" << Rn << ", #" << (imm5 << 2) << "]";
1915 break;
1916 }
1917 case 0x9: {
1918 // STR Rt, [SP, #imm] - 01100 ttt iiiiiiii
1919 // LDR Rt, [SP, #imm] - 01101 ttt iiiiiiii
1920 uint16_t imm8 = instr & 0xFF;
1921 ThumbRegister Rt(instr, 8);
1922 opcode << ((instr & 0x800) == 0 ? "str" : "ldr");
1923 args << Rt << ", [sp, #" << (imm8 << 2) << "]";
1924 break;
1925 }
1926 default:
1927 break;
1928 }
1929 } else if (opcode1 == 0x38 || opcode1 == 0x39) {
1930 uint16_t imm11 = instr & 0x7FFF;
1931 int32_t imm32 = imm11 << 1;
1932 imm32 = (imm32 << 20) >> 20; // sign extend 12 bit immediate
1933 opcode << "b";
1934 DumpBranchTarget(args, instr_ptr + 4, imm32);
1935 }
1936
1937 // Apply any IT-block conditions to the opcode if necessary.
1938 if (!it_conditions_.empty()) {
1939 opcode << it_conditions_.back();
1940 it_conditions_.pop_back();
1941 }
1942
1943 os << FormatInstructionPointer(instr_ptr)
1944 << StringPrintf(": %04x \t%-7s ", instr, opcode.str().c_str())
1945 << args.str() << '\n';
1946 }
1947 return 2;
1948 }
1949
1950 } // namespace arm
1951 } // namespace art
1952