blob: 3022a77a4372b2dbfe40ce7e9dc753cbc4fe0270 [file] [log] [blame]
Greg Clayton64c84432011-01-21 22:02:52 +00001//===-- EmulateInstructionARM.cpp -------------------------------*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include "EmulateInstructionARM.h"
Greg Clayton8482ded2011-02-01 00:04:43 +000011#include "lldb/Core/ConstString.h"
12
Johnny Chen8584c922011-01-26 01:18:52 +000013#include "ARMDefines.h"
Johnny Chen4baf2e32011-01-24 18:24:53 +000014#include "ARMUtils.h"
Greg Clayton8482ded2011-02-01 00:04:43 +000015#include "ARM_DWARF_Registers.h"
Greg Clayton64c84432011-01-21 22:02:52 +000016
17using namespace lldb;
18using namespace lldb_private;
19
20// ARM constants used during decoding
21#define REG_RD 0
22#define LDM_REGLIST 1
23#define PC_REG 15
24#define PC_REGLIST_BIT 0x8000
25
Johnny Chen251af6a2011-01-21 22:47:25 +000026#define ARMv4 (1u << 0)
Greg Clayton64c84432011-01-21 22:02:52 +000027#define ARMv4T (1u << 1)
28#define ARMv5T (1u << 2)
29#define ARMv5TE (1u << 3)
30#define ARMv5TEJ (1u << 4)
Johnny Chen251af6a2011-01-21 22:47:25 +000031#define ARMv6 (1u << 5)
Greg Clayton64c84432011-01-21 22:02:52 +000032#define ARMv6K (1u << 6)
33#define ARMv6T2 (1u << 7)
Johnny Chen251af6a2011-01-21 22:47:25 +000034#define ARMv7 (1u << 8)
Johnny Chen60c0d622011-01-25 23:49:39 +000035#define ARMv8 (1u << 9)
Greg Clayton64c84432011-01-21 22:02:52 +000036#define ARMvAll (0xffffffffu)
37
Johnny Chen7dc60e12011-01-24 19:46:32 +000038typedef enum
Greg Clayton64c84432011-01-21 22:02:52 +000039{
40 eEncodingA1,
41 eEncodingA2,
42 eEncodingA3,
43 eEncodingA4,
44 eEncodingA5,
45 eEncodingT1,
46 eEncodingT2,
47 eEncodingT3,
48 eEncodingT4,
49 eEncodingT5,
50} ARMEncoding;
51
Johnny Chen7dc60e12011-01-24 19:46:32 +000052typedef enum
53{
54 eSize16,
55 eSize32
56} ARMInstrSize;
57
Johnny Chen4baf2e32011-01-24 18:24:53 +000058// Typedef for the callback function used during the emulation.
Johnny Chen3c75c762011-01-22 00:47:08 +000059// Pass along (ARMEncoding)encoding as the callback data.
60typedef bool (*EmulateCallback) (EmulateInstructionARM *emulator, ARMEncoding encoding);
61
Johnny Chen7dc60e12011-01-24 19:46:32 +000062typedef struct
Greg Clayton64c84432011-01-21 22:02:52 +000063{
64 uint32_t mask;
65 uint32_t value;
66 uint32_t variants;
67 ARMEncoding encoding;
Johnny Chen7dc60e12011-01-24 19:46:32 +000068 ARMInstrSize size;
Greg Clayton64c84432011-01-21 22:02:52 +000069 EmulateCallback callback;
Johnny Chen4bee8ce2011-01-22 00:59:07 +000070 const char *name;
Johnny Chen7dc60e12011-01-24 19:46:32 +000071} ARMOpcode;
Greg Clayton64c84432011-01-21 22:02:52 +000072
Johnny Chen08c25e82011-01-31 18:02:28 +000073// Push Multiple Registers stores multiple registers to the stack, storing to
74// consecutive memory locations ending just below the address in SP, and updates
75// SP to point to the start of the stored data.
Greg Clayton64c84432011-01-21 22:02:52 +000076static bool
Johnny Chence1ca772011-01-25 01:13:00 +000077emulate_push (EmulateInstructionARM *emulator, ARMEncoding encoding)
Greg Clayton64c84432011-01-21 22:02:52 +000078{
79#if 0
80 // ARM pseudo code...
81 if (ConditionPassed())
82 {
83 EncodingSpecificOperations();
84 NullCheckIfThumbEE(13);
85 address = SP - 4*BitCount(registers);
86
87 for (i = 0 to 14)
88 {
89 if (registers<i> == 1’)
90 {
91 if i == 13 && i != LowestSetBit(registers) // Only possible for encoding A1
92 MemA[address,4] = bits(32) UNKNOWN;
93 else
94 MemA[address,4] = R[i];
95 address = address + 4;
96 }
97 }
98
99 if (registers<15> == 1’) // Only possible for encoding A1 or A2
100 MemA[address,4] = PCStoreValue();
101
102 SP = SP - 4*BitCount(registers);
103 }
104#endif
105
106 bool success = false;
107 const uint32_t opcode = emulator->OpcodeAsUnsigned (&success);
108 if (!success)
109 return false;
110
111 if (emulator->ConditionPassed())
112 {
113 const uint32_t addr_byte_size = emulator->GetAddressByteSize();
114 const addr_t sp = emulator->ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, 0, &success);
115 if (!success)
116 return false;
Johnny Chen3c75c762011-01-22 00:47:08 +0000117 uint32_t registers = 0;
Johnny Chen91d99862011-01-25 19:07:04 +0000118 uint32_t Rt; // the source register
Johnny Chen3c75c762011-01-22 00:47:08 +0000119 switch (encoding) {
Johnny Chenaedde1c2011-01-24 20:38:45 +0000120 case eEncodingT1:
Johnny Chen108d5aa2011-01-26 01:00:55 +0000121 registers = Bits32(opcode, 7, 0);
Johnny Chenaedde1c2011-01-24 20:38:45 +0000122 // The M bit represents LR.
Johnny Chen108d5aa2011-01-26 01:00:55 +0000123 if (Bits32(opcode, 8, 8))
Johnny Chenef85e912011-01-31 23:07:40 +0000124 registers |= (1u << 14);
Johnny Chenaedde1c2011-01-24 20:38:45 +0000125 // if BitCount(registers) < 1 then UNPREDICTABLE;
126 if (BitCount(registers) < 1)
127 return false;
128 break;
Johnny Chen7dc60e12011-01-24 19:46:32 +0000129 case eEncodingT2:
130 // Ignore bits 15 & 13.
Johnny Chen108d5aa2011-01-26 01:00:55 +0000131 registers = Bits32(opcode, 15, 0) & ~0xa000;
Johnny Chen7dc60e12011-01-24 19:46:32 +0000132 // if BitCount(registers) < 2 then UNPREDICTABLE;
133 if (BitCount(registers) < 2)
134 return false;
135 break;
136 case eEncodingT3:
Johnny Chen108d5aa2011-01-26 01:00:55 +0000137 Rt = Bits32(opcode, 15, 12);
Johnny Chen7dc60e12011-01-24 19:46:32 +0000138 // if BadReg(t) then UNPREDICTABLE;
Johnny Chen91d99862011-01-25 19:07:04 +0000139 if (BadReg(Rt))
Johnny Chen7dc60e12011-01-24 19:46:32 +0000140 return false;
Johnny Chen91d99862011-01-25 19:07:04 +0000141 registers = (1u << Rt);
Johnny Chen7dc60e12011-01-24 19:46:32 +0000142 break;
Johnny Chen3c75c762011-01-22 00:47:08 +0000143 case eEncodingA1:
Johnny Chen108d5aa2011-01-26 01:00:55 +0000144 registers = Bits32(opcode, 15, 0);
Johnny Chena33d4842011-01-24 22:25:48 +0000145 // Instead of return false, let's handle the following case as well,
146 // which amounts to pushing one reg onto the full descending stacks.
147 // if BitCount(register_list) < 2 then SEE STMDB / STMFD;
Johnny Chen3c75c762011-01-22 00:47:08 +0000148 break;
149 case eEncodingA2:
Johnny Chen108d5aa2011-01-26 01:00:55 +0000150 Rt = Bits32(opcode, 15, 12);
Johnny Chen7dc60e12011-01-24 19:46:32 +0000151 // if t == 13 then UNPREDICTABLE;
Johnny Chen91d99862011-01-25 19:07:04 +0000152 if (Rt == dwarf_sp)
Johnny Chen3c75c762011-01-22 00:47:08 +0000153 return false;
Johnny Chen91d99862011-01-25 19:07:04 +0000154 registers = (1u << Rt);
Johnny Chen3c75c762011-01-22 00:47:08 +0000155 break;
Johnny Chence1ca772011-01-25 01:13:00 +0000156 default:
157 return false;
Johnny Chen3c75c762011-01-22 00:47:08 +0000158 }
Johnny Chence1ca772011-01-25 01:13:00 +0000159 addr_t sp_offset = addr_byte_size * BitCount (registers);
Greg Clayton64c84432011-01-21 22:02:52 +0000160 addr_t addr = sp - sp_offset;
161 uint32_t i;
162
163 EmulateInstruction::Context context = { EmulateInstruction::eContextPushRegisterOnStack, eRegisterKindDWARF, 0, 0 };
164 for (i=0; i<15; ++i)
165 {
Johnny Chen108d5aa2011-01-26 01:00:55 +0000166 if (BitIsSet (registers, 1u << i))
Greg Clayton64c84432011-01-21 22:02:52 +0000167 {
168 context.arg1 = dwarf_r0 + i; // arg1 in the context is the DWARF register number
169 context.arg2 = addr - sp; // arg2 in the context is the stack pointer offset
170 uint32_t reg_value = emulator->ReadRegisterUnsigned(eRegisterKindDWARF, context.arg1, 0, &success);
171 if (!success)
172 return false;
173 if (!emulator->WriteMemoryUnsigned (context, addr, reg_value, addr_byte_size))
174 return false;
175 addr += addr_byte_size;
176 }
177 }
178
Johnny Chen108d5aa2011-01-26 01:00:55 +0000179 if (BitIsSet (registers, 1u << 15))
Greg Clayton64c84432011-01-21 22:02:52 +0000180 {
181 context.arg1 = dwarf_pc; // arg1 in the context is the DWARF register number
Johnny Chen3c75c762011-01-22 00:47:08 +0000182 context.arg2 = addr - sp; // arg2 in the context is the stack pointer offset
Greg Clayton64c84432011-01-21 22:02:52 +0000183 const uint32_t pc = emulator->ReadRegisterUnsigned(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, 0, &success);
184 if (!success)
185 return false;
186 if (!emulator->WriteMemoryUnsigned (context, addr, pc + 8, addr_byte_size))
187 return false;
188 }
189
190 context.type = EmulateInstruction::eContextAdjustStackPointer;
191 context.arg0 = eRegisterKindGeneric;
192 context.arg1 = LLDB_REGNUM_GENERIC_SP;
Johnny Chen5b442b72011-01-27 19:34:30 +0000193 context.arg2 = -sp_offset;
Greg Clayton64c84432011-01-21 22:02:52 +0000194
195 if (!emulator->WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, sp - sp_offset))
196 return false;
197 }
198 return true;
199}
200
Johnny Chenef85e912011-01-31 23:07:40 +0000201// Pop Multiple Registers loads multiple registers from the stack, loading from
202// consecutive memory locations staring at the address in SP, and updates
203// SP to point just above the loaded data.
204static bool
205emulate_pop (EmulateInstructionARM *emulator, ARMEncoding encoding)
206{
207#if 0
208 // ARM pseudo code...
209 if (ConditionPassed())
210 {
211 EncodingSpecificOperations(); NullCheckIfThumbEE(13);
212 address = SP;
213 for i = 0 to 14
214 if registers<i> == 1 then
215 R[i} = if UnalignedAllowed then MemU[address,4] else MemA[address,4]; address = address + 4;
216 if registers<15> == 1 then
217 if UnalignedAllowed then
218 LoadWritePC(MemU[address,4]);
219 else
220 LoadWritePC(MemA[address,4]);
221 if registers<13> == 0 then SP = SP + 4*BitCount(registers);
222 if registers<13> == 1 then SP = bits(32) UNKNOWN;
223 }
224#endif
225
226 bool success = false;
227 const uint32_t opcode = emulator->OpcodeAsUnsigned (&success);
228 if (!success)
229 return false;
230
231 if (emulator->ConditionPassed())
232 {
233 const uint32_t addr_byte_size = emulator->GetAddressByteSize();
234 const addr_t sp = emulator->ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, 0, &success);
235 if (!success)
236 return false;
237 uint32_t registers = 0;
238 uint32_t Rt; // the destination register
239 switch (encoding) {
240 case eEncodingT1:
241 registers = Bits32(opcode, 7, 0);
242 // The P bit represents PC.
243 if (Bits32(opcode, 8, 8))
244 registers |= (1u << 15);
245 // if BitCount(registers) < 1 then UNPREDICTABLE;
246 if (BitCount(registers) < 1)
247 return false;
248 break;
249 case eEncodingT2:
250 // Ignore bit 13.
251 registers = Bits32(opcode, 15, 0) & ~0x2000;
252 // if BitCount(registers) < 2 || (P == '1' && M == '1') then UNPREDICTABLE;
253 if (BitCount(registers) < 2 || (Bits32(opcode, 15, 15) && Bits32(opcode, 14, 14)))
254 return false;
255 break;
256 case eEncodingT3:
257 Rt = Bits32(opcode, 15, 12);
258 // if t == 13 || (t == 15 && InITBlock() && !LastInITBlock()) then UNPREDICTABLE;
259 if (Rt == dwarf_sp)
260 return false;
261 registers = (1u << Rt);
262 break;
263 case eEncodingA1:
264 registers = Bits32(opcode, 15, 0);
265 // Instead of return false, let's handle the following case as well,
266 // which amounts to popping one reg from the full descending stacks.
267 // if BitCount(register_list) < 2 then SEE LDM / LDMIA / LDMFD;
268
269 // if registers<13> == ‘1’ && ArchVersion() >= 7 then UNPREDICTABLE;
270 if (Bits32(opcode, 13, 13))
271 return false;
272 break;
273 case eEncodingA2:
274 Rt = Bits32(opcode, 15, 12);
275 // if t == 13 then UNPREDICTABLE;
276 if (Rt == dwarf_sp)
277 return false;
278 registers = (1u << Rt);
279 break;
280 default:
281 return false;
282 }
283 addr_t sp_offset = addr_byte_size * BitCount (registers);
284 addr_t addr = sp;
285 uint32_t i, data;
286
287 EmulateInstruction::Context context = { EmulateInstruction::eContextPopRegisterOffStack, eRegisterKindDWARF, 0, 0 };
288 for (i=0; i<15; ++i)
289 {
290 if (BitIsSet (registers, 1u << i))
291 {
292 context.arg1 = dwarf_r0 + i; // arg1 in the context is the DWARF register number
293 context.arg2 = addr - sp; // arg2 in the context is the stack pointer offset
294 data = emulator->ReadMemoryUnsigned(context, addr, 4, 0, &success);
295 if (!success)
296 return false;
297 if (!emulator->WriteRegisterUnsigned(context, eRegisterKindDWARF, context.arg1, data))
298 return false;
299 addr += addr_byte_size;
300 }
301 }
302
303 if (BitIsSet (registers, 1u << 15))
304 {
305 context.arg1 = dwarf_pc; // arg1 in the context is the DWARF register number
306 context.arg2 = addr - sp; // arg2 in the context is the stack pointer offset
307 data = emulator->ReadMemoryUnsigned(context, addr, 4, 0, &success);
308 if (!success)
309 return false;
310 if (!emulator->WriteRegisterUnsigned(context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, data))
311 return false;
312 addr += addr_byte_size;
313 }
314
315 context.type = EmulateInstruction::eContextAdjustStackPointer;
316 context.arg0 = eRegisterKindGeneric;
317 context.arg1 = LLDB_REGNUM_GENERIC_SP;
318 context.arg2 = sp_offset;
319
320 if (!emulator->WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, sp + sp_offset))
321 return false;
322 }
323 return true;
324}
325
Johnny Chen5b442b72011-01-27 19:34:30 +0000326// Set r7 or ip to point to saved value residing within the stack.
Johnny Chenbcec3af2011-01-27 01:26:19 +0000327// ADD (SP plus immediate)
328static bool
329emulate_add_rd_sp_imm (EmulateInstructionARM *emulator, ARMEncoding encoding)
330{
331#if 0
332 // ARM pseudo code...
333 if (ConditionPassed())
334 {
335 EncodingSpecificOperations();
336 (result, carry, overflow) = AddWithCarry(SP, imm32, 0’);
337 if d == 15 then
338 ALUWritePC(result); // setflags is always FALSE here
339 else
340 R[d] = result;
341 if setflags then
342 APSR.N = result<31>;
343 APSR.Z = IsZeroBit(result);
344 APSR.C = carry;
345 APSR.V = overflow;
346 }
347#endif
348
349 bool success = false;
350 const uint32_t opcode = emulator->OpcodeAsUnsigned (&success);
351 if (!success)
352 return false;
353
354 if (emulator->ConditionPassed())
355 {
356 const addr_t sp = emulator->ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, 0, &success);
357 if (!success)
358 return false;
359 uint32_t Rd; // the destination register
360 uint32_t imm32;
361 switch (encoding) {
362 case eEncodingT1:
363 Rd = 7;
364 imm32 = Bits32(opcode, 7, 0) << 2; // imm32 = ZeroExtend(imm8:'00', 32)
365 break;
366 case eEncodingA1:
367 Rd = Bits32(opcode, 15, 12);
368 imm32 = ARMExpandImm(opcode); // imm32 = ARMExpandImm(imm12)
369 break;
370 default:
371 return false;
372 }
373 addr_t sp_offset = imm32;
374 addr_t addr = sp + sp_offset; // a pointer to the stack area
375
376 EmulateInstruction::Context context = { EmulateInstruction::eContextRegisterPlusOffset,
377 eRegisterKindGeneric,
378 LLDB_REGNUM_GENERIC_SP,
379 sp_offset };
380
381 if (!emulator->WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + Rd, addr))
382 return false;
383 }
384 return true;
385}
386
Johnny Chen2ccad832011-01-28 19:57:25 +0000387// Set r7 or ip to the current stack pointer.
388// MOV (register)
389static bool
390emulate_mov_rd_sp (EmulateInstructionARM *emulator, ARMEncoding encoding)
391{
392#if 0
393 // ARM pseudo code...
394 if (ConditionPassed())
395 {
396 EncodingSpecificOperations();
397 result = R[m];
398 if d == 15 then
399 ALUWritePC(result); // setflags is always FALSE here
400 else
401 R[d] = result;
402 if setflags then
403 APSR.N = result<31>;
404 APSR.Z = IsZeroBit(result);
405 // APSR.C unchanged
406 // APSR.V unchanged
407 }
408#endif
409
410 bool success = false;
Johnny Chen1c13b622011-01-29 00:11:15 +0000411 //const uint32_t opcode = emulator->OpcodeAsUnsigned (&success);
412 //if (!success)
413 // return false;
Johnny Chen2ccad832011-01-28 19:57:25 +0000414
415 if (emulator->ConditionPassed())
416 {
417 const addr_t sp = emulator->ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, 0, &success);
418 if (!success)
419 return false;
420 uint32_t Rd; // the destination register
421 switch (encoding) {
422 case eEncodingT1:
423 Rd = 7;
424 break;
425 case eEncodingA1:
426 Rd = 12;
427 break;
428 default:
429 return false;
430 }
431 EmulateInstruction::Context context = { EmulateInstruction::eContextRegisterPlusOffset,
432 eRegisterKindGeneric,
433 LLDB_REGNUM_GENERIC_SP,
434 0 };
435
436 if (!emulator->WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + Rd, sp))
437 return false;
438 }
439 return true;
440}
441
Johnny Chen1c13b622011-01-29 00:11:15 +0000442// Move from high register (r8-r15) to low register (r0-r7).
443// MOV (register)
444static bool
445emulate_mov_low_high (EmulateInstructionARM *emulator, ARMEncoding encoding)
446{
447#if 0
448 // ARM pseudo code...
449 if (ConditionPassed())
450 {
451 EncodingSpecificOperations();
452 result = R[m];
453 if d == 15 then
454 ALUWritePC(result); // setflags is always FALSE here
455 else
456 R[d] = result;
457 if setflags then
458 APSR.N = result<31>;
459 APSR.Z = IsZeroBit(result);
460 // APSR.C unchanged
461 // APSR.V unchanged
462 }
463#endif
464
465 bool success = false;
466 const uint32_t opcode = emulator->OpcodeAsUnsigned (&success);
467 if (!success)
468 return false;
469
470 if (emulator->ConditionPassed())
471 {
472 uint32_t Rm; // the source register
473 uint32_t Rd; // the destination register
474 switch (encoding) {
475 case eEncodingT1:
476 Rm = Bits32(opcode, 6, 3);
477 Rd = Bits32(opcode, 2, 1); // bits(7) == 0
478 break;
479 default:
480 return false;
481 }
482 int32_t reg_value = emulator->ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + Rm, 0, &success);
483 if (!success)
484 return false;
485
486 // The context specifies that Rm is to be moved into Rd.
487 EmulateInstruction::Context context = { EmulateInstruction::eContextRegisterPlusOffset,
488 eRegisterKindDWARF,
489 dwarf_r0 + Rm,
490 0 };
491
492 if (!emulator->WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + Rd, reg_value))
493 return false;
494 }
495 return true;
496}
497
Johnny Chen788e0552011-01-27 22:52:23 +0000498// PC relative immediate load into register, possibly followed by ADD (SP plus register).
499// LDR (literal)
500static bool
501emulate_ldr_rd_pc_rel (EmulateInstructionARM *emulator, ARMEncoding encoding)
502{
503#if 0
504 // ARM pseudo code...
505 if (ConditionPassed())
506 {
507 EncodingSpecificOperations(); NullCheckIfThumbEE(15);
508 base = Align(PC,4);
509 address = if add then (base + imm32) else (base - imm32);
510 data = MemU[address,4];
511 if t == 15 then
512 if address<1:0> == 00 then LoadWritePC(data); else UNPREDICTABLE;
513 elsif UnalignedSupport() || address<1:0> = 00 then
514 R[t] = data;
515 else // Can only apply before ARMv7
516 if CurrentInstrSet() == InstrSet_ARM then
517 R[t] = ROR(data, 8*UInt(address<1:0>));
518 else
519 R[t] = bits(32) UNKNOWN;
520 }
521#endif
522
523 bool success = false;
524 const uint32_t opcode = emulator->OpcodeAsUnsigned (&success);
525 if (!success)
526 return false;
527
528 if (emulator->ConditionPassed())
529 {
530 const uint32_t pc = emulator->ReadRegisterUnsigned(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, 0, &success);
531 if (!success)
532 return false;
Johnny Chen809742e2011-01-28 00:32:27 +0000533
534 // PC relative immediate load context
535 EmulateInstruction::Context context = {EmulateInstruction::eContextRegisterPlusOffset,
536 eRegisterKindGeneric,
537 LLDB_REGNUM_GENERIC_PC,
538 0};
Johnny Chen788e0552011-01-27 22:52:23 +0000539 uint32_t Rd; // the destination register
540 uint32_t imm32; // immediate offset from the PC
541 addr_t addr; // the PC relative address
542 uint32_t data; // the literal data value from the PC relative load
543 switch (encoding) {
544 case eEncodingT1:
545 Rd = Bits32(opcode, 10, 8);
546 imm32 = Bits32(opcode, 7, 0) << 2; // imm32 = ZeroExtend(imm8:'00', 32);
547 addr = pc + 4 + imm32;
Johnny Chen809742e2011-01-28 00:32:27 +0000548 context.arg2 = 4 + imm32;
Johnny Chen788e0552011-01-27 22:52:23 +0000549 break;
550 default:
551 return false;
552 }
Johnny Chen809742e2011-01-28 00:32:27 +0000553 data = emulator->ReadMemoryUnsigned(context, addr, 4, 0, &success);
Johnny Chen788e0552011-01-27 22:52:23 +0000554 if (!success)
Johnny Chen809742e2011-01-28 00:32:27 +0000555 return false;
Johnny Chen788e0552011-01-27 22:52:23 +0000556 if (!emulator->WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + Rd, data))
557 return false;
558 }
559 return true;
560}
561
Johnny Chen5b442b72011-01-27 19:34:30 +0000562// An add operation to adjust the SP.
Johnny Chenfdd179e2011-01-31 20:09:28 +0000563// ADD (SP plus immediate)
564static bool
565emulate_add_sp_imm (EmulateInstructionARM *emulator, ARMEncoding encoding)
566{
567#if 0
568 // ARM pseudo code...
569 if (ConditionPassed())
570 {
571 EncodingSpecificOperations();
572 (result, carry, overflow) = AddWithCarry(SP, imm32, 0’);
573 if d == 15 then // Can only occur for ARM encoding
574 ALUWritePC(result); // setflags is always FALSE here
575 else
576 R[d] = result;
577 if setflags then
578 APSR.N = result<31>;
579 APSR.Z = IsZeroBit(result);
580 APSR.C = carry;
581 APSR.V = overflow;
582 }
583#endif
584
585 bool success = false;
586 const uint32_t opcode = emulator->OpcodeAsUnsigned (&success);
587 if (!success)
588 return false;
589
590 if (emulator->ConditionPassed())
591 {
592 const addr_t sp = emulator->ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, 0, &success);
593 if (!success)
594 return false;
595 uint32_t imm32; // the immediate operand
596 switch (encoding) {
597 case eEncodingT2:
598 imm32 = ThumbImmScaled(opcode); // imm32 = ZeroExtend(imm7:'00', 32)
599 break;
600 default:
601 return false;
602 }
603 addr_t sp_offset = imm32;
604 addr_t addr = sp + sp_offset; // the adjusted stack pointer value
605
606 EmulateInstruction::Context context = { EmulateInstruction::eContextAdjustStackPointer,
607 eRegisterKindGeneric,
608 LLDB_REGNUM_GENERIC_SP,
609 sp_offset };
610
611 if (!emulator->WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, addr))
612 return false;
613 }
614 return true;
615}
616
617// An add operation to adjust the SP.
Johnny Chen5b442b72011-01-27 19:34:30 +0000618// ADD (SP plus register)
619static bool
620emulate_add_sp_rm (EmulateInstructionARM *emulator, ARMEncoding encoding)
621{
622#if 0
623 // ARM pseudo code...
624 if (ConditionPassed())
625 {
626 EncodingSpecificOperations();
627 shifted = Shift(R[m], shift_t, shift_n, APSR.C);
628 (result, carry, overflow) = AddWithCarry(SP, shifted, 0’);
629 if d == 15 then
630 ALUWritePC(result); // setflags is always FALSE here
631 else
632 R[d] = result;
633 if setflags then
634 APSR.N = result<31>;
635 APSR.Z = IsZeroBit(result);
636 APSR.C = carry;
637 APSR.V = overflow;
638 }
639#endif
640
641 bool success = false;
642 const uint32_t opcode = emulator->OpcodeAsUnsigned (&success);
643 if (!success)
644 return false;
645
646 if (emulator->ConditionPassed())
647 {
648 const addr_t sp = emulator->ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, 0, &success);
649 if (!success)
650 return false;
651 uint32_t Rm; // the second operand
652 switch (encoding) {
653 case eEncodingT2:
654 Rm = Bits32(opcode, 6, 3);
655 break;
656 default:
657 return false;
658 }
659 int32_t reg_value = emulator->ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + Rm, 0, &success);
660 if (!success)
661 return false;
662
663 addr_t addr = (int32_t)sp + reg_value; // the adjusted stack pointer value
664
665 EmulateInstruction::Context context = { EmulateInstruction::eContextAdjustStackPointer,
666 eRegisterKindGeneric,
667 LLDB_REGNUM_GENERIC_SP,
668 reg_value };
669
670 if (!emulator->WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, addr))
671 return false;
672 }
673 return true;
674}
675
Johnny Chen0d0148e2011-01-28 02:26:08 +0000676// Set r7 to point to some ip offset.
677// SUB (immediate)
678static bool
679emulate_sub_r7_ip_imm (EmulateInstructionARM *emulator, ARMEncoding encoding)
680{
681#if 0
682 // ARM pseudo code...
683 if (ConditionPassed())
684 {
685 EncodingSpecificOperations();
686 (result, carry, overflow) = AddWithCarry(SP, NOT(imm32), 1’);
687 if d == 15 then // Can only occur for ARM encoding
688 ALUWritePC(result); // setflags is always FALSE here
689 else
690 R[d] = result;
691 if setflags then
692 APSR.N = result<31>;
693 APSR.Z = IsZeroBit(result);
694 APSR.C = carry;
695 APSR.V = overflow;
696 }
697#endif
698
699 bool success = false;
700 const uint32_t opcode = emulator->OpcodeAsUnsigned (&success);
701 if (!success)
702 return false;
703
704 if (emulator->ConditionPassed())
705 {
706 const addr_t ip = emulator->ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r12, 0, &success);
707 if (!success)
708 return false;
709 uint32_t imm32;
710 switch (encoding) {
711 case eEncodingA1:
712 imm32 = ARMExpandImm(opcode); // imm32 = ARMExpandImm(imm12)
713 break;
714 default:
715 return false;
716 }
717 addr_t ip_offset = imm32;
718 addr_t addr = ip - ip_offset; // the adjusted ip value
719
720 EmulateInstruction::Context context = { EmulateInstruction::eContextRegisterPlusOffset,
721 eRegisterKindDWARF,
722 dwarf_r12,
723 -ip_offset };
724
725 if (!emulator->WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r7, addr))
726 return false;
727 }
728 return true;
729}
730
731// Set ip to point to some stack offset.
732// SUB (SP minus immediate)
733static bool
734emulate_sub_ip_sp_imm (EmulateInstructionARM *emulator, ARMEncoding encoding)
735{
736#if 0
737 // ARM pseudo code...
738 if (ConditionPassed())
739 {
740 EncodingSpecificOperations();
741 (result, carry, overflow) = AddWithCarry(SP, NOT(imm32), 1’);
742 if d == 15 then // Can only occur for ARM encoding
743 ALUWritePC(result); // setflags is always FALSE here
744 else
745 R[d] = result;
746 if setflags then
747 APSR.N = result<31>;
748 APSR.Z = IsZeroBit(result);
749 APSR.C = carry;
750 APSR.V = overflow;
751 }
752#endif
753
754 bool success = false;
755 const uint32_t opcode = emulator->OpcodeAsUnsigned (&success);
756 if (!success)
757 return false;
758
759 if (emulator->ConditionPassed())
760 {
761 const addr_t sp = emulator->ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, 0, &success);
762 if (!success)
763 return false;
764 uint32_t imm32;
765 switch (encoding) {
766 case eEncodingA1:
767 imm32 = ARMExpandImm(opcode); // imm32 = ARMExpandImm(imm12)
768 break;
769 default:
770 return false;
771 }
772 addr_t sp_offset = imm32;
773 addr_t addr = sp - sp_offset; // the adjusted stack pointer value
774
775 EmulateInstruction::Context context = { EmulateInstruction::eContextRegisterPlusOffset,
776 eRegisterKindGeneric,
777 LLDB_REGNUM_GENERIC_SP,
778 -sp_offset };
779
780 if (!emulator->WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r12, addr))
781 return false;
782 }
783 return true;
784}
785
Johnny Chen4c0e0bc2011-01-25 22:45:28 +0000786// A sub operation to adjust the SP -- allocate space for local storage.
787static bool
788emulate_sub_sp_imm (EmulateInstructionARM *emulator, ARMEncoding encoding)
789{
790#if 0
791 // ARM pseudo code...
792 if (ConditionPassed())
793 {
794 EncodingSpecificOperations();
795 (result, carry, overflow) = AddWithCarry(SP, NOT(imm32), 1’);
796 if d == 15 then // Can only occur for ARM encoding
Johnny Chen799dfd02011-01-26 23:14:33 +0000797 ALUWritePC(result); // setflags is always FALSE here
Johnny Chen4c0e0bc2011-01-25 22:45:28 +0000798 else
799 R[d] = result;
800 if setflags then
801 APSR.N = result<31>;
802 APSR.Z = IsZeroBit(result);
803 APSR.C = carry;
804 APSR.V = overflow;
805 }
806#endif
807
808 bool success = false;
809 const uint32_t opcode = emulator->OpcodeAsUnsigned (&success);
810 if (!success)
811 return false;
812
813 if (emulator->ConditionPassed())
814 {
815 const addr_t sp = emulator->ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, 0, &success);
816 if (!success)
817 return false;
818 uint32_t imm32;
819 switch (encoding) {
Johnny Chene4455022011-01-26 00:08:59 +0000820 case eEncodingT1:
821 imm32 = ThumbImmScaled(opcode); // imm32 = ZeroExtend(imm7:'00', 32)
Johnny Chen60c0d622011-01-25 23:49:39 +0000822 case eEncodingT2:
823 imm32 = ThumbExpandImm(opcode); // imm32 = ThumbExpandImm(i:imm3:imm8)
824 break;
825 case eEncodingT3:
826 imm32 = ThumbImm12(opcode); // imm32 = ZeroExtend(i:imm3:imm8, 32)
827 break;
Johnny Chen4c0e0bc2011-01-25 22:45:28 +0000828 case eEncodingA1:
Johnny Chen60c0d622011-01-25 23:49:39 +0000829 imm32 = ARMExpandImm(opcode); // imm32 = ARMExpandImm(imm12)
Johnny Chen4c0e0bc2011-01-25 22:45:28 +0000830 break;
831 default:
832 return false;
833 }
834 addr_t sp_offset = imm32;
835 addr_t addr = sp - sp_offset; // the adjusted stack pointer value
836
837 EmulateInstruction::Context context = { EmulateInstruction::eContextAdjustStackPointer,
838 eRegisterKindGeneric,
839 LLDB_REGNUM_GENERIC_SP,
Johnny Chen5b442b72011-01-27 19:34:30 +0000840 -sp_offset };
Johnny Chen4c0e0bc2011-01-25 22:45:28 +0000841
842 if (!emulator->WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, addr))
843 return false;
844 }
845 return true;
846}
847
Johnny Chen08c25e82011-01-31 18:02:28 +0000848// A store operation to the stack that also updates the SP.
Johnny Chence1ca772011-01-25 01:13:00 +0000849static bool
850emulate_str_rt_sp (EmulateInstructionARM *emulator, ARMEncoding encoding)
851{
852#if 0
853 // ARM pseudo code...
854 if (ConditionPassed())
855 {
856 EncodingSpecificOperations();
857 offset_addr = if add then (R[n] + imm32) else (R[n] - imm32);
858 address = if index then offset_addr else R[n];
859 MemU[address,4] = if t == 15 then PCStoreValue() else R[t];
860 if wback then R[n] = offset_addr;
861 }
862#endif
863
864 bool success = false;
865 const uint32_t opcode = emulator->OpcodeAsUnsigned (&success);
866 if (!success)
867 return false;
868
869 if (emulator->ConditionPassed())
870 {
871 const uint32_t addr_byte_size = emulator->GetAddressByteSize();
872 const addr_t sp = emulator->ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, 0, &success);
873 if (!success)
874 return false;
Johnny Chen91d99862011-01-25 19:07:04 +0000875 uint32_t Rt; // the source register
Johnny Chence1ca772011-01-25 01:13:00 +0000876 uint32_t imm12;
877 switch (encoding) {
878 case eEncodingA1:
Johnny Chen108d5aa2011-01-26 01:00:55 +0000879 Rt = Bits32(opcode, 15, 12);
880 imm12 = Bits32(opcode, 11, 0);
Johnny Chence1ca772011-01-25 01:13:00 +0000881 break;
882 default:
883 return false;
884 }
885 addr_t sp_offset = imm12;
886 addr_t addr = sp - sp_offset;
887
888 EmulateInstruction::Context context = { EmulateInstruction::eContextPushRegisterOnStack, eRegisterKindDWARF, 0, 0 };
Johnny Chen91d99862011-01-25 19:07:04 +0000889 if (Rt != 15)
Johnny Chence1ca772011-01-25 01:13:00 +0000890 {
Johnny Chen91d99862011-01-25 19:07:04 +0000891 context.arg1 = dwarf_r0 + Rt; // arg1 in the context is the DWARF register number
892 context.arg2 = addr - sp; // arg2 in the context is the stack pointer offset
Johnny Chence1ca772011-01-25 01:13:00 +0000893 uint32_t reg_value = emulator->ReadRegisterUnsigned(eRegisterKindDWARF, context.arg1, 0, &success);
894 if (!success)
895 return false;
896 if (!emulator->WriteMemoryUnsigned (context, addr, reg_value, addr_byte_size))
897 return false;
898 }
899 else
900 {
901 context.arg1 = dwarf_pc; // arg1 in the context is the DWARF register number
902 context.arg2 = addr - sp; // arg2 in the context is the stack pointer offset
903 const uint32_t pc = emulator->ReadRegisterUnsigned(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, 0, &success);
904 if (!success)
905 return false;
906 if (!emulator->WriteMemoryUnsigned (context, addr, pc + 8, addr_byte_size))
907 return false;
908 }
909
910 context.type = EmulateInstruction::eContextAdjustStackPointer;
911 context.arg0 = eRegisterKindGeneric;
912 context.arg1 = LLDB_REGNUM_GENERIC_SP;
Johnny Chen5b442b72011-01-27 19:34:30 +0000913 context.arg2 = -sp_offset;
Johnny Chence1ca772011-01-25 01:13:00 +0000914
915 if (!emulator->WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, sp - sp_offset))
916 return false;
917 }
918 return true;
919}
920
Johnny Chen08c25e82011-01-31 18:02:28 +0000921// Vector Push stores multiple extension registers to the stack.
922// It also updates SP to point to the start of the stored data.
Johnny Chen799dfd02011-01-26 23:14:33 +0000923static bool
924emulate_vpush (EmulateInstructionARM *emulator, ARMEncoding encoding)
925{
926#if 0
927 // ARM pseudo code...
928 if (ConditionPassed())
929 {
930 EncodingSpecificOperations(); CheckVFPEnabled(TRUE); NullCheckIfThumbEE(13);
931 address = SP - imm32;
932 SP = SP - imm32;
933 if single_regs then
934 for r = 0 to regs-1
935 MemA[address,4] = S[d+r]; address = address+4;
936 else
937 for r = 0 to regs-1
938 // Store as two word-aligned words in the correct order for current endianness.
939 MemA[address,4] = if BigEndian() then D[d+r]<63:32> else D[d+r]<31:0>;
940 MemA[address+4,4] = if BigEndian() then D[d+r]<31:0> else D[d+r]<63:32>;
941 address = address+8;
942 }
943#endif
944
945 bool success = false;
946 const uint32_t opcode = emulator->OpcodeAsUnsigned (&success);
947 if (!success)
948 return false;
949
950 if (emulator->ConditionPassed())
951 {
952 const uint32_t addr_byte_size = emulator->GetAddressByteSize();
953 const addr_t sp = emulator->ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, 0, &success);
954 if (!success)
955 return false;
956 bool single_regs;
957 uint32_t d; // UInt(Vd:D) starting register
958 uint32_t imm32; // stack offset
959 uint32_t regs; // number of registers
960 switch (encoding) {
961 case eEncodingT1:
962 case eEncodingA1:
963 single_regs = false;
964 d = Bits32(opcode, 15, 12) << 1 | Bits32(opcode, 22, 22);
965 imm32 = Bits32(opcode, 7, 0) * addr_byte_size;
966 // If UInt(imm8) is odd, see "FSTMX".
967 regs = Bits32(opcode, 7, 0) / 2;
968 // if regs == 0 || regs > 16 || (d+regs) > 32 then UNPREDICTABLE;
969 if (regs == 0 || regs > 16 || (d + regs) > 32)
970 return false;
971 break;
972 case eEncodingT2:
973 case eEncodingA2:
974 single_regs = true;
975 d = Bits32(opcode, 15, 12) << 1 | Bits32(opcode, 22, 22);
976 imm32 = Bits32(opcode, 7, 0) * addr_byte_size;
977 regs = Bits32(opcode, 7, 0);
978 // if regs == 0 || regs > 16 || (d+regs) > 32 then UNPREDICTABLE;
979 if (regs == 0 || regs > 16 || (d + regs) > 32)
980 return false;
981 break;
982 default:
983 return false;
984 }
985 uint32_t start_reg = single_regs ? dwarf_s0 : dwarf_d0;
986 uint32_t reg_byte_size = single_regs ? addr_byte_size : addr_byte_size * 2;
987 addr_t sp_offset = imm32;
988 addr_t addr = sp - sp_offset;
989 uint32_t i;
990
991 EmulateInstruction::Context context = { EmulateInstruction::eContextPushRegisterOnStack, eRegisterKindDWARF, 0, 0 };
992 for (i=d; i<regs; ++i)
993 {
994 context.arg1 = start_reg + i; // arg1 in the context is the DWARF register number
995 context.arg2 = addr - sp; // arg2 in the context is the stack pointer offset
996 // uint64_t to accommodate 64-bit registers.
997 uint64_t reg_value = emulator->ReadRegisterUnsigned(eRegisterKindDWARF, context.arg1, 0, &success);
998 if (!success)
999 return false;
1000 if (!emulator->WriteMemoryUnsigned (context, addr, reg_value, reg_byte_size))
1001 return false;
1002 addr += reg_byte_size;
1003 }
1004
1005 context.type = EmulateInstruction::eContextAdjustStackPointer;
1006 context.arg0 = eRegisterKindGeneric;
1007 context.arg1 = LLDB_REGNUM_GENERIC_SP;
Johnny Chen5b442b72011-01-27 19:34:30 +00001008 context.arg2 = -sp_offset;
Johnny Chen799dfd02011-01-26 23:14:33 +00001009
1010 if (!emulator->WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, sp - sp_offset))
1011 return false;
1012 }
1013 return true;
1014}
1015
Greg Clayton64c84432011-01-21 22:02:52 +00001016static ARMOpcode g_arm_opcodes[] =
1017{
Johnny Chenfdd179e2011-01-31 20:09:28 +00001018 ///////////////////////////
1019 // Prologue instructions //
1020 ///////////////////////////
1021
Johnny Chene4455022011-01-26 00:08:59 +00001022 // push register(s)
Johnny Chenbcec3af2011-01-27 01:26:19 +00001023 { 0x0fff0000, 0x092d0000, ARMvAll, eEncodingA1, eSize32, emulate_push, "push <registers>" },
1024 { 0x0fff0fff, 0x052d0004, ARMvAll, eEncodingA2, eSize32, emulate_push, "push <register>" },
1025
Johnny Chen5b442b72011-01-27 19:34:30 +00001026 // set r7 to point to a stack offset
Johnny Chenbcec3af2011-01-27 01:26:19 +00001027 { 0x0ffff000, 0x028d7000, ARMvAll, eEncodingA1, eSize32, emulate_add_rd_sp_imm, "add r7, sp, #<const>" },
Johnny Chen2ccad832011-01-28 19:57:25 +00001028 { 0x0ffff000, 0x024c7000, ARMvAll, eEncodingA1, eSize32, emulate_sub_r7_ip_imm, "sub r7, ip, #<const>"},
Johnny Chen5b442b72011-01-27 19:34:30 +00001029 // set ip to point to a stack offset
Johnny Chen2ccad832011-01-28 19:57:25 +00001030 { 0x0fffffff, 0x01a0c00d, ARMvAll, eEncodingA1, eSize32, emulate_mov_rd_sp, "mov ip, sp" },
Johnny Chenbcec3af2011-01-27 01:26:19 +00001031 { 0x0ffff000, 0x028dc000, ARMvAll, eEncodingA1, eSize32, emulate_add_rd_sp_imm, "add ip, sp, #<const>" },
Johnny Chen2ccad832011-01-28 19:57:25 +00001032 { 0x0ffff000, 0x024dc000, ARMvAll, eEncodingA1, eSize32, emulate_sub_ip_sp_imm, "sub ip, sp, #<const>"},
Johnny Chen4c0e0bc2011-01-25 22:45:28 +00001033
1034 // adjust the stack pointer
Johnny Chenbcec3af2011-01-27 01:26:19 +00001035 { 0x0ffff000, 0x024dd000, ARMvAll, eEncodingA1, eSize32, emulate_sub_sp_imm, "sub sp, sp, #<const>"},
Johnny Chence1ca772011-01-25 01:13:00 +00001036
Johnny Chen2ccad832011-01-28 19:57:25 +00001037 // push one register
Johnny Chence1ca772011-01-25 01:13:00 +00001038 // if Rn == '1101' && imm12 == '000000000100' then SEE PUSH;
Johnny Chen788e0552011-01-27 22:52:23 +00001039 { 0x0fff0000, 0x052d0000, ARMvAll, eEncodingA1, eSize32, emulate_str_rt_sp, "str Rt, [sp, #-imm12]!" },
Johnny Chen799dfd02011-01-26 23:14:33 +00001040
1041 // vector push consecutive extension register(s)
Johnny Chenbcec3af2011-01-27 01:26:19 +00001042 { 0x0fbf0f00, 0x0d2d0b00, ARMv6T2|ARMv7, eEncodingA1, eSize32, emulate_vpush, "vpush.64 <list>"},
Johnny Chenef85e912011-01-31 23:07:40 +00001043 { 0x0fbf0f00, 0x0d2d0a00, ARMv6T2|ARMv7, eEncodingA2, eSize32, emulate_vpush, "vpush.32 <list>"},
1044
1045 ///////////////////////////
1046 // Epilogue instructions //
1047 ///////////////////////////
1048
1049 { 0x0fff0000, 0x08bd0000, ARMvAll, eEncodingA1, eSize32, emulate_pop, "pop <registers>"},
1050 { 0x0fff0fff, 0x049d0004, ARMvAll, eEncodingA2, eSize32, emulate_pop, "pop <register>"}
Greg Clayton64c84432011-01-21 22:02:52 +00001051};
1052
Johnny Chen347320d2011-01-24 23:40:59 +00001053static ARMOpcode g_thumb_opcodes[] =
1054{
Johnny Chenfdd179e2011-01-31 20:09:28 +00001055 ///////////////////////////
1056 // Prologue instructions //
1057 ///////////////////////////
1058
Johnny Chene4455022011-01-26 00:08:59 +00001059 // push register(s)
Johnny Chenbcec3af2011-01-27 01:26:19 +00001060 { 0xfffffe00, 0x0000b400, ARMvAll, eEncodingT1, eSize16, emulate_push, "push <registers>" },
1061 { 0xffff0000, 0xe92d0000, ARMv6T2|ARMv7, eEncodingT2, eSize32, emulate_push, "push.w <registers>" },
1062 { 0xffff0fff, 0xf84d0d04, ARMv6T2|ARMv7, eEncodingT3, eSize32, emulate_push, "push.w <register>" },
Johnny Chen1c13b622011-01-29 00:11:15 +00001063 // move from high register to low register
1064 { 0xffffffc0, 0x00004640, ARMvAll, eEncodingT1, eSize16, emulate_mov_low_high, "mov r0-r7, r8-r15" },
Johnny Chenbcec3af2011-01-27 01:26:19 +00001065
Johnny Chen5b442b72011-01-27 19:34:30 +00001066 // set r7 to point to a stack offset
Johnny Chen2ccad832011-01-28 19:57:25 +00001067 { 0xffffff00, 0x0000af00, ARMvAll, eEncodingT1, eSize16, emulate_add_rd_sp_imm, "add r7, sp, #imm" },
1068 { 0xffffffff, 0x0000466f, ARMvAll, eEncodingT1, eSize16, emulate_mov_rd_sp, "mov r7, sp" },
Johnny Chen788e0552011-01-27 22:52:23 +00001069
1070 // PC relative load into register (see also emulate_add_sp_rm)
1071 { 0xfffff800, 0x00004800, ARMvAll, eEncodingT1, eSize16, emulate_ldr_rd_pc_rel, "ldr <Rd>, [PC, #imm]"},
Johnny Chen60c0d622011-01-25 23:49:39 +00001072
1073 // adjust the stack pointer
Johnny Chen5b442b72011-01-27 19:34:30 +00001074 { 0xffffff87, 0x00004485, ARMvAll, eEncodingT2, eSize16, emulate_add_sp_rm, "add sp, <Rm>"},
Johnny Chen788e0552011-01-27 22:52:23 +00001075 { 0xffffff80, 0x0000b080, ARMvAll, eEncodingT1, eSize16, emulate_sub_sp_imm, "add sp, sp, #imm"},
Johnny Chen5b442b72011-01-27 19:34:30 +00001076 { 0xfbef8f00, 0xf1ad0d00, ARMv6T2|ARMv7, eEncodingT2, eSize32, emulate_sub_sp_imm, "sub.w sp, sp, #<const>"},
Johnny Chen788e0552011-01-27 22:52:23 +00001077 { 0xfbff8f00, 0xf2ad0d00, ARMv6T2|ARMv7, eEncodingT3, eSize32, emulate_sub_sp_imm, "subw sp, sp, #imm12"},
Johnny Chen799dfd02011-01-26 23:14:33 +00001078
1079 // vector push consecutive extension register(s)
Johnny Chenbcec3af2011-01-27 01:26:19 +00001080 { 0xffbf0f00, 0xed2d0b00, ARMv6T2|ARMv7, eEncodingT1, eSize32, emulate_vpush, "vpush.64 <list>"},
Johnny Chenfdd179e2011-01-31 20:09:28 +00001081 { 0xffbf0f00, 0xed2d0a00, ARMv6T2|ARMv7, eEncodingT2, eSize32, emulate_vpush, "vpush.32 <list>"},
1082
1083 ///////////////////////////
1084 // Epilogue instructions //
1085 ///////////////////////////
1086
Johnny Chenef85e912011-01-31 23:07:40 +00001087 { 0xffffff80, 0x0000b000, ARMvAll, eEncodingT2, eSize16, emulate_add_sp_imm, "add sp, #imm"},
1088 { 0xfffffe00, 0x0000bc00, ARMvAll, eEncodingT1, eSize16, emulate_pop, "pop <registers>"},
1089 { 0xffff0000, 0xe8bd0000, ARMv6T2|ARMv7, eEncodingT2, eSize32, emulate_pop, "pop.w <registers>" },
1090 { 0xffff0fff, 0xf85d0d04, ARMv6T2|ARMv7, eEncodingT3, eSize32, emulate_pop, "pop.w <register>" }
Johnny Chen347320d2011-01-24 23:40:59 +00001091};
1092
Greg Clayton64c84432011-01-21 22:02:52 +00001093static const size_t k_num_arm_opcodes = sizeof(g_arm_opcodes)/sizeof(ARMOpcode);
Johnny Chen347320d2011-01-24 23:40:59 +00001094static const size_t k_num_thumb_opcodes = sizeof(g_thumb_opcodes)/sizeof(ARMOpcode);
Greg Clayton64c84432011-01-21 22:02:52 +00001095
Greg Clayton31e2a382011-01-30 20:03:56 +00001096bool
1097EmulateInstructionARM::SetTargetTriple (const ConstString &triple)
1098{
1099 m_arm_isa = 0;
1100 const char *triple_cstr = triple.GetCString();
1101 if (triple_cstr)
1102 {
1103 const char *dash = ::strchr (triple_cstr, '-');
1104 if (dash)
1105 {
1106 std::string arch (triple_cstr, dash);
1107 const char *arch_cstr = arch.c_str();
1108 if (strcasecmp(arch_cstr, "armv4t") == 0)
1109 m_arm_isa = ARMv4T;
1110 else if (strcasecmp(arch_cstr, "armv4") == 0)
1111 m_arm_isa = ARMv4;
1112 else if (strcasecmp(arch_cstr, "armv5tej") == 0)
1113 m_arm_isa = ARMv5TEJ;
1114 else if (strcasecmp(arch_cstr, "armv5te") == 0)
1115 m_arm_isa = ARMv5TE;
1116 else if (strcasecmp(arch_cstr, "armv5t") == 0)
1117 m_arm_isa = ARMv5T;
1118 else if (strcasecmp(arch_cstr, "armv6k") == 0)
1119 m_arm_isa = ARMv6K;
1120 else if (strcasecmp(arch_cstr, "armv6") == 0)
1121 m_arm_isa = ARMv6;
1122 else if (strcasecmp(arch_cstr, "armv6t2") == 0)
1123 m_arm_isa = ARMv6T2;
1124 else if (strcasecmp(arch_cstr, "armv7") == 0)
1125 m_arm_isa = ARMv7;
1126 else if (strcasecmp(arch_cstr, "armv8") == 0)
1127 m_arm_isa = ARMv8;
1128 }
1129 }
1130 return m_arm_isa != 0;
1131}
1132
1133
Greg Clayton64c84432011-01-21 22:02:52 +00001134bool
1135EmulateInstructionARM::ReadInstruction ()
1136{
1137 bool success = false;
1138 m_inst_cpsr = ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FLAGS, 0, &success);
1139 if (success)
1140 {
1141 addr_t pc = ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, LLDB_INVALID_ADDRESS, &success);
1142 if (success)
1143 {
1144 Context read_inst_context = {eContextReadOpcode, 0, 0};
1145 if (m_inst_cpsr & MASK_CPSR_T)
1146 {
1147 m_inst_mode = eModeThumb;
1148 uint32_t thumb_opcode = ReadMemoryUnsigned(read_inst_context, pc, 2, 0, &success);
1149
1150 if (success)
1151 {
1152 if ((m_inst.opcode.inst16 & 0xe000) != 0xe000 || ((m_inst.opcode.inst16 & 0x1800u) == 0))
1153 {
1154 m_inst.opcode_type = eOpcode16;
1155 m_inst.opcode.inst16 = thumb_opcode;
1156 }
1157 else
1158 {
1159 m_inst.opcode_type = eOpcode32;
1160 m_inst.opcode.inst32 = (thumb_opcode << 16) | ReadMemoryUnsigned(read_inst_context, pc + 2, 2, 0, &success);
1161 }
1162 }
1163 }
1164 else
1165 {
1166 m_inst_mode = eModeARM;
1167 m_inst.opcode_type = eOpcode32;
1168 m_inst.opcode.inst32 = ReadMemoryUnsigned(read_inst_context, pc, 4, 0, &success);
1169 }
1170 }
1171 }
1172 if (!success)
1173 {
1174 m_inst_mode = eModeInvalid;
1175 m_inst_pc = LLDB_INVALID_ADDRESS;
1176 }
1177 return success;
1178}
1179
1180uint32_t
1181EmulateInstructionARM::CurrentCond ()
1182{
1183 switch (m_inst_mode)
1184 {
1185 default:
1186 case eModeInvalid:
1187 break;
1188
1189 case eModeARM:
1190 return UnsignedBits(m_inst.opcode.inst32, 31, 28);
1191
1192 case eModeThumb:
1193 return 0x0000000Eu; // Return always for now, we need to handl IT instructions later
1194 }
1195 return UINT32_MAX; // Return invalid value
1196}
1197bool
1198EmulateInstructionARM::ConditionPassed ()
1199{
1200 if (m_inst_cpsr == 0)
1201 return false;
1202
1203 const uint32_t cond = CurrentCond ();
1204
1205 if (cond == UINT32_MAX)
1206 return false;
1207
1208 bool result = false;
1209 switch (UnsignedBits(cond, 3, 1))
1210 {
1211 case 0: result = (m_inst_cpsr & MASK_CPSR_Z) != 0; break;
1212 case 1: result = (m_inst_cpsr & MASK_CPSR_C) != 0; break;
1213 case 2: result = (m_inst_cpsr & MASK_CPSR_N) != 0; break;
1214 case 3: result = (m_inst_cpsr & MASK_CPSR_V) != 0; break;
1215 case 4: result = ((m_inst_cpsr & MASK_CPSR_C) != 0) && ((m_inst_cpsr & MASK_CPSR_Z) == 0); break;
1216 case 5:
1217 {
1218 bool n = (m_inst_cpsr & MASK_CPSR_N);
1219 bool v = (m_inst_cpsr & MASK_CPSR_V);
1220 result = n == v;
1221 }
1222 break;
1223 case 6:
1224 {
1225 bool n = (m_inst_cpsr & MASK_CPSR_N);
1226 bool v = (m_inst_cpsr & MASK_CPSR_V);
1227 result = n == v && ((m_inst_cpsr & MASK_CPSR_Z) == 0);
1228 }
1229 break;
1230 case 7:
1231 result = true;
1232 break;
1233 }
1234
1235 if (cond & 1)
1236 result = !result;
1237 return result;
1238}
1239
1240
1241bool
1242EmulateInstructionARM::EvaluateInstruction ()
1243{
1244 return false;
1245}