1 | /* |
2 | * Copyright (C) 2013 Apple Inc. All rights reserved. |
3 | * |
4 | * Redistribution and use in source and binary forms, with or without |
5 | * modification, are permitted provided that the following conditions |
6 | * are met: |
7 | * 1. Redistributions of source code must retain the above copyright |
8 | * notice, this list of conditions and the following disclaimer. |
9 | * 2. Redistributions in binary form must reproduce the above copyright |
10 | * notice, this list of conditions and the following disclaimer in the |
11 | * documentation and/or other materials provided with the distribution. |
12 | * |
13 | * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY |
14 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
15 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
16 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR |
17 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
18 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
19 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
20 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
21 | * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
22 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
23 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
24 | */ |
25 | |
26 | #include "config.h" |
27 | |
28 | #if USE(ARMV7_DISASSEMBLER) |
29 | |
30 | #include "ARMv7DOpcode.h" |
31 | |
32 | #include <stdarg.h> |
33 | #include <stdint.h> |
34 | #include <stdio.h> |
35 | #include <string.h> |
36 | |
37 | namespace JSC { namespace ARMv7Disassembler { |
38 | |
39 | ARMv7D16BitOpcode::OpcodeGroup* ARMv7D16BitOpcode::opcodeTable[32]; |
40 | ARMv7D32BitOpcode::OpcodeGroup* ARMv7D32BitOpcode::opcodeTable[16]; |
41 | |
42 | const char* const ARMv7DOpcode::s_conditionNames[16] = { |
43 | "eq" , "ne" , "hs" , "lo" , "mi" , "pl" , "vs" , "vc" , |
44 | "hi" , "ls" , "ge" , "lt" , "gt" , "le" , "al" , "al" |
45 | }; |
46 | |
47 | const char* const ARMv7DOpcode::s_optionName[8] = { |
48 | "uxtb" , "uxth" , "uxtw" , "uxtx" , "sxtb" , "sxth" , "sxtw" , "sxtx" |
49 | }; |
50 | |
51 | const char* const ARMv7DOpcode::s_shiftNames[4] = { |
52 | "lsl" , "lsr" , "asr" , "ror" |
53 | }; |
54 | |
55 | const char* const ARMv7DOpcode::s_specialRegisterNames[3] = { "sp" , "lr" , "pc" }; |
56 | |
57 | template <typename OpcodeType, typename InstructionType> |
58 | struct OpcodeGroupInitializer { |
59 | unsigned m_opcodeGroupNumber; |
60 | InstructionType m_mask; |
61 | InstructionType m_pattern; |
62 | const char* (*m_format)(OpcodeType*); |
63 | }; |
64 | |
65 | #define OPCODE_GROUP_ENTRY(groupIndex, groupClass) \ |
66 | { groupIndex, groupClass::s_mask, groupClass::s_pattern, groupClass::format } |
67 | |
68 | typedef OpcodeGroupInitializer<ARMv7D16BitOpcode, uint16_t> Opcode16GroupInitializer; |
69 | typedef OpcodeGroupInitializer<ARMv7D32BitOpcode, uint32_t> Opcode32GroupInitializer; |
70 | |
71 | static Opcode16GroupInitializer opcode16BitGroupList[] = { |
72 | OPCODE_GROUP_ENTRY(0x0, ARMv7DOpcodeLogicalImmediateT1), |
73 | OPCODE_GROUP_ENTRY(0x1, ARMv7DOpcodeLogicalImmediateT1), |
74 | OPCODE_GROUP_ENTRY(0x2, ARMv7DOpcodeLogicalImmediateT1), |
75 | OPCODE_GROUP_ENTRY(0x3, ARMv7DOpcodeAddSubtractT1), |
76 | OPCODE_GROUP_ENTRY(0x3, ARMv7DOpcodeAddSubtractImmediate3), |
77 | OPCODE_GROUP_ENTRY(0x4, ARMv7DOpcodeMoveImmediateT1), |
78 | OPCODE_GROUP_ENTRY(0x5, ARMv7DOpcodeCompareImmediateT1), |
79 | OPCODE_GROUP_ENTRY(0x6, ARMv7DOpcodeAddSubtractImmediate8), |
80 | OPCODE_GROUP_ENTRY(0x7, ARMv7DOpcodeAddSubtractImmediate8), |
81 | OPCODE_GROUP_ENTRY(0x8, ARMv7DOpcodeDataProcessingRegisterT1), |
82 | OPCODE_GROUP_ENTRY(0x8, ARMv7DOpcodeAddRegisterT2), |
83 | OPCODE_GROUP_ENTRY(0x8, ARMv7DOpcodeCompareRegisterT2), |
84 | OPCODE_GROUP_ENTRY(0x8, ARMv7DOpcodeCompareRegisterT1), |
85 | OPCODE_GROUP_ENTRY(0x8, ARMv7DOpcodeMoveRegisterT1), |
86 | OPCODE_GROUP_ENTRY(0x8, ARMv7DOpcodeBranchExchangeT1), |
87 | OPCODE_GROUP_ENTRY(0x9, ARMv7DOpcodeLoadFromLiteralPool), |
88 | OPCODE_GROUP_ENTRY(0xa, ARMv7DOpcodeLoadStoreRegisterOffsetT1), |
89 | OPCODE_GROUP_ENTRY(0xb, ARMv7DOpcodeLoadStoreRegisterOffsetT1), |
90 | OPCODE_GROUP_ENTRY(0xc, ARMv7DOpcodeLoadStoreRegisterImmediateWordAndByte), |
91 | OPCODE_GROUP_ENTRY(0xd, ARMv7DOpcodeLoadStoreRegisterImmediateWordAndByte), |
92 | OPCODE_GROUP_ENTRY(0xe, ARMv7DOpcodeLoadStoreRegisterImmediateWordAndByte), |
93 | OPCODE_GROUP_ENTRY(0xf, ARMv7DOpcodeLoadStoreRegisterImmediateWordAndByte), |
94 | OPCODE_GROUP_ENTRY(0x10, ARMv7DOpcodeLoadStoreRegisterImmediateHalfWord), |
95 | OPCODE_GROUP_ENTRY(0x11, ARMv7DOpcodeLoadStoreRegisterImmediateHalfWord), |
96 | OPCODE_GROUP_ENTRY(0x12, ARMv7DOpcodeLoadStoreRegisterSPRelative), |
97 | OPCODE_GROUP_ENTRY(0x13, ARMv7DOpcodeLoadStoreRegisterSPRelative), |
98 | OPCODE_GROUP_ENTRY(0x14, ARMv7DOpcodeGeneratePCRelativeAddress), |
99 | OPCODE_GROUP_ENTRY(0x15, ARMv7DOpcodeAddSPPlusImmediate), |
100 | OPCODE_GROUP_ENTRY(0x16, ARMv7DOpcodeMiscCompareAndBranch), |
101 | OPCODE_GROUP_ENTRY(0x16, ARMv7DOpcodeMiscByteHalfwordOps), |
102 | OPCODE_GROUP_ENTRY(0x16, ARMv7DOpcodeMiscPushPop), |
103 | OPCODE_GROUP_ENTRY(0x16, ARMv7DOpcodeMiscAddSubSP), |
104 | OPCODE_GROUP_ENTRY(0x17, ARMv7DOpcodeMiscHint16), // Needs to be before IfThenT1 |
105 | OPCODE_GROUP_ENTRY(0x17, ARMv7DOpcodeMiscIfThenT1), |
106 | OPCODE_GROUP_ENTRY(0x17, ARMv7DOpcodeMiscByteHalfwordOps), |
107 | OPCODE_GROUP_ENTRY(0x17, ARMv7DOpcodeMiscCompareAndBranch), |
108 | OPCODE_GROUP_ENTRY(0x17, ARMv7DOpcodeMiscPushPop), |
109 | OPCODE_GROUP_ENTRY(0x17, ARMv7DOpcodeMiscBreakpointT1), |
110 | OPCODE_GROUP_ENTRY(0x1a, ARMv7DOpcodeBranchConditionalT1), |
111 | OPCODE_GROUP_ENTRY(0x1b, ARMv7DOpcodeBranchConditionalT1), |
112 | OPCODE_GROUP_ENTRY(0x1c, ARMv7DOpcodeBranchT2) |
113 | }; |
114 | |
115 | static Opcode32GroupInitializer opcode32BitGroupList[] = { |
116 | OPCODE_GROUP_ENTRY(0x5, ARMv7DOpcodeDataProcessingShiftedReg), |
117 | OPCODE_GROUP_ENTRY(0x6, ARMv7DOpcodeVMOVSinglePrecision), |
118 | OPCODE_GROUP_ENTRY(0x6, ARMv7DOpcodeVMOVDoublePrecision), |
119 | OPCODE_GROUP_ENTRY(0x6, ARMv7DOpcodeVLDRVSTR), |
120 | OPCODE_GROUP_ENTRY(0x7, ARMv7DOpcodeFPTransfer), |
121 | OPCODE_GROUP_ENTRY(0x7, ARMv7DOpcodeVMSR), |
122 | OPCODE_GROUP_ENTRY(0x7, ARMv7DOpcodeVADDVSUB), |
123 | OPCODE_GROUP_ENTRY(0x7, ARMv7DOpcodeVMUL), |
124 | OPCODE_GROUP_ENTRY(0x7, ARMv7DOpcodeVCVT), |
125 | OPCODE_GROUP_ENTRY(0x7, ARMv7DOpcodeVCMP), |
126 | OPCODE_GROUP_ENTRY(0x8, ARMv7DOpcodeDataProcessingModifiedImmediate), |
127 | OPCODE_GROUP_ENTRY(0x8, ARMv7DOpcodeConditionalBranchT3), |
128 | OPCODE_GROUP_ENTRY(0x8, ARMv7DOpcodeBranchOrBranchLink), |
129 | OPCODE_GROUP_ENTRY(0x9, ARMv7DOpcodeUnmodifiedImmediate), |
130 | OPCODE_GROUP_ENTRY(0x9, ARMv7DOpcodeHint32), |
131 | OPCODE_GROUP_ENTRY(0x9, ARMv7DOpcodeConditionalBranchT3), |
132 | OPCODE_GROUP_ENTRY(0x9, ARMv7DOpcodeBranchOrBranchLink), |
133 | OPCODE_GROUP_ENTRY(0xa, ARMv7DOpcodeDataProcessingModifiedImmediate), |
134 | OPCODE_GROUP_ENTRY(0xa, ARMv7DOpcodeConditionalBranchT3), |
135 | OPCODE_GROUP_ENTRY(0xa, ARMv7DOpcodeBranchOrBranchLink), |
136 | OPCODE_GROUP_ENTRY(0xb, ARMv7DOpcodeUnmodifiedImmediate), |
137 | OPCODE_GROUP_ENTRY(0xb, ARMv7DOpcodeConditionalBranchT3), |
138 | OPCODE_GROUP_ENTRY(0xb, ARMv7DOpcodeBranchOrBranchLink), |
139 | OPCODE_GROUP_ENTRY(0xc, ARMv7DOpcodeLoadRegister), |
140 | OPCODE_GROUP_ENTRY(0xc, ARMv7DOpcodeDataPushPopSingle), // Should be before StoreSingle* |
141 | OPCODE_GROUP_ENTRY(0xc, ARMv7DOpcodeStoreSingleRegister), |
142 | OPCODE_GROUP_ENTRY(0xc, ARMv7DOpcodeStoreSingleImmediate12), |
143 | OPCODE_GROUP_ENTRY(0xc, ARMv7DOpcodeStoreSingleImmediate8), |
144 | OPCODE_GROUP_ENTRY(0xc, ARMv7DOpcodeLoadSignedImmediate), |
145 | OPCODE_GROUP_ENTRY(0xc, ARMv7DOpcodeLoadUnsignedImmediate), |
146 | OPCODE_GROUP_ENTRY(0xd, ARMv7DOpcodeLongMultipleDivide), |
147 | OPCODE_GROUP_ENTRY(0xd, ARMv7DOpcodeDataProcessingRegShift), |
148 | OPCODE_GROUP_ENTRY(0xd, ARMv7DOpcodeDataProcessingRegExtend), |
149 | OPCODE_GROUP_ENTRY(0xd, ARMv7DOpcodeDataProcessingRegParallel), |
150 | OPCODE_GROUP_ENTRY(0xd, ARMv7DOpcodeDataProcessingRegMisc), |
151 | }; |
152 | |
153 | bool ARMv7DOpcode::s_initialized = false; |
154 | |
155 | void ARMv7DOpcode::init() |
156 | { |
157 | if (s_initialized) |
158 | return; |
159 | |
160 | ARMv7D16BitOpcode::init(); |
161 | ARMv7D32BitOpcode::init(); |
162 | |
163 | s_initialized = true; |
164 | } |
165 | |
166 | void ARMv7DOpcode::startITBlock(unsigned blocksize, unsigned firstCondition) |
167 | { |
168 | ASSERT(blocksize > 0 && blocksize <= MaxITBlockSize); |
169 | m_ITBlocksize = blocksize; |
170 | m_ITConditionIndex = m_ITBlocksize + 1; |
171 | m_currentITCondition = 0; |
172 | m_ifThenConditions[0] = firstCondition; |
173 | } |
174 | |
175 | void ARMv7DOpcode::saveITConditionAt(unsigned blockPosition, unsigned condition) |
176 | { |
177 | if (blockPosition < m_ITBlocksize) |
178 | m_ifThenConditions[blockPosition] = static_cast<unsigned char>(condition); |
179 | } |
180 | |
181 | void ARMv7DOpcode::fetchOpcode(uint16_t*& newPC) |
182 | { |
183 | m_bufferOffset = 0; |
184 | m_formatBuffer[0] = '\0'; |
185 | m_currentPC = newPC; |
186 | |
187 | m_opcode = *newPC++; |
188 | |
189 | if (is32BitInstruction()) { |
190 | m_opcode <<= 16; |
191 | m_opcode |= *newPC++; |
192 | } |
193 | |
194 | if (m_ITConditionIndex < m_ITBlocksize) |
195 | m_currentITCondition = m_ifThenConditions[m_ITConditionIndex]; |
196 | else |
197 | m_currentITCondition = CondNone; |
198 | } |
199 | |
200 | const char* ARMv7DOpcode::disassemble(uint16_t*& currentPC) |
201 | { |
202 | const char* result; |
203 | fetchOpcode(currentPC); |
204 | |
205 | if (is32BitInstruction()) |
206 | result = reinterpret_cast<ARMv7D32BitOpcode*>(this)->doDisassemble(); |
207 | else |
208 | result = reinterpret_cast<ARMv7D16BitOpcode*>(this)->doDisassemble(); |
209 | |
210 | if (startingITBlock()) |
211 | m_ITConditionIndex = 0; |
212 | else if (inITBlock() && (++m_ITConditionIndex >= m_ITBlocksize)) |
213 | endITBlock(); |
214 | |
215 | return result; |
216 | } |
217 | |
218 | void ARMv7DOpcode::bufferPrintf(const char* format, ...) |
219 | { |
220 | if (m_bufferOffset >= bufferSize) |
221 | return; |
222 | |
223 | va_list argList; |
224 | va_start(argList, format); |
225 | |
226 | m_bufferOffset += vsnprintf(m_formatBuffer + m_bufferOffset, bufferSize - m_bufferOffset, format, argList); |
227 | |
228 | va_end(argList); |
229 | } |
230 | |
231 | void ARMv7DOpcode::appendInstructionName(const char* instructionName, bool addS) |
232 | { |
233 | if (!inITBlock() && !addS) { |
234 | appendInstructionNameNoITBlock(instructionName); |
235 | |
236 | return; |
237 | } |
238 | |
239 | const char sevenSpaces[8] = " " ; |
240 | |
241 | unsigned length = strlen(instructionName); |
242 | |
243 | bufferPrintf(" %s" , instructionName); |
244 | if (inITBlock()) { |
245 | const char* condition = conditionName(m_currentITCondition); |
246 | length += strlen(condition); |
247 | appendString(condition); |
248 | } else if (addS) { |
249 | length++; |
250 | appendCharacter('s'); |
251 | } |
252 | |
253 | if (length >= 7) |
254 | length = 6; |
255 | |
256 | appendString(sevenSpaces + length); |
257 | } |
258 | |
259 | void ARMv7DOpcode::appendRegisterName(unsigned registerNumber) |
260 | { |
261 | registerNumber &= 0xf; |
262 | |
263 | if (registerNumber > 12) { |
264 | appendString(s_specialRegisterNames[registerNumber - 13]); |
265 | return; |
266 | } |
267 | |
268 | bufferPrintf("r%u" , registerNumber); |
269 | } |
270 | |
271 | void ARMv7DOpcode::appendRegisterList(unsigned registers) |
272 | { |
273 | unsigned numberPrinted = 0; |
274 | |
275 | appendCharacter('{'); |
276 | |
277 | for (unsigned i = 0; i < 16; i++) { |
278 | if (registers & i) { |
279 | if (numberPrinted++) |
280 | appendSeparator(); |
281 | appendRegisterName(i); |
282 | } |
283 | } |
284 | |
285 | appendCharacter('}'); |
286 | } |
287 | |
288 | void ARMv7DOpcode::appendFPRegisterName(char registerPrefix, unsigned registerNumber) |
289 | { |
290 | bufferPrintf("%c%u" , registerPrefix, registerNumber); |
291 | } |
292 | |
293 | // 16 Bit Instructions |
294 | |
295 | void ARMv7D16BitOpcode::init() |
296 | { |
297 | OpcodeGroup* lastGroups[OpcodeGroup::opcodeTableSize]; |
298 | |
299 | for (unsigned i = 0; i < OpcodeGroup::opcodeTableSize; i++) { |
300 | opcodeTable[i] = 0; |
301 | lastGroups[i] = 0; |
302 | } |
303 | |
304 | for (unsigned i = 0; i < sizeof(opcode16BitGroupList) / sizeof(Opcode16GroupInitializer); i++) { |
305 | OpcodeGroup* newOpcodeGroup = new OpcodeGroup(opcode16BitGroupList[i].m_mask, opcode16BitGroupList[i].m_pattern, opcode16BitGroupList[i].m_format); |
306 | uint16_t opcodeGroupNumber = opcode16BitGroupList[i].m_opcodeGroupNumber; |
307 | |
308 | if (!opcodeTable[opcodeGroupNumber]) |
309 | opcodeTable[opcodeGroupNumber] = newOpcodeGroup; |
310 | else |
311 | lastGroups[opcodeGroupNumber]->setNext(newOpcodeGroup); |
312 | lastGroups[opcodeGroupNumber] = newOpcodeGroup; |
313 | } |
314 | } |
315 | |
316 | const char* ARMv7D16BitOpcode::doDisassemble() |
317 | { |
318 | OpcodeGroup* opGroup = opcodeTable[opcodeGroupNumber(m_opcode)]; |
319 | |
320 | while (opGroup) { |
321 | if (opGroup->matches(static_cast<uint16_t>(m_opcode))) |
322 | return opGroup->format(this); |
323 | opGroup = opGroup->next(); |
324 | } |
325 | |
326 | return defaultFormat(); |
327 | } |
328 | |
329 | const char* ARMv7D16BitOpcode::defaultFormat() |
330 | { |
331 | bufferPrintf(" .word %04x" , m_opcode); |
332 | return m_formatBuffer; |
333 | } |
334 | |
335 | const char* ARMv7DOpcodeAddRegisterT2::format() |
336 | { |
337 | appendInstructionName("add" ); |
338 | appendRegisterName(rdn()); |
339 | appendSeparator(); |
340 | appendRegisterName(rm()); |
341 | |
342 | return m_formatBuffer; |
343 | } |
344 | |
345 | const char* ARMv7DOpcodeAddSPPlusImmediate::format() |
346 | { |
347 | appendInstructionName("add" ); |
348 | appendRegisterName(rd()); |
349 | appendSeparator(); |
350 | appendRegisterName(RegSP); |
351 | appendSeparator(); |
352 | appendUnsignedImmediate(immediate8()); |
353 | |
354 | return m_formatBuffer; |
355 | } |
356 | |
357 | const char* const ARMv7DOpcodeAddSubtract::s_opNames[2] = { "add" , "sub" }; |
358 | |
359 | const char* ARMv7DOpcodeAddSubtractT1::format() |
360 | { |
361 | appendInstructionName(opName(), !inITBlock()); |
362 | appendRegisterName(rd()); |
363 | appendSeparator(); |
364 | appendRegisterName(rn()); |
365 | appendSeparator(); |
366 | appendRegisterName(rm()); |
367 | |
368 | return m_formatBuffer; |
369 | } |
370 | |
371 | const char* ARMv7DOpcodeAddSubtractImmediate3::format() |
372 | { |
373 | appendInstructionName(opName(), !inITBlock()); |
374 | appendRegisterName(rd()); |
375 | appendSeparator(); |
376 | appendRegisterName(rn()); |
377 | appendSeparator(); |
378 | appendUnsignedImmediate(immediate3()); |
379 | |
380 | return m_formatBuffer; |
381 | } |
382 | |
383 | const char* ARMv7DOpcodeAddSubtractImmediate8::format() |
384 | { |
385 | appendInstructionName(opName(), !inITBlock()); |
386 | appendRegisterName(rdn()); |
387 | appendSeparator(); |
388 | appendUnsignedImmediate(immediate8()); |
389 | |
390 | return m_formatBuffer; |
391 | } |
392 | |
393 | const char* ARMv7DOpcodeBranchConditionalT1::format() |
394 | { |
395 | if (condition() == 0xe) |
396 | return defaultFormat(); |
397 | |
398 | if (condition() == 0xf) { |
399 | appendInstructionName("svc" ); |
400 | appendUnsignedImmediate(offset()); |
401 | |
402 | return m_formatBuffer; |
403 | } |
404 | |
405 | bufferPrintf(" b%-6.6s" , conditionName(condition())); |
406 | appendPCRelativeOffset(static_cast<int32_t>(offset()) + 2); |
407 | |
408 | return m_formatBuffer; |
409 | } |
410 | |
411 | const char* ARMv7DOpcodeBranchExchangeT1::format() |
412 | { |
413 | appendInstructionName(opName()); |
414 | appendRegisterName(rm()); |
415 | |
416 | return m_formatBuffer; |
417 | } |
418 | |
419 | const char* ARMv7DOpcodeBranchT2::format() |
420 | { |
421 | appendInstructionName("b" ); |
422 | appendPCRelativeOffset(static_cast<int32_t>(immediate11()) + 2); |
423 | |
424 | return m_formatBuffer; |
425 | } |
426 | |
427 | const char* ARMv7DOpcodeCompareImmediateT1::format() |
428 | { |
429 | appendInstructionName("cmp" ); |
430 | appendRegisterName(rn()); |
431 | appendSeparator(); |
432 | appendUnsignedImmediate(immediate8()); |
433 | |
434 | return m_formatBuffer; |
435 | } |
436 | |
437 | const char* ARMv7DOpcodeCompareRegisterT1::format() |
438 | { |
439 | appendInstructionName("cmp" ); |
440 | appendRegisterName(rn()); |
441 | appendSeparator(); |
442 | appendRegisterName(rm()); |
443 | |
444 | return m_formatBuffer; |
445 | } |
446 | |
447 | const char* ARMv7DOpcodeCompareRegisterT2::format() |
448 | { |
449 | appendInstructionName("compare" ); |
450 | appendRegisterName(rn()); |
451 | appendSeparator(); |
452 | appendRegisterName(rm()); |
453 | |
454 | return m_formatBuffer; |
455 | } |
456 | |
457 | const char* const ARMv7DOpcodeDataProcessingRegisterT1::s_opNames[16] = { |
458 | "and" , "eor" , "lsl" , "lsr" , "asr" , "adc" , "sbc" , "ror" , "tst" , "rsb" , "cmp" , "cmn" , "orr" , "mul" , "bic" , "mvn" |
459 | }; |
460 | |
461 | const char* ARMv7DOpcodeDataProcessingRegisterT1::format() |
462 | { |
463 | appendInstructionName(opName(), inITBlock() && (!(op() == 0x8) || (op() == 0xa) || (op() == 0xb))); |
464 | appendRegisterName(rdn()); |
465 | appendSeparator(); |
466 | appendRegisterName(rm()); |
467 | if (op() == 0x9) // rsb T1 |
468 | appendString(", #0" ); |
469 | else if (op() == 0xd) { // mul T1 |
470 | appendSeparator(); |
471 | appendRegisterName(rdn()); |
472 | } |
473 | |
474 | return m_formatBuffer; |
475 | } |
476 | |
477 | const char* ARMv7DOpcodeGeneratePCRelativeAddress::format() |
478 | { |
479 | appendInstructionName("adr" ); |
480 | appendRegisterName(rd()); |
481 | appendSeparator(); |
482 | appendPCRelativeOffset(static_cast<int32_t>(immediate8())); |
483 | |
484 | return m_formatBuffer; |
485 | } |
486 | |
487 | const char* ARMv7DOpcodeLoadFromLiteralPool::format() |
488 | { |
489 | appendInstructionName("ldr" ); |
490 | appendRegisterName(rt()); |
491 | appendSeparator(); |
492 | appendPCRelativeOffset(static_cast<int32_t>(immediate8())); |
493 | |
494 | return m_formatBuffer; |
495 | } |
496 | |
497 | const char* const ARMv7DOpcodeLoadStoreRegisterImmediate::s_opNames[6] = { |
498 | "str" , "ldr" , "strb" , "ldrb" , "strh" , "ldrh" |
499 | }; |
500 | |
501 | const char* ARMv7DOpcodeLoadStoreRegisterImmediate::format() |
502 | { |
503 | const char* instructionName = opName(); |
504 | |
505 | if (!instructionName) |
506 | return defaultFormat(); |
507 | |
508 | appendInstructionName(opName()); |
509 | appendRegisterName(rt()); |
510 | appendSeparator(); |
511 | appendCharacter('['); |
512 | appendRegisterName(rn()); |
513 | if (immediate5()) { |
514 | appendSeparator(); |
515 | appendUnsignedImmediate(immediate5() << scale()); |
516 | } |
517 | appendCharacter(']'); |
518 | |
519 | return m_formatBuffer; |
520 | } |
521 | |
522 | const char* const ARMv7DOpcodeLoadStoreRegisterOffsetT1::s_opNames[8] = { |
523 | "str" , "strh" , "strb" , "ldrsb" , "ldr" , "ldrh" , "ldrb" , "ldrsh" |
524 | }; |
525 | |
526 | const char* ARMv7DOpcodeLoadStoreRegisterOffsetT1::format() |
527 | { |
528 | appendInstructionName(opName()); |
529 | appendRegisterName(rt()); |
530 | appendSeparator(); |
531 | appendCharacter('['); |
532 | appendRegisterName(rn()); |
533 | appendSeparator(); |
534 | appendRegisterName(rm()); |
535 | appendCharacter(']'); |
536 | |
537 | return m_formatBuffer; |
538 | } |
539 | |
540 | const char* ARMv7DOpcodeLoadStoreRegisterSPRelative::format() |
541 | { |
542 | appendInstructionName(opName()); |
543 | appendRegisterName(rt()); |
544 | appendSeparator(); |
545 | appendCharacter('['); |
546 | appendRegisterName(RegSP); |
547 | if (immediate8()) { |
548 | appendSeparator(); |
549 | appendUnsignedImmediate(immediate8() << 2); |
550 | } |
551 | appendCharacter(']'); |
552 | |
553 | return m_formatBuffer; |
554 | } |
555 | |
556 | const char* ARMv7DOpcodeLogicalImmediateT1::format() |
557 | { |
558 | if (!op() && !immediate5()) { |
559 | // mov T2 |
560 | appendInstructionName("movs" ); |
561 | appendRegisterName(rd()); |
562 | appendSeparator(); |
563 | appendRegisterName(rm()); |
564 | |
565 | return m_formatBuffer; |
566 | } |
567 | |
568 | appendInstructionName(opName(), !inITBlock()); |
569 | appendRegisterName(rd()); |
570 | appendSeparator(); |
571 | appendRegisterName(rm()); |
572 | appendSeparator(); |
573 | appendUnsignedImmediate((op() && !immediate5()) ? 32 : immediate5()); |
574 | |
575 | return m_formatBuffer; |
576 | } |
577 | |
578 | const char* ARMv7DOpcodeMiscAddSubSP::format() |
579 | { |
580 | appendInstructionName(opName()); |
581 | appendRegisterName(RegSP); |
582 | appendSeparator(); |
583 | appendRegisterName(RegSP); |
584 | appendSeparator(); |
585 | appendUnsignedImmediate(immediate7() << 2); |
586 | |
587 | return m_formatBuffer; |
588 | } |
589 | |
590 | const char* ARMv7DOpcodeMiscBreakpointT1::format() |
591 | { |
592 | appendInstructionNameNoITBlock("bkpt" ); |
593 | appendUnsignedImmediate(immediate8()); |
594 | |
595 | return m_formatBuffer; |
596 | } |
597 | |
598 | const char* const ARMv7DOpcodeMiscByteHalfwordOps::s_opNames[8] = { |
599 | "sxth" , "sxb" , "uxth" , "uxtb" , "rev" , "rev16" , "revsh" |
600 | }; |
601 | |
602 | const char* ARMv7DOpcodeMiscByteHalfwordOps::format() |
603 | { |
604 | const char* instructionName = opName(); |
605 | |
606 | if (!instructionName) |
607 | return defaultFormat(); |
608 | |
609 | appendInstructionName(instructionName); |
610 | appendRegisterName(rd()); |
611 | appendSeparator(); |
612 | appendRegisterName(rm()); |
613 | |
614 | return m_formatBuffer; |
615 | } |
616 | |
617 | const char* ARMv7DOpcodeMiscCompareAndBranch::format() |
618 | { |
619 | appendInstructionName(opName()); |
620 | appendPCRelativeOffset(immediate6() + 2); |
621 | |
622 | return m_formatBuffer; |
623 | } |
624 | |
625 | const char* const ARMv7DOpcodeMiscHint16::s_opNames[16] = { |
626 | "nop" , "yield" , "wfe" , "wfi" , "sev" |
627 | }; |
628 | |
629 | const char* ARMv7DOpcodeMiscHint16::format() |
630 | { |
631 | if (opA() > 4) |
632 | return defaultFormat(); |
633 | |
634 | appendInstructionName(opName()); |
635 | |
636 | return m_formatBuffer; |
637 | } |
638 | |
639 | const char* ARMv7DOpcodeMiscIfThenT1::format() |
640 | { |
641 | char opName[6]; |
642 | opName[0] = 'i'; |
643 | opName[1] = 't'; |
644 | |
645 | unsigned condition = firstCondition(); |
646 | unsigned maskBits = mask(); |
647 | unsigned blockLength = 0; |
648 | |
649 | for (unsigned i = 0; i < 4; ++i) { |
650 | if (maskBits & (1 << i)) { |
651 | blockLength = 4 - i; |
652 | break; |
653 | } |
654 | } |
655 | |
656 | startITBlock(blockLength, condition); |
657 | |
658 | for (unsigned i = 1; i < blockLength; ++i) { |
659 | unsigned currMaskBit = (maskBits >> (4-i)) & 0x1; |
660 | opName[i + 1] = (currMaskBit ^ (condition & 1)) ? 'e' : 't'; |
661 | saveITConditionAt(i, (condition & ~1) | currMaskBit); |
662 | } |
663 | opName[blockLength + 1] = '\0'; |
664 | |
665 | appendInstructionNameNoITBlock(opName); |
666 | appendString(conditionName(condition)); |
667 | |
668 | return m_formatBuffer; |
669 | } |
670 | |
671 | const char* ARMv7DOpcodeMiscPushPop::format() |
672 | { |
673 | appendInstructionName(opName()); |
674 | appendRegisterList(registerMask()); |
675 | |
676 | return m_formatBuffer; |
677 | } |
678 | |
679 | const char* ARMv7DOpcodeMoveImmediateT1::format() |
680 | { |
681 | appendInstructionName("mov" , !inITBlock()); |
682 | appendRegisterName(rd()); |
683 | appendSeparator(); |
684 | appendUnsignedImmediate(immediate8()); |
685 | |
686 | return m_formatBuffer; |
687 | } |
688 | |
689 | const char* ARMv7DOpcodeMoveRegisterT1::format() |
690 | { |
691 | appendInstructionName("mov" ); |
692 | appendRegisterName(rd()); |
693 | appendSeparator(); |
694 | appendRegisterName(rm()); |
695 | |
696 | return m_formatBuffer; |
697 | } |
698 | |
699 | // 32 bit Intructions |
700 | |
701 | void ARMv7D32BitOpcode::init() |
702 | { |
703 | OpcodeGroup* lastGroups[OpcodeGroup::opcodeTableSize]; |
704 | |
705 | for (unsigned i = 0; i < OpcodeGroup::opcodeTableSize; i++) { |
706 | opcodeTable[i] = 0; |
707 | lastGroups[i] = 0; |
708 | } |
709 | |
710 | for (unsigned i = 0; i < sizeof(opcode32BitGroupList) / sizeof(Opcode32GroupInitializer); i++) { |
711 | OpcodeGroup* newOpcodeGroup = new OpcodeGroup(opcode32BitGroupList[i].m_mask, opcode32BitGroupList[i].m_pattern, opcode32BitGroupList[i].m_format); |
712 | uint16_t opcodeGroupNumber = opcode32BitGroupList[i].m_opcodeGroupNumber; |
713 | |
714 | if (!opcodeTable[opcodeGroupNumber]) |
715 | opcodeTable[opcodeGroupNumber] = newOpcodeGroup; |
716 | else |
717 | lastGroups[opcodeGroupNumber]->setNext(newOpcodeGroup); |
718 | lastGroups[opcodeGroupNumber] = newOpcodeGroup; |
719 | } |
720 | } |
721 | |
722 | const char* ARMv7D32BitOpcode::doDisassemble() |
723 | { |
724 | OpcodeGroup* opGroup = opcodeTable[opcodeGroupNumber(m_opcode)]; |
725 | |
726 | while (opGroup) { |
727 | if (opGroup->matches(m_opcode)) |
728 | return opGroup->format(this); |
729 | opGroup = opGroup->next(); |
730 | } |
731 | |
732 | return defaultFormat(); |
733 | } |
734 | |
735 | const char* ARMv7D32BitOpcode::defaultFormat() |
736 | { |
737 | bufferPrintf(" .long %08x" , m_opcode); |
738 | return m_formatBuffer; |
739 | } |
740 | |
741 | const char* ARMv7DOpcodeConditionalBranchT3::format() |
742 | { |
743 | if (condition() < 0xe) |
744 | bufferPrintf(" b%-6.6s" , conditionName(condition())); |
745 | else |
746 | appendInstructionName("b" ); |
747 | appendPCRelativeOffset(offset() + 2); |
748 | |
749 | return m_formatBuffer; |
750 | } |
751 | |
752 | const char* ARMv7DOpcodeBranchOrBranchLink::format() |
753 | { |
754 | appendInstructionName(isBL() ? "bl" : "b" ); |
755 | appendPCRelativeOffset(offset() + 2); |
756 | |
757 | return m_formatBuffer; |
758 | } |
759 | |
760 | const char* const ARMv7DOpcodeDataProcessingLogicalAndRithmetic::s_opNames[16] = { |
761 | "and" , "bic" , "orr" , "orn" , "eor" , 0, "pkh" , 0, "add" , 0, "adc" , "sbc" , 0, "sub" , "rsb" , 0 |
762 | }; |
763 | |
764 | void ARMv7DOpcodeDataProcessingModifiedImmediate::appendModifiedImmediate(unsigned immediate12) |
765 | { |
766 | if (!(immediate12 & 0xc00)) { |
767 | unsigned immediate = 0; |
768 | unsigned lower8Bits = immediate12 & 0xff; |
769 | |
770 | switch ((immediate12 >> 8) & 3) { |
771 | case 0: |
772 | immediate = lower8Bits; |
773 | break; |
774 | case 1: |
775 | immediate = (lower8Bits << 16) | lower8Bits; |
776 | break; |
777 | case 2: |
778 | immediate = (lower8Bits << 24) | (lower8Bits << 8); |
779 | break; |
780 | case 3: |
781 | immediate = (lower8Bits << 24) | (lower8Bits << 16) | (lower8Bits << 8) | lower8Bits; |
782 | break; |
783 | } |
784 | appendUnsignedImmediate(immediate); |
785 | return; |
786 | } |
787 | |
788 | unsigned immediate8 = 0x80 | (immediate12 & 0x7f); |
789 | unsigned shiftAmount = 32 - ((immediate12 >> 7) & 0x1f); |
790 | |
791 | appendUnsignedImmediate(immediate8 << shiftAmount); |
792 | } |
793 | |
794 | const char* ARMv7DOpcodeDataProcessingModifiedImmediate::format() |
795 | { |
796 | if ((op() == 0x5) || (op() == 0x6) || (op() == 0x7) || (op() == 0x9) || (op() == 0xc) || (op() == 0xf)) |
797 | return defaultFormat(); |
798 | |
799 | const char* instructionName = opName(); |
800 | |
801 | if (rn() == 15) { |
802 | if (op() == 2) { |
803 | // MOV T2 |
804 | instructionName = sBit() ? "movs" : "mov" ; |
805 | appendInstructionName(instructionName); |
806 | appendRegisterName(rd()); |
807 | appendSeparator(); |
808 | appendModifiedImmediate(immediate12()); |
809 | |
810 | return m_formatBuffer; |
811 | } |
812 | |
813 | if (op() == 3) { |
814 | // MVN T1 |
815 | instructionName = sBit() ? "mvns" : "mvn" ; |
816 | appendInstructionName(instructionName); |
817 | appendRegisterName(rd()); |
818 | appendSeparator(); |
819 | appendModifiedImmediate(immediate12()); |
820 | |
821 | return m_formatBuffer; |
822 | } |
823 | } |
824 | |
825 | if (rd() == 15) { |
826 | if (sBit()) { |
827 | bool testOrCmpInstruction = false; |
828 | |
829 | switch (op()) { |
830 | case 0x0: |
831 | instructionName = "tst" ; |
832 | testOrCmpInstruction = true; |
833 | break; |
834 | case 0x4: |
835 | instructionName = "teq" ; |
836 | testOrCmpInstruction = true; |
837 | break; |
838 | case 0x8: |
839 | instructionName = "cmn" ; |
840 | testOrCmpInstruction = true; |
841 | break; |
842 | case 0xd: |
843 | instructionName = "cmp" ; |
844 | testOrCmpInstruction = true; |
845 | break; |
846 | } |
847 | |
848 | if (testOrCmpInstruction) { |
849 | appendInstructionName(instructionName); |
850 | appendRegisterName(rn()); |
851 | appendSeparator(); |
852 | appendModifiedImmediate(immediate12()); |
853 | |
854 | return m_formatBuffer; |
855 | } |
856 | } |
857 | } |
858 | |
859 | appendInstructionName(instructionName); |
860 | appendRegisterName(rd()); |
861 | appendSeparator(); |
862 | appendRegisterName(rn()); |
863 | appendSeparator(); |
864 | appendModifiedImmediate(immediate12()); |
865 | |
866 | return m_formatBuffer; |
867 | } |
868 | |
869 | void ARMv7DOpcodeDataProcessingShiftedReg::appendImmShift(unsigned type, unsigned immediate) |
870 | { |
871 | if (type || immediate) { |
872 | appendSeparator(); |
873 | |
874 | if (!immediate) { |
875 | switch (type) { |
876 | case 1: |
877 | case 2: |
878 | immediate = 32; |
879 | break; |
880 | case 3: |
881 | appendString("rrx" ); |
882 | return; |
883 | } |
884 | } |
885 | |
886 | appendShiftType(type); |
887 | appendUnsignedImmediate(immediate); |
888 | } |
889 | } |
890 | |
891 | const char* ARMv7DOpcodeDataProcessingShiftedReg::format() |
892 | { |
893 | if ((op() == 0x5) || (op() == 0x7) || (op() == 0x9) || (op() == 0xc) || (op() == 0xf)) |
894 | return defaultFormat(); |
895 | |
896 | if (op() == 6) { |
897 | // pkhbt or pkhtb |
898 | if (sBit() || tBit()) |
899 | return defaultFormat(); |
900 | |
901 | if (tbBit()) |
902 | appendInstructionName("pkhtb" ); |
903 | else |
904 | appendInstructionName("pkhbt" ); |
905 | appendRegisterName(rd()); |
906 | appendSeparator(); |
907 | appendRegisterName(rn()); |
908 | appendSeparator(); |
909 | appendRegisterName(rm()); |
910 | appendImmShift(tbBit() << 1, immediate5()); |
911 | |
912 | return m_formatBuffer; |
913 | } |
914 | |
915 | const char* instructionName = opName(); |
916 | |
917 | if (rn() == 15) { |
918 | if (op() == 2) { |
919 | if (!type() && !immediate5()) { |
920 | // MOV T3 |
921 | instructionName = sBit() ? "movs" : "mov" ; |
922 | appendInstructionName(instructionName); |
923 | appendRegisterName(rd()); |
924 | appendSeparator(); |
925 | appendRegisterName(rm()); |
926 | |
927 | return m_formatBuffer; |
928 | } |
929 | |
930 | if (type() == 3 && !immediate5()) { |
931 | // RRX T1 |
932 | instructionName = sBit() ? "rrx" : "rrx" ; |
933 | appendInstructionName(instructionName); |
934 | appendRegisterName(rd()); |
935 | appendSeparator(); |
936 | appendRegisterName(rm()); |
937 | |
938 | return m_formatBuffer; |
939 | } |
940 | |
941 | // Logical |
942 | if (sBit()) |
943 | bufferPrintf("%ss " , shiftName(type())); |
944 | else |
945 | appendInstructionName(shiftName(type())); |
946 | appendRegisterName(rd()); |
947 | appendSeparator(); |
948 | appendRegisterName(rm()); |
949 | appendSeparator(); |
950 | appendImmShift(type(), immediate5()); |
951 | |
952 | return m_formatBuffer; |
953 | } |
954 | |
955 | if (op() == 3) { |
956 | // MVN T2 |
957 | instructionName = sBit() ? "mvns" : "mvn" ; |
958 | appendInstructionName(instructionName); |
959 | appendRegisterName(rd()); |
960 | appendSeparator(); |
961 | appendRegisterName(rm()); |
962 | appendImmShift(type(), immediate5()); |
963 | |
964 | return m_formatBuffer; |
965 | } |
966 | } |
967 | |
968 | if (rd() == 15) { |
969 | if (sBit()) { |
970 | bool testOrCmpInstruction = false; |
971 | |
972 | switch (op()) { |
973 | case 0x0: |
974 | instructionName = "tst" ; |
975 | testOrCmpInstruction = true; |
976 | break; |
977 | case 0x4: |
978 | instructionName = "teq" ; |
979 | testOrCmpInstruction = true; |
980 | break; |
981 | case 0x8: |
982 | instructionName = "cmn" ; |
983 | testOrCmpInstruction = true; |
984 | break; |
985 | case 0xd: |
986 | instructionName = "cmp" ; |
987 | testOrCmpInstruction = true; |
988 | break; |
989 | } |
990 | |
991 | if (testOrCmpInstruction) { |
992 | appendInstructionName(instructionName); |
993 | appendRegisterName(rn()); |
994 | appendSeparator(); |
995 | appendRegisterName(rm()); |
996 | appendImmShift(type(), immediate5()); |
997 | |
998 | return m_formatBuffer; |
999 | } |
1000 | } |
1001 | } |
1002 | |
1003 | appendInstructionName(instructionName); |
1004 | appendRegisterName(rd()); |
1005 | appendSeparator(); |
1006 | appendRegisterName(rn()); |
1007 | appendSeparator(); |
1008 | appendRegisterName(rm()); |
1009 | appendImmShift(type(), immediate5()); |
1010 | |
1011 | return m_formatBuffer; |
1012 | } |
1013 | |
1014 | const char* ARMv7DOpcodeFPTransfer::format() |
1015 | { |
1016 | appendInstructionName("vmov" ); |
1017 | |
1018 | if (opL()) { |
1019 | appendFPRegister(); |
1020 | appendSeparator(); |
1021 | } |
1022 | |
1023 | appendRegisterName(rt()); |
1024 | |
1025 | if (!opL()) { |
1026 | appendSeparator(); |
1027 | appendFPRegister(); |
1028 | } |
1029 | |
1030 | return m_formatBuffer; |
1031 | } |
1032 | |
1033 | void ARMv7DOpcodeFPTransfer::appendFPRegister() |
1034 | { |
1035 | if (opC()) { |
1036 | appendFPRegisterName('d', vd()); |
1037 | bufferPrintf("[%u]" , opH()); |
1038 | } else |
1039 | appendFPRegisterName('s', vn()); |
1040 | } |
1041 | |
1042 | const char* ARMv7DOpcodeDataProcessingRegShift::format() |
1043 | { |
1044 | appendInstructionName(opName()); |
1045 | appendRegisterName(rd()); |
1046 | appendSeparator(); |
1047 | appendRegisterName(rn()); |
1048 | appendSeparator(); |
1049 | appendRegisterName(rm()); |
1050 | |
1051 | return m_formatBuffer; |
1052 | } |
1053 | |
1054 | const char* const ARMv7DOpcodeDataProcessingRegExtend::s_opExtendNames[8] = { |
1055 | "sxth" , "uxth" , "sxtb16" , "uxtb16" , "sxtb" , "uxtb" |
1056 | }; |
1057 | |
1058 | const char* const ARMv7DOpcodeDataProcessingRegExtend::s_opExtendAndAddNames[8] = { |
1059 | "sxtah" , "uxtah" , "sxtab16" , "uxtab16" , "sxtab" , "uxtab" |
1060 | }; |
1061 | |
1062 | const char* ARMv7DOpcodeDataProcessingRegExtend::format() |
1063 | { |
1064 | const char* instructionName; |
1065 | |
1066 | if (rn() == 0xf) |
1067 | instructionName = opExtendName(); |
1068 | else |
1069 | instructionName = opExtendAndAddName(); |
1070 | |
1071 | if (!instructionName) |
1072 | return defaultFormat(); |
1073 | |
1074 | appendInstructionName(instructionName); |
1075 | appendRegisterName(rd()); |
1076 | appendSeparator(); |
1077 | appendRegisterName(rn()); |
1078 | appendSeparator(); |
1079 | appendRegisterName(rm()); |
1080 | |
1081 | if (rotate()) { |
1082 | appendSeparator(); |
1083 | appendString("ror " ); |
1084 | appendUnsignedImmediate(rotate() * 8); |
1085 | } |
1086 | |
1087 | return m_formatBuffer; |
1088 | } |
1089 | |
1090 | const char* const ARMv7DOpcodeDataProcessingRegParallel::s_opNames[16] = { |
1091 | "sadd8" , "sadd16" , "sasx" , 0, "ssub8" , "ssub16" , "ssax" , 0, |
1092 | "qadd8" , "qadd16" , "qasx" , 0, "qsub8" , "qsub16" , "qsax" , 0 |
1093 | }; |
1094 | |
1095 | const char* ARMv7DOpcodeDataProcessingRegParallel::format() |
1096 | { |
1097 | const char* instructionName; |
1098 | |
1099 | instructionName = opName(); |
1100 | |
1101 | if (!instructionName) |
1102 | return defaultFormat(); |
1103 | |
1104 | appendInstructionName(instructionName); |
1105 | appendRegisterName(rd()); |
1106 | appendSeparator(); |
1107 | appendRegisterName(rn()); |
1108 | appendSeparator(); |
1109 | appendRegisterName(rm()); |
1110 | |
1111 | return m_formatBuffer; |
1112 | } |
1113 | |
1114 | const char* const ARMv7DOpcodeDataProcessingRegMisc::s_opNames[16] = { |
1115 | "qadd" , "qdadd" , "qsub" , "qdsub" , "rev" , "rev16" , "rbit" , "revsh" , |
1116 | "sel" , 0, 0, 0, "clz" |
1117 | }; |
1118 | |
1119 | const char* ARMv7DOpcodeDataProcessingRegMisc::format() |
1120 | { |
1121 | const char* instructionName; |
1122 | |
1123 | instructionName = opName(); |
1124 | |
1125 | if (!instructionName) |
1126 | return defaultFormat(); |
1127 | |
1128 | if ((op1() & 0x1) && (rn() != rm())) |
1129 | return defaultFormat(); |
1130 | |
1131 | appendInstructionName(instructionName); |
1132 | appendRegisterName(rd()); |
1133 | appendSeparator(); |
1134 | |
1135 | if (op1() == 0x2) { // sel |
1136 | appendRegisterName(rn()); |
1137 | appendSeparator(); |
1138 | appendRegisterName(rm()); |
1139 | |
1140 | return m_formatBuffer; |
1141 | } |
1142 | |
1143 | appendRegisterName(rm()); |
1144 | |
1145 | if (!(op1() & 0x1)) { |
1146 | appendSeparator(); |
1147 | appendRegisterName(rn()); |
1148 | } |
1149 | |
1150 | return m_formatBuffer; |
1151 | } |
1152 | |
1153 | const char* const ARMv7DOpcodeHint32::s_opNames[8] = { |
1154 | "nop" , "yield" , "wfe" , "wfi" , "sev" |
1155 | }; |
1156 | |
1157 | const char* ARMv7DOpcodeHint32::format() |
1158 | { |
1159 | if (isDebugHint()) { |
1160 | appendInstructionName("debug" ); |
1161 | appendUnsignedImmediate(debugOption()); |
1162 | |
1163 | return m_formatBuffer; |
1164 | } |
1165 | |
1166 | if (op() > 0x4) |
1167 | return defaultFormat(); |
1168 | |
1169 | appendInstructionName(opName()); |
1170 | |
1171 | return m_formatBuffer; |
1172 | } |
1173 | |
1174 | const char* const ARMv7DOpcodeDataLoad::s_opNames[8] = { |
1175 | "ldrb" , "ldrh" , "ldr" , 0, "ldrsb" , "ldrsh" |
1176 | }; |
1177 | |
1178 | const char* ARMv7DOpcodeLoadRegister::format() |
1179 | { |
1180 | appendInstructionName(opName()); |
1181 | appendRegisterName(rt()); |
1182 | appendSeparator(); |
1183 | appendCharacter('['); |
1184 | appendRegisterName(rn()); |
1185 | appendSeparator(); |
1186 | appendRegisterName(rm()); |
1187 | if (immediate2()) { |
1188 | appendSeparator(); |
1189 | appendUnsignedImmediate(immediate2()); |
1190 | } |
1191 | appendCharacter(']'); |
1192 | |
1193 | return m_formatBuffer; |
1194 | } |
1195 | |
1196 | const char* ARMv7DOpcodeLoadSignedImmediate::format() |
1197 | { |
1198 | appendInstructionName(opName()); |
1199 | appendRegisterName(rt()); |
1200 | appendSeparator(); |
1201 | appendCharacter('['); |
1202 | appendRegisterName(rn()); |
1203 | if (pBit()) { |
1204 | if (wBit() || immediate8()) { |
1205 | appendSeparator(); |
1206 | if (uBit()) |
1207 | appendUnsignedImmediate(immediate8()); |
1208 | else |
1209 | appendSignedImmediate(0 - static_cast<int>(immediate8())); |
1210 | } |
1211 | appendCharacter(']'); |
1212 | if (wBit()) |
1213 | appendCharacter('!'); |
1214 | } else { |
1215 | appendCharacter(']'); |
1216 | appendSeparator(); |
1217 | if (uBit()) |
1218 | appendUnsignedImmediate(immediate8()); |
1219 | else |
1220 | appendSignedImmediate(0 - static_cast<int>(immediate8())); |
1221 | } |
1222 | |
1223 | return m_formatBuffer; |
1224 | } |
1225 | |
1226 | const char* ARMv7DOpcodeLoadUnsignedImmediate::format() |
1227 | { |
1228 | appendInstructionName(opName()); |
1229 | appendRegisterName(rt()); |
1230 | appendSeparator(); |
1231 | appendCharacter('['); |
1232 | appendRegisterName(rn()); |
1233 | if (immediate12()) { |
1234 | appendSeparator(); |
1235 | appendUnsignedImmediate(immediate12()); |
1236 | } |
1237 | appendCharacter(']'); |
1238 | |
1239 | return m_formatBuffer; |
1240 | } |
1241 | |
1242 | const char* const ARMv7DOpcodeLongMultipleDivide::s_opNames[8] = { |
1243 | "smull" , "sdiv" , "umull" , "udiv" , "smlal" , "smlsld" , "umlal" , 0 |
1244 | }; |
1245 | |
1246 | const char* const ARMv7DOpcodeLongMultipleDivide::s_smlalOpNames[4] = { |
1247 | "smlalbb" , "smlalbt" , "smlaltb" , "smlaltt" |
1248 | }; |
1249 | |
1250 | const char* const ARMv7DOpcodeLongMultipleDivide::s_smlaldOpNames[2] = { |
1251 | "smlald" , "smlaldx" |
1252 | }; |
1253 | |
1254 | const char* const ARMv7DOpcodeLongMultipleDivide::s_smlsldOpNames[2] = { |
1255 | "smlsld" , "smlsldx" |
1256 | }; |
1257 | |
1258 | const char* ARMv7DOpcodeLongMultipleDivide::format() |
1259 | { |
1260 | const char* instructionName = opName(); |
1261 | |
1262 | switch (op1()) { |
1263 | case 0x0: |
1264 | case 0x2: |
1265 | if (op2()) |
1266 | return defaultFormat(); |
1267 | break; |
1268 | case 0x1: |
1269 | case 0x3: |
1270 | if (op2() != 0xf) |
1271 | return defaultFormat(); |
1272 | break; |
1273 | case 0x4: |
1274 | if ((op2() & 0xc) == 0x8) |
1275 | instructionName = smlalOpName(); |
1276 | else if ((op2() & 0xe) == 0xc) |
1277 | instructionName = smlaldOpName(); |
1278 | else if (op2()) |
1279 | return defaultFormat(); |
1280 | break; |
1281 | case 0x5: |
1282 | if ((op2() & 0xe) == 0xc) |
1283 | instructionName = smlaldOpName(); |
1284 | else |
1285 | return defaultFormat(); |
1286 | break; |
1287 | case 0x6: |
1288 | if (op2() == 0x5) |
1289 | instructionName = "umaal" ; |
1290 | else if (op2()) |
1291 | return defaultFormat(); |
1292 | break; |
1293 | case 0x7: |
1294 | return defaultFormat(); |
1295 | break; |
1296 | } |
1297 | |
1298 | appendInstructionName(instructionName); |
1299 | if ((op1() & 0x5) == 0x1) { // sdiv and udiv |
1300 | if (rt() != 0xf) |
1301 | return defaultFormat(); |
1302 | } else { |
1303 | appendRegisterName(rdLo()); |
1304 | appendSeparator(); |
1305 | } |
1306 | appendRegisterName(rdHi()); |
1307 | appendSeparator(); |
1308 | appendRegisterName(rn()); |
1309 | appendSeparator(); |
1310 | appendRegisterName(rm()); |
1311 | |
1312 | return m_formatBuffer; |
1313 | } |
1314 | |
1315 | const char* const ARMv7DOpcodeUnmodifiedImmediate::s_opNames[16] = { |
1316 | "addw" , 0, "movw" , 0, 0, "subw" , "movt" , 0, |
1317 | "ssat" , "ssat16" , "sbfx" , "bfi" , "usat" , "usat16" , "ubfx" , 0 |
1318 | }; |
1319 | |
1320 | const char* ARMv7DOpcodeUnmodifiedImmediate::format() |
1321 | { |
1322 | const char* instructionName = opName(); |
1323 | |
1324 | switch (op() >> 1) { |
1325 | case 0x0: |
1326 | case 0x5: |
1327 | if (rn() == 0xf) |
1328 | instructionName = "adr" ; |
1329 | break; |
1330 | case 0x9: |
1331 | if (immediate5()) |
1332 | instructionName = "ssat" ; |
1333 | break; |
1334 | case 0xb: |
1335 | if (rn() == 0xf) |
1336 | instructionName = "bfc" ; |
1337 | break; |
1338 | case 0xd: |
1339 | if (immediate5()) |
1340 | instructionName = "usat" ; |
1341 | break; |
1342 | } |
1343 | |
1344 | if (!instructionName) |
1345 | return defaultFormat(); |
1346 | |
1347 | appendInstructionName(instructionName); |
1348 | appendRegisterName(rd()); |
1349 | appendSeparator(); |
1350 | |
1351 | if ((op() & 0x17) == 0x4) { // movw or movt |
1352 | appendUnsignedImmediate(immediate16()); |
1353 | |
1354 | return m_formatBuffer; |
1355 | } |
1356 | |
1357 | if (!op() || (op() == 0xa)) { // addw, subw and adr |
1358 | if (rn() == 0xf) { |
1359 | int32_t offset; |
1360 | |
1361 | if ((op() == 0xa) && (rn() == 0xf)) |
1362 | offset = 0 - static_cast<int32_t>(immediate12()); |
1363 | else |
1364 | offset = static_cast<int32_t>(immediate12()); |
1365 | |
1366 | appendPCRelativeOffset(offset); |
1367 | |
1368 | return m_formatBuffer; |
1369 | } |
1370 | |
1371 | appendRegisterName(rn()); |
1372 | appendSeparator(); |
1373 | appendUnsignedImmediate(immediate12()); |
1374 | |
1375 | return m_formatBuffer; |
1376 | } |
1377 | |
1378 | if (((op() & 0x15) == 0x10) || (((op() & 0x17) == 0x12) && immediate5())) { // ssat, usat, ssat16 & usat16 |
1379 | appendSeparator(); |
1380 | appendUnsignedImmediate(bitNumOrSatImmediate() + 1); |
1381 | appendSeparator(); |
1382 | appendRegisterName(rn()); |
1383 | if (shBit() || immediate5()) { |
1384 | appendSeparator(); |
1385 | appendShiftType(shBit() << 1); |
1386 | appendUnsignedImmediate(immediate5()); |
1387 | } |
1388 | |
1389 | return m_formatBuffer; |
1390 | } |
1391 | |
1392 | if (op() == 0x16) { // bfi or bfc |
1393 | int width = static_cast<int>(bitNumOrSatImmediate()) - static_cast<int>(immediate5()) + 1; |
1394 | |
1395 | if (width < 0) |
1396 | return defaultFormat(); |
1397 | |
1398 | if (rn() != 0xf) { |
1399 | appendSeparator(); |
1400 | appendRegisterName(rn()); |
1401 | } |
1402 | appendSeparator(); |
1403 | appendUnsignedImmediate(immediate5()); |
1404 | appendSeparator(); |
1405 | appendSignedImmediate(width); |
1406 | |
1407 | return m_formatBuffer; |
1408 | } |
1409 | |
1410 | // Must be sbfx or ubfx |
1411 | appendSeparator(); |
1412 | appendRegisterName(rn()); |
1413 | appendSeparator(); |
1414 | appendUnsignedImmediate(immediate5()); |
1415 | appendSeparator(); |
1416 | appendUnsignedImmediate(bitNumOrSatImmediate() + 1); |
1417 | |
1418 | return m_formatBuffer; |
1419 | } |
1420 | |
1421 | const char* const ARMv7DOpcodeDataStoreSingle::s_opNames[4] = { |
1422 | "strb" , "strh" , "str" , 0 |
1423 | }; |
1424 | |
1425 | const char* ARMv7DOpcodeDataPushPopSingle::format() |
1426 | { |
1427 | appendInstructionName(opName()); |
1428 | appendRegisterName(rt()); |
1429 | |
1430 | return m_formatBuffer; |
1431 | } |
1432 | |
1433 | const char* ARMv7DOpcodeStoreSingleImmediate12::format() |
1434 | { |
1435 | appendInstructionName(opName()); |
1436 | appendRegisterName(rt()); |
1437 | appendSeparator(); |
1438 | appendCharacter('['); |
1439 | appendRegisterName(rn()); |
1440 | if (immediate12()) { |
1441 | appendSeparator(); |
1442 | appendUnsignedImmediate(immediate12()); |
1443 | } |
1444 | appendCharacter(']'); |
1445 | |
1446 | return m_formatBuffer; |
1447 | } |
1448 | |
1449 | const char* ARMv7DOpcodeStoreSingleImmediate8::format() |
1450 | { |
1451 | if (pBit() && uBit() && !wBit()) // Really undecoded strt |
1452 | return defaultFormat(); |
1453 | |
1454 | if ((rn() == 0xf) || (!pBit() && !wBit())) |
1455 | return defaultFormat(); |
1456 | |
1457 | appendInstructionName(opName()); |
1458 | appendRegisterName(rt()); |
1459 | appendSeparator(); |
1460 | appendCharacter('['); |
1461 | appendRegisterName(rn()); |
1462 | |
1463 | if (!pBit()) { |
1464 | appendCharacter(']'); |
1465 | appendSeparator(); |
1466 | appendSignedImmediate(uBit() ? static_cast<int32_t>(immediate8()) : (0 - static_cast<int32_t>(immediate8()))); |
1467 | |
1468 | return m_formatBuffer; |
1469 | } |
1470 | |
1471 | if (immediate8()) { |
1472 | appendSeparator(); |
1473 | appendSignedImmediate(uBit() ? static_cast<int32_t>(immediate8()) : (0 - static_cast<int32_t>(immediate8()))); |
1474 | } |
1475 | appendCharacter(']'); |
1476 | |
1477 | if (wBit()) |
1478 | appendCharacter('!'); |
1479 | |
1480 | return m_formatBuffer; |
1481 | } |
1482 | |
1483 | const char* ARMv7DOpcodeStoreSingleRegister::format() |
1484 | { |
1485 | appendInstructionName(opName()); |
1486 | appendRegisterName(rt()); |
1487 | appendSeparator(); |
1488 | appendCharacter('['); |
1489 | appendRegisterName(rn()); |
1490 | appendSeparator(); |
1491 | appendRegisterName(rm()); |
1492 | if (immediate2()) { |
1493 | appendSeparator(); |
1494 | appendString("lsl " ); |
1495 | appendUnsignedImmediate(immediate2()); |
1496 | } |
1497 | appendCharacter(']'); |
1498 | |
1499 | return m_formatBuffer; |
1500 | } |
1501 | |
1502 | const char* ARMv7DOpcodeVMOVDoublePrecision::format() |
1503 | { |
1504 | appendInstructionName("vmov" ); |
1505 | if (op()) { |
1506 | appendRegisterName(rt()); |
1507 | appendSeparator(); |
1508 | appendRegisterName(rt2()); |
1509 | appendSeparator(); |
1510 | } |
1511 | |
1512 | appendFPRegisterName('d', vm()); |
1513 | |
1514 | if (!op()) { |
1515 | appendSeparator(); |
1516 | appendRegisterName(rt()); |
1517 | appendSeparator(); |
1518 | appendRegisterName(rt2()); |
1519 | } |
1520 | |
1521 | return m_formatBuffer; |
1522 | } |
1523 | |
1524 | const char* ARMv7DOpcodeVMOVSinglePrecision::format() |
1525 | { |
1526 | appendInstructionName("vmov" ); |
1527 | if (op()) { |
1528 | appendRegisterName(rt()); |
1529 | appendSeparator(); |
1530 | appendRegisterName(rt2()); |
1531 | appendSeparator(); |
1532 | } |
1533 | |
1534 | appendFPRegisterName('s', vm()); |
1535 | appendSeparator(); |
1536 | appendFPRegisterName('s', (vm() + 1) % 32); |
1537 | |
1538 | if (!op()) { |
1539 | appendSeparator(); |
1540 | appendRegisterName(rt()); |
1541 | appendSeparator(); |
1542 | appendRegisterName(rt2()); |
1543 | } |
1544 | |
1545 | return m_formatBuffer; |
1546 | } |
1547 | |
1548 | const char* ARMv7DOpcodeVMSR::format() |
1549 | { |
1550 | appendInstructionName("vmrs" ); |
1551 | if (opL()) { |
1552 | if (rt() == 0xf) |
1553 | appendString("apsr_nzcv" ); |
1554 | else |
1555 | appendRegisterName(rt()); |
1556 | appendSeparator(); |
1557 | } |
1558 | |
1559 | appendString("fpscr" ); |
1560 | |
1561 | if (!opL()) { |
1562 | appendSeparator(); |
1563 | appendRegisterName(rt()); |
1564 | } |
1565 | |
1566 | return m_formatBuffer; |
1567 | } |
1568 | |
1569 | const char* ARMv7DOpcodeVADDVSUB::format() |
1570 | { |
1571 | char regPrefix = sz() ? 'd' : 's'; |
1572 | if (isSub()) |
1573 | appendInstructionName("vsub" ); |
1574 | else |
1575 | appendInstructionName("vadd" ); |
1576 | appendFPRegisterName(regPrefix, vd()); |
1577 | appendSeparator(); |
1578 | appendFPRegisterName(regPrefix, vn()); |
1579 | appendSeparator(); |
1580 | appendFPRegisterName(regPrefix, vm()); |
1581 | |
1582 | return m_formatBuffer; |
1583 | } |
1584 | |
1585 | const char* ARMv7DOpcodeVMUL::format() |
1586 | { |
1587 | char regPrefix = sz() ? 'd' : 's'; |
1588 | appendInstructionName("vmul" ); |
1589 | appendFPRegisterName(regPrefix, vd()); |
1590 | appendSeparator(); |
1591 | appendFPRegisterName(regPrefix, vn()); |
1592 | appendSeparator(); |
1593 | appendFPRegisterName(regPrefix, vm()); |
1594 | |
1595 | return m_formatBuffer; |
1596 | } |
1597 | |
1598 | const char* ARMv7DOpcodeVCVT::format() |
1599 | { |
1600 | char dregPrefix; |
1601 | char mregPrefix; |
1602 | const char *n1, *n2; |
1603 | |
1604 | switch (opc2()) { |
1605 | case 5: |
1606 | n1 = op() ? "vcvtr.s32." : "vcvt.s32." ; |
1607 | n2 = sz() ? "f64" : "f32" ; |
1608 | dregPrefix = 's'; |
1609 | mregPrefix = sz() ? 'd' : 's'; |
1610 | break; |
1611 | case 4: |
1612 | n1 = op() ? "vcvtr.u32." : "vcvt.u32." ; |
1613 | n2 = sz() ? "f64" : "f32" ; |
1614 | dregPrefix = 's'; |
1615 | mregPrefix = sz() ? 'd' : 's'; |
1616 | break; |
1617 | case 0: |
1618 | n1 = sz() ? "vcvt.f64." : "vcvt.f32." ; |
1619 | n2 = op() ? "s32" : "u32" ; |
1620 | dregPrefix = sz() ? 'd' : 's'; |
1621 | mregPrefix = 's'; |
1622 | break; |
1623 | default: |
1624 | n1 = "vcvt.?" ; |
1625 | n2 = ".?" ; |
1626 | dregPrefix = '?'; |
1627 | mregPrefix = '?'; |
1628 | break; |
1629 | } |
1630 | |
1631 | char buf[42]; |
1632 | snprintf(buf, 42, "%s%s" , n1, n2); |
1633 | appendInstructionName(buf); |
1634 | |
1635 | appendFPRegisterName(dregPrefix, vd()); |
1636 | appendSeparator(); |
1637 | appendFPRegisterName(mregPrefix, vm()); |
1638 | |
1639 | return m_formatBuffer; |
1640 | } |
1641 | |
1642 | const char* ARMv7DOpcodeVCMP::format() |
1643 | { |
1644 | char regPrefix = sz() ? 'd' : 's'; |
1645 | appendInstructionName(e() ? "vcmpe" : "vcmp" ); |
1646 | appendFPRegisterName(regPrefix, vd()); |
1647 | appendSeparator(); |
1648 | if (zero()) |
1649 | appendString("#0.0" ); |
1650 | else |
1651 | appendFPRegisterName(regPrefix, vm()); |
1652 | |
1653 | return m_formatBuffer; |
1654 | } |
1655 | |
1656 | const char* ARMv7DOpcodeVLDRVSTR::format() |
1657 | { |
1658 | appendInstructionName(opName()); |
1659 | |
1660 | char regPrefix = sz() ? 'd' : 's'; |
1661 | appendFPRegisterName(regPrefix, vd()); |
1662 | |
1663 | appendSeparator(); |
1664 | appendCharacter('['); |
1665 | appendRegisterName(rn()); |
1666 | |
1667 | if (immediate8() || !uBit()) { |
1668 | appendSeparator(); |
1669 | if (uBit()) |
1670 | appendUnsignedImmediate(immediate8() << 2); |
1671 | else |
1672 | appendSignedImmediate(0 - static_cast<int>(immediate8() << 2)); |
1673 | } |
1674 | appendCharacter(']'); |
1675 | |
1676 | return m_formatBuffer; |
1677 | } |
1678 | |
1679 | } } // namespace JSC::ARMv7Disassembler |
1680 | |
1681 | #endif // #if USE(ARMV7_DISASSEMBLER) |
1682 | |