blob: ad26d1d5184f439bc16bca92410594fbe7361d54 [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"
Johnny Chen9b8d7832011-02-02 01:13:56 +000016#include "llvm/Support/MathExtras.h" // for SignExtend32 template function
Greg Clayton64c84432011-01-21 22:02:52 +000017
18using namespace lldb;
19using namespace lldb_private;
20
21// ARM constants used during decoding
22#define REG_RD 0
23#define LDM_REGLIST 1
24#define PC_REG 15
25#define PC_REGLIST_BIT 0x8000
26
Johnny Chen251af6a2011-01-21 22:47:25 +000027#define ARMv4 (1u << 0)
Greg Clayton64c84432011-01-21 22:02:52 +000028#define ARMv4T (1u << 1)
29#define ARMv5T (1u << 2)
30#define ARMv5TE (1u << 3)
31#define ARMv5TEJ (1u << 4)
Johnny Chen251af6a2011-01-21 22:47:25 +000032#define ARMv6 (1u << 5)
Greg Clayton64c84432011-01-21 22:02:52 +000033#define ARMv6K (1u << 6)
34#define ARMv6T2 (1u << 7)
Johnny Chen251af6a2011-01-21 22:47:25 +000035#define ARMv7 (1u << 8)
Johnny Chen60c0d622011-01-25 23:49:39 +000036#define ARMv8 (1u << 9)
Greg Clayton64c84432011-01-21 22:02:52 +000037#define ARMvAll (0xffffffffu)
38
Johnny Chen9b8d7832011-02-02 01:13:56 +000039#define ARMV4T_ABOVE (ARMv4T|ARMv5T|ARMv5TE|ARMv5TEJ|ARMv6|ARMv6K|ARMv6T2|ARMv7|ARMv8)
40#define ARMV5_ABOVE (ARMv5T|ARMv5TE|ARMv5TEJ|ARMv6|ARMv6K|ARMv6T2|ARMv7|ARMv8)
41#define ARMV6T2_ABOVE (ARMv6T2|ARMv7|ARMv8)
Greg Clayton64c84432011-01-21 22:02:52 +000042
Greg Clayton2b8e8b02011-02-01 00:49:32 +000043void
44EmulateInstructionARM::Initialize ()
Johnny Chen7dc60e12011-01-24 19:46:32 +000045{
Greg Clayton2b8e8b02011-02-01 00:49:32 +000046}
Johnny Chen7dc60e12011-01-24 19:46:32 +000047
Greg Clayton2b8e8b02011-02-01 00:49:32 +000048void
49EmulateInstructionARM::Terminate ()
Greg Clayton64c84432011-01-21 22:02:52 +000050{
Greg Clayton2b8e8b02011-02-01 00:49:32 +000051}
52
Greg Clayton64c84432011-01-21 22:02:52 +000053
Johnny Chen08c25e82011-01-31 18:02:28 +000054// Push Multiple Registers stores multiple registers to the stack, storing to
55// consecutive memory locations ending just below the address in SP, and updates
56// SP to point to the start of the stored data.
Greg Clayton2b8e8b02011-02-01 00:49:32 +000057bool
58EmulateInstructionARM::EmulatePush (ARMEncoding encoding)
Greg Clayton64c84432011-01-21 22:02:52 +000059{
60#if 0
61 // ARM pseudo code...
62 if (ConditionPassed())
63 {
64 EncodingSpecificOperations();
65 NullCheckIfThumbEE(13);
66 address = SP - 4*BitCount(registers);
67
68 for (i = 0 to 14)
69 {
70 if (registers<i> == 1’)
71 {
72 if i == 13 && i != LowestSetBit(registers) // Only possible for encoding A1
73 MemA[address,4] = bits(32) UNKNOWN;
74 else
75 MemA[address,4] = R[i];
76 address = address + 4;
77 }
78 }
79
80 if (registers<15> == 1’) // Only possible for encoding A1 or A2
81 MemA[address,4] = PCStoreValue();
82
83 SP = SP - 4*BitCount(registers);
84 }
85#endif
86
87 bool success = false;
Greg Clayton2b8e8b02011-02-01 00:49:32 +000088 const uint32_t opcode = OpcodeAsUnsigned (&success);
Greg Clayton64c84432011-01-21 22:02:52 +000089 if (!success)
90 return false;
91
Greg Clayton2b8e8b02011-02-01 00:49:32 +000092 if (ConditionPassed())
Greg Clayton64c84432011-01-21 22:02:52 +000093 {
Greg Clayton2b8e8b02011-02-01 00:49:32 +000094 const uint32_t addr_byte_size = GetAddressByteSize();
95 const addr_t sp = ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, 0, &success);
Greg Clayton64c84432011-01-21 22:02:52 +000096 if (!success)
97 return false;
Johnny Chen3c75c762011-01-22 00:47:08 +000098 uint32_t registers = 0;
Johnny Chen91d99862011-01-25 19:07:04 +000099 uint32_t Rt; // the source register
Johnny Chen3c75c762011-01-22 00:47:08 +0000100 switch (encoding) {
Johnny Chenaedde1c2011-01-24 20:38:45 +0000101 case eEncodingT1:
Johnny Chen108d5aa2011-01-26 01:00:55 +0000102 registers = Bits32(opcode, 7, 0);
Johnny Chenaedde1c2011-01-24 20:38:45 +0000103 // The M bit represents LR.
Johnny Chen108d5aa2011-01-26 01:00:55 +0000104 if (Bits32(opcode, 8, 8))
Johnny Chenef85e912011-01-31 23:07:40 +0000105 registers |= (1u << 14);
Johnny Chenaedde1c2011-01-24 20:38:45 +0000106 // if BitCount(registers) < 1 then UNPREDICTABLE;
107 if (BitCount(registers) < 1)
108 return false;
109 break;
Johnny Chen7dc60e12011-01-24 19:46:32 +0000110 case eEncodingT2:
111 // Ignore bits 15 & 13.
Johnny Chen108d5aa2011-01-26 01:00:55 +0000112 registers = Bits32(opcode, 15, 0) & ~0xa000;
Johnny Chen7dc60e12011-01-24 19:46:32 +0000113 // if BitCount(registers) < 2 then UNPREDICTABLE;
114 if (BitCount(registers) < 2)
115 return false;
116 break;
117 case eEncodingT3:
Johnny Chen108d5aa2011-01-26 01:00:55 +0000118 Rt = Bits32(opcode, 15, 12);
Johnny Chen7dc60e12011-01-24 19:46:32 +0000119 // if BadReg(t) then UNPREDICTABLE;
Johnny Chen91d99862011-01-25 19:07:04 +0000120 if (BadReg(Rt))
Johnny Chen7dc60e12011-01-24 19:46:32 +0000121 return false;
Johnny Chen91d99862011-01-25 19:07:04 +0000122 registers = (1u << Rt);
Johnny Chen7dc60e12011-01-24 19:46:32 +0000123 break;
Johnny Chen3c75c762011-01-22 00:47:08 +0000124 case eEncodingA1:
Johnny Chen108d5aa2011-01-26 01:00:55 +0000125 registers = Bits32(opcode, 15, 0);
Johnny Chena33d4842011-01-24 22:25:48 +0000126 // Instead of return false, let's handle the following case as well,
127 // which amounts to pushing one reg onto the full descending stacks.
128 // if BitCount(register_list) < 2 then SEE STMDB / STMFD;
Johnny Chen3c75c762011-01-22 00:47:08 +0000129 break;
130 case eEncodingA2:
Johnny Chen108d5aa2011-01-26 01:00:55 +0000131 Rt = Bits32(opcode, 15, 12);
Johnny Chen7dc60e12011-01-24 19:46:32 +0000132 // if t == 13 then UNPREDICTABLE;
Johnny Chen91d99862011-01-25 19:07:04 +0000133 if (Rt == dwarf_sp)
Johnny Chen3c75c762011-01-22 00:47:08 +0000134 return false;
Johnny Chen91d99862011-01-25 19:07:04 +0000135 registers = (1u << Rt);
Johnny Chen3c75c762011-01-22 00:47:08 +0000136 break;
Johnny Chence1ca772011-01-25 01:13:00 +0000137 default:
138 return false;
Johnny Chen3c75c762011-01-22 00:47:08 +0000139 }
Johnny Chence1ca772011-01-25 01:13:00 +0000140 addr_t sp_offset = addr_byte_size * BitCount (registers);
Greg Clayton64c84432011-01-21 22:02:52 +0000141 addr_t addr = sp - sp_offset;
142 uint32_t i;
143
144 EmulateInstruction::Context context = { EmulateInstruction::eContextPushRegisterOnStack, eRegisterKindDWARF, 0, 0 };
145 for (i=0; i<15; ++i)
146 {
Johnny Chen108d5aa2011-01-26 01:00:55 +0000147 if (BitIsSet (registers, 1u << i))
Greg Clayton64c84432011-01-21 22:02:52 +0000148 {
149 context.arg1 = dwarf_r0 + i; // arg1 in the context is the DWARF register number
150 context.arg2 = addr - sp; // arg2 in the context is the stack pointer offset
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000151 uint32_t reg_value = ReadRegisterUnsigned(eRegisterKindDWARF, context.arg1, 0, &success);
Greg Clayton64c84432011-01-21 22:02:52 +0000152 if (!success)
153 return false;
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000154 if (!WriteMemoryUnsigned (context, addr, reg_value, addr_byte_size))
Greg Clayton64c84432011-01-21 22:02:52 +0000155 return false;
156 addr += addr_byte_size;
157 }
158 }
159
Johnny Chen108d5aa2011-01-26 01:00:55 +0000160 if (BitIsSet (registers, 1u << 15))
Greg Clayton64c84432011-01-21 22:02:52 +0000161 {
162 context.arg1 = dwarf_pc; // arg1 in the context is the DWARF register number
Johnny Chen3c75c762011-01-22 00:47:08 +0000163 context.arg2 = addr - sp; // arg2 in the context is the stack pointer offset
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000164 const uint32_t pc = ReadRegisterUnsigned(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, 0, &success);
Greg Clayton64c84432011-01-21 22:02:52 +0000165 if (!success)
166 return false;
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000167 if (!WriteMemoryUnsigned (context, addr, pc + 8, addr_byte_size))
Greg Clayton64c84432011-01-21 22:02:52 +0000168 return false;
169 }
170
171 context.type = EmulateInstruction::eContextAdjustStackPointer;
172 context.arg0 = eRegisterKindGeneric;
173 context.arg1 = LLDB_REGNUM_GENERIC_SP;
Johnny Chen5b442b72011-01-27 19:34:30 +0000174 context.arg2 = -sp_offset;
Greg Clayton64c84432011-01-21 22:02:52 +0000175
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000176 if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, sp - sp_offset))
Greg Clayton64c84432011-01-21 22:02:52 +0000177 return false;
178 }
179 return true;
180}
181
Johnny Chenef85e912011-01-31 23:07:40 +0000182// Pop Multiple Registers loads multiple registers from the stack, loading from
183// consecutive memory locations staring at the address in SP, and updates
184// SP to point just above the loaded data.
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000185bool
186EmulateInstructionARM::EmulatePop (ARMEncoding encoding)
Johnny Chenef85e912011-01-31 23:07:40 +0000187{
188#if 0
189 // ARM pseudo code...
190 if (ConditionPassed())
191 {
192 EncodingSpecificOperations(); NullCheckIfThumbEE(13);
193 address = SP;
194 for i = 0 to 14
195 if registers<i> == 1 then
196 R[i} = if UnalignedAllowed then MemU[address,4] else MemA[address,4]; address = address + 4;
197 if registers<15> == 1 then
198 if UnalignedAllowed then
199 LoadWritePC(MemU[address,4]);
200 else
201 LoadWritePC(MemA[address,4]);
202 if registers<13> == 0 then SP = SP + 4*BitCount(registers);
203 if registers<13> == 1 then SP = bits(32) UNKNOWN;
204 }
205#endif
206
207 bool success = false;
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000208 const uint32_t opcode = OpcodeAsUnsigned (&success);
Johnny Chenef85e912011-01-31 23:07:40 +0000209 if (!success)
210 return false;
211
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000212 if (ConditionPassed())
Johnny Chenef85e912011-01-31 23:07:40 +0000213 {
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000214 const uint32_t addr_byte_size = GetAddressByteSize();
215 const addr_t sp = ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, 0, &success);
Johnny Chenef85e912011-01-31 23:07:40 +0000216 if (!success)
217 return false;
218 uint32_t registers = 0;
219 uint32_t Rt; // the destination register
220 switch (encoding) {
221 case eEncodingT1:
222 registers = Bits32(opcode, 7, 0);
223 // The P bit represents PC.
224 if (Bits32(opcode, 8, 8))
225 registers |= (1u << 15);
226 // if BitCount(registers) < 1 then UNPREDICTABLE;
227 if (BitCount(registers) < 1)
228 return false;
229 break;
230 case eEncodingT2:
231 // Ignore bit 13.
232 registers = Bits32(opcode, 15, 0) & ~0x2000;
233 // if BitCount(registers) < 2 || (P == '1' && M == '1') then UNPREDICTABLE;
234 if (BitCount(registers) < 2 || (Bits32(opcode, 15, 15) && Bits32(opcode, 14, 14)))
235 return false;
236 break;
237 case eEncodingT3:
238 Rt = Bits32(opcode, 15, 12);
239 // if t == 13 || (t == 15 && InITBlock() && !LastInITBlock()) then UNPREDICTABLE;
240 if (Rt == dwarf_sp)
241 return false;
242 registers = (1u << Rt);
243 break;
244 case eEncodingA1:
245 registers = Bits32(opcode, 15, 0);
246 // Instead of return false, let's handle the following case as well,
247 // which amounts to popping one reg from the full descending stacks.
248 // if BitCount(register_list) < 2 then SEE LDM / LDMIA / LDMFD;
249
250 // if registers<13> == ‘1’ && ArchVersion() >= 7 then UNPREDICTABLE;
251 if (Bits32(opcode, 13, 13))
252 return false;
253 break;
254 case eEncodingA2:
255 Rt = Bits32(opcode, 15, 12);
256 // if t == 13 then UNPREDICTABLE;
257 if (Rt == dwarf_sp)
258 return false;
259 registers = (1u << Rt);
260 break;
261 default:
262 return false;
263 }
264 addr_t sp_offset = addr_byte_size * BitCount (registers);
265 addr_t addr = sp;
266 uint32_t i, data;
267
268 EmulateInstruction::Context context = { EmulateInstruction::eContextPopRegisterOffStack, eRegisterKindDWARF, 0, 0 };
269 for (i=0; i<15; ++i)
270 {
271 if (BitIsSet (registers, 1u << i))
272 {
273 context.arg1 = dwarf_r0 + i; // arg1 in the context is the DWARF register number
274 context.arg2 = addr - sp; // arg2 in the context is the stack pointer offset
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000275 data = ReadMemoryUnsigned(context, addr, 4, 0, &success);
Johnny Chenef85e912011-01-31 23:07:40 +0000276 if (!success)
277 return false;
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000278 if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, context.arg1, data))
Johnny Chenef85e912011-01-31 23:07:40 +0000279 return false;
280 addr += addr_byte_size;
281 }
282 }
283
284 if (BitIsSet (registers, 1u << 15))
285 {
286 context.arg1 = dwarf_pc; // arg1 in the context is the DWARF register number
287 context.arg2 = addr - sp; // arg2 in the context is the stack pointer offset
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000288 data = ReadMemoryUnsigned(context, addr, 4, 0, &success);
Johnny Chenef85e912011-01-31 23:07:40 +0000289 if (!success)
290 return false;
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000291 if (!WriteRegisterUnsigned(context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, data))
Johnny Chenef85e912011-01-31 23:07:40 +0000292 return false;
293 addr += addr_byte_size;
294 }
295
296 context.type = EmulateInstruction::eContextAdjustStackPointer;
297 context.arg0 = eRegisterKindGeneric;
298 context.arg1 = LLDB_REGNUM_GENERIC_SP;
299 context.arg2 = sp_offset;
300
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000301 if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, sp + sp_offset))
Johnny Chenef85e912011-01-31 23:07:40 +0000302 return false;
303 }
304 return true;
305}
306
Johnny Chen5b442b72011-01-27 19:34:30 +0000307// Set r7 or ip to point to saved value residing within the stack.
Johnny Chenbcec3af2011-01-27 01:26:19 +0000308// ADD (SP plus immediate)
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000309bool
310EmulateInstructionARM::EmulateAddRdSPImmediate (ARMEncoding encoding)
Johnny Chenbcec3af2011-01-27 01:26:19 +0000311{
312#if 0
313 // ARM pseudo code...
314 if (ConditionPassed())
315 {
316 EncodingSpecificOperations();
317 (result, carry, overflow) = AddWithCarry(SP, imm32, 0’);
318 if d == 15 then
319 ALUWritePC(result); // setflags is always FALSE here
320 else
321 R[d] = result;
322 if setflags then
323 APSR.N = result<31>;
324 APSR.Z = IsZeroBit(result);
325 APSR.C = carry;
326 APSR.V = overflow;
327 }
328#endif
329
330 bool success = false;
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000331 const uint32_t opcode = OpcodeAsUnsigned (&success);
Johnny Chenbcec3af2011-01-27 01:26:19 +0000332 if (!success)
333 return false;
334
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000335 if (ConditionPassed())
Johnny Chenbcec3af2011-01-27 01:26:19 +0000336 {
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000337 const addr_t sp = ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, 0, &success);
Johnny Chenbcec3af2011-01-27 01:26:19 +0000338 if (!success)
339 return false;
340 uint32_t Rd; // the destination register
341 uint32_t imm32;
342 switch (encoding) {
343 case eEncodingT1:
344 Rd = 7;
345 imm32 = Bits32(opcode, 7, 0) << 2; // imm32 = ZeroExtend(imm8:'00', 32)
346 break;
347 case eEncodingA1:
348 Rd = Bits32(opcode, 15, 12);
349 imm32 = ARMExpandImm(opcode); // imm32 = ARMExpandImm(imm12)
350 break;
351 default:
352 return false;
353 }
354 addr_t sp_offset = imm32;
355 addr_t addr = sp + sp_offset; // a pointer to the stack area
356
357 EmulateInstruction::Context context = { EmulateInstruction::eContextRegisterPlusOffset,
358 eRegisterKindGeneric,
359 LLDB_REGNUM_GENERIC_SP,
360 sp_offset };
361
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000362 if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + Rd, addr))
Johnny Chenbcec3af2011-01-27 01:26:19 +0000363 return false;
364 }
365 return true;
366}
367
Johnny Chen2ccad832011-01-28 19:57:25 +0000368// Set r7 or ip to the current stack pointer.
369// MOV (register)
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000370bool
371EmulateInstructionARM::EmulateMovRdSP (ARMEncoding encoding)
Johnny Chen2ccad832011-01-28 19:57:25 +0000372{
373#if 0
374 // ARM pseudo code...
375 if (ConditionPassed())
376 {
377 EncodingSpecificOperations();
378 result = R[m];
379 if d == 15 then
380 ALUWritePC(result); // setflags is always FALSE here
381 else
382 R[d] = result;
383 if setflags then
384 APSR.N = result<31>;
385 APSR.Z = IsZeroBit(result);
386 // APSR.C unchanged
387 // APSR.V unchanged
388 }
389#endif
390
391 bool success = false;
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000392 //const uint32_t opcode = OpcodeAsUnsigned (&success);
Johnny Chen1c13b622011-01-29 00:11:15 +0000393 //if (!success)
394 // return false;
Johnny Chen2ccad832011-01-28 19:57:25 +0000395
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000396 if (ConditionPassed())
Johnny Chen2ccad832011-01-28 19:57:25 +0000397 {
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000398 const addr_t sp = ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, 0, &success);
Johnny Chen2ccad832011-01-28 19:57:25 +0000399 if (!success)
400 return false;
401 uint32_t Rd; // the destination register
402 switch (encoding) {
403 case eEncodingT1:
404 Rd = 7;
405 break;
406 case eEncodingA1:
407 Rd = 12;
408 break;
409 default:
410 return false;
411 }
412 EmulateInstruction::Context context = { EmulateInstruction::eContextRegisterPlusOffset,
413 eRegisterKindGeneric,
414 LLDB_REGNUM_GENERIC_SP,
415 0 };
416
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000417 if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + Rd, sp))
Johnny Chen2ccad832011-01-28 19:57:25 +0000418 return false;
419 }
420 return true;
421}
422
Johnny Chen1c13b622011-01-29 00:11:15 +0000423// Move from high register (r8-r15) to low register (r0-r7).
424// MOV (register)
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000425bool
426EmulateInstructionARM::EmulateMovLowHigh (ARMEncoding encoding)
Johnny Chen1c13b622011-01-29 00:11:15 +0000427{
428#if 0
429 // ARM pseudo code...
430 if (ConditionPassed())
431 {
432 EncodingSpecificOperations();
433 result = R[m];
434 if d == 15 then
435 ALUWritePC(result); // setflags is always FALSE here
436 else
437 R[d] = result;
438 if setflags then
439 APSR.N = result<31>;
440 APSR.Z = IsZeroBit(result);
441 // APSR.C unchanged
442 // APSR.V unchanged
443 }
444#endif
445
446 bool success = false;
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000447 const uint32_t opcode = OpcodeAsUnsigned (&success);
Johnny Chen1c13b622011-01-29 00:11:15 +0000448 if (!success)
449 return false;
450
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000451 if (ConditionPassed())
Johnny Chen1c13b622011-01-29 00:11:15 +0000452 {
453 uint32_t Rm; // the source register
454 uint32_t Rd; // the destination register
455 switch (encoding) {
456 case eEncodingT1:
457 Rm = Bits32(opcode, 6, 3);
458 Rd = Bits32(opcode, 2, 1); // bits(7) == 0
459 break;
460 default:
461 return false;
462 }
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000463 int32_t reg_value = ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + Rm, 0, &success);
Johnny Chen1c13b622011-01-29 00:11:15 +0000464 if (!success)
465 return false;
466
467 // The context specifies that Rm is to be moved into Rd.
468 EmulateInstruction::Context context = { EmulateInstruction::eContextRegisterPlusOffset,
469 eRegisterKindDWARF,
470 dwarf_r0 + Rm,
471 0 };
472
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000473 if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + Rd, reg_value))
Johnny Chen1c13b622011-01-29 00:11:15 +0000474 return false;
475 }
476 return true;
477}
478
Johnny Chen788e0552011-01-27 22:52:23 +0000479// PC relative immediate load into register, possibly followed by ADD (SP plus register).
480// LDR (literal)
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000481bool
482EmulateInstructionARM::EmulateLDRRdPCRelative (ARMEncoding encoding)
Johnny Chen788e0552011-01-27 22:52:23 +0000483{
484#if 0
485 // ARM pseudo code...
486 if (ConditionPassed())
487 {
488 EncodingSpecificOperations(); NullCheckIfThumbEE(15);
489 base = Align(PC,4);
490 address = if add then (base + imm32) else (base - imm32);
491 data = MemU[address,4];
492 if t == 15 then
493 if address<1:0> == 00 then LoadWritePC(data); else UNPREDICTABLE;
494 elsif UnalignedSupport() || address<1:0> = 00 then
495 R[t] = data;
496 else // Can only apply before ARMv7
497 if CurrentInstrSet() == InstrSet_ARM then
498 R[t] = ROR(data, 8*UInt(address<1:0>));
499 else
500 R[t] = bits(32) UNKNOWN;
501 }
502#endif
503
504 bool success = false;
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000505 const uint32_t opcode = OpcodeAsUnsigned (&success);
Johnny Chen788e0552011-01-27 22:52:23 +0000506 if (!success)
507 return false;
508
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000509 if (ConditionPassed())
Johnny Chen788e0552011-01-27 22:52:23 +0000510 {
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000511 const uint32_t pc = ReadRegisterUnsigned(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, 0, &success);
Johnny Chen788e0552011-01-27 22:52:23 +0000512 if (!success)
513 return false;
Johnny Chen809742e2011-01-28 00:32:27 +0000514
515 // PC relative immediate load context
516 EmulateInstruction::Context context = {EmulateInstruction::eContextRegisterPlusOffset,
517 eRegisterKindGeneric,
518 LLDB_REGNUM_GENERIC_PC,
519 0};
Johnny Chen788e0552011-01-27 22:52:23 +0000520 uint32_t Rd; // the destination register
521 uint32_t imm32; // immediate offset from the PC
522 addr_t addr; // the PC relative address
523 uint32_t data; // the literal data value from the PC relative load
524 switch (encoding) {
525 case eEncodingT1:
526 Rd = Bits32(opcode, 10, 8);
527 imm32 = Bits32(opcode, 7, 0) << 2; // imm32 = ZeroExtend(imm8:'00', 32);
528 addr = pc + 4 + imm32;
Johnny Chen809742e2011-01-28 00:32:27 +0000529 context.arg2 = 4 + imm32;
Johnny Chen788e0552011-01-27 22:52:23 +0000530 break;
531 default:
532 return false;
533 }
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000534 data = ReadMemoryUnsigned(context, addr, 4, 0, &success);
Johnny Chen788e0552011-01-27 22:52:23 +0000535 if (!success)
Johnny Chen809742e2011-01-28 00:32:27 +0000536 return false;
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000537 if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + Rd, data))
Johnny Chen788e0552011-01-27 22:52:23 +0000538 return false;
539 }
540 return true;
541}
542
Johnny Chen5b442b72011-01-27 19:34:30 +0000543// An add operation to adjust the SP.
Johnny Chenfdd179e2011-01-31 20:09:28 +0000544// ADD (SP plus immediate)
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000545bool
546EmulateInstructionARM::EmulateAddSPImmediate (ARMEncoding encoding)
Johnny Chenfdd179e2011-01-31 20:09:28 +0000547{
548#if 0
549 // ARM pseudo code...
550 if (ConditionPassed())
551 {
552 EncodingSpecificOperations();
553 (result, carry, overflow) = AddWithCarry(SP, imm32, 0’);
554 if d == 15 then // Can only occur for ARM encoding
555 ALUWritePC(result); // setflags is always FALSE here
556 else
557 R[d] = result;
558 if setflags then
559 APSR.N = result<31>;
560 APSR.Z = IsZeroBit(result);
561 APSR.C = carry;
562 APSR.V = overflow;
563 }
564#endif
565
566 bool success = false;
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000567 const uint32_t opcode = OpcodeAsUnsigned (&success);
Johnny Chenfdd179e2011-01-31 20:09:28 +0000568 if (!success)
569 return false;
570
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000571 if (ConditionPassed())
Johnny Chenfdd179e2011-01-31 20:09:28 +0000572 {
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000573 const addr_t sp = ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, 0, &success);
Johnny Chenfdd179e2011-01-31 20:09:28 +0000574 if (!success)
575 return false;
576 uint32_t imm32; // the immediate operand
577 switch (encoding) {
578 case eEncodingT2:
579 imm32 = ThumbImmScaled(opcode); // imm32 = ZeroExtend(imm7:'00', 32)
580 break;
581 default:
582 return false;
583 }
584 addr_t sp_offset = imm32;
585 addr_t addr = sp + sp_offset; // the adjusted stack pointer value
586
587 EmulateInstruction::Context context = { EmulateInstruction::eContextAdjustStackPointer,
588 eRegisterKindGeneric,
589 LLDB_REGNUM_GENERIC_SP,
590 sp_offset };
591
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000592 if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, addr))
Johnny Chenfdd179e2011-01-31 20:09:28 +0000593 return false;
594 }
595 return true;
596}
597
598// An add operation to adjust the SP.
Johnny Chen5b442b72011-01-27 19:34:30 +0000599// ADD (SP plus register)
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000600bool
601EmulateInstructionARM::EmulateAddSPRm (ARMEncoding encoding)
Johnny Chen5b442b72011-01-27 19:34:30 +0000602{
603#if 0
604 // ARM pseudo code...
605 if (ConditionPassed())
606 {
607 EncodingSpecificOperations();
608 shifted = Shift(R[m], shift_t, shift_n, APSR.C);
609 (result, carry, overflow) = AddWithCarry(SP, shifted, 0’);
610 if d == 15 then
611 ALUWritePC(result); // setflags is always FALSE here
612 else
613 R[d] = result;
614 if setflags then
615 APSR.N = result<31>;
616 APSR.Z = IsZeroBit(result);
617 APSR.C = carry;
618 APSR.V = overflow;
619 }
620#endif
621
622 bool success = false;
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000623 const uint32_t opcode = OpcodeAsUnsigned (&success);
Johnny Chen5b442b72011-01-27 19:34:30 +0000624 if (!success)
625 return false;
626
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000627 if (ConditionPassed())
Johnny Chen5b442b72011-01-27 19:34:30 +0000628 {
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000629 const addr_t sp = ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, 0, &success);
Johnny Chen5b442b72011-01-27 19:34:30 +0000630 if (!success)
631 return false;
632 uint32_t Rm; // the second operand
633 switch (encoding) {
634 case eEncodingT2:
635 Rm = Bits32(opcode, 6, 3);
636 break;
637 default:
638 return false;
639 }
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000640 int32_t reg_value = ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + Rm, 0, &success);
Johnny Chen5b442b72011-01-27 19:34:30 +0000641 if (!success)
642 return false;
643
644 addr_t addr = (int32_t)sp + reg_value; // the adjusted stack pointer value
645
646 EmulateInstruction::Context context = { EmulateInstruction::eContextAdjustStackPointer,
647 eRegisterKindGeneric,
648 LLDB_REGNUM_GENERIC_SP,
649 reg_value };
650
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000651 if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, addr))
Johnny Chen5b442b72011-01-27 19:34:30 +0000652 return false;
653 }
654 return true;
655}
656
Johnny Chen9b8d7832011-02-02 01:13:56 +0000657// Branch with Link and Exchange Instruction Sets (immediate) calls a subroutine
658// at a PC-relative address, and changes instruction set from ARM to Thumb, or
659// from Thumb to ARM.
660// BLX (immediate)
661bool
662EmulateInstructionARM::EmulateBLXImmediate (ARMEncoding encoding)
663{
664#if 0
665 // ARM pseudo code...
666 if (ConditionPassed())
667 {
668 EncodingSpecificOperations();
669 if CurrentInstrSet() == InstrSet_ARM then
670 LR = PC - 4;
671 else
672 LR = PC<31:1> : '1';
673 if targetInstrSet == InstrSet_ARM then
674 targetAddress = Align(PC,4) + imm32;
675 else
676 targetAddress = PC + imm32;
677 SelectInstrSet(targetInstrSet);
678 BranchWritePC(targetAddress);
679 }
680#endif
681
682 bool success = false;
683 const uint32_t opcode = OpcodeAsUnsigned (&success);
684 if (!success)
685 return false;
686
687 if (ConditionPassed())
688 {
689 EmulateInstruction::Context context = { EmulateInstruction::eContextRelativeBranchImmediate, 0, 0, 0};
690 const uint32_t pc = ReadRegisterUnsigned(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, 0, &success);
691 addr_t lr; // next instruction address
692 addr_t target; // target address
693 if (!success)
694 return false;
695 int32_t imm32; // PC-relative offset
696 switch (encoding) {
697 case eEncodingT2:
698 {
699 lr = (pc + 4) | 1u; // return address
700 uint32_t S = Bits32(opcode, 26, 26);
701 uint32_t imm10H = Bits32(opcode, 25, 16);
702 uint32_t J1 = Bits32(opcode, 13, 13);
703 uint32_t J2 = Bits32(opcode, 11, 11);
704 uint32_t imm10L = Bits32(opcode, 10, 1);
705 uint32_t I1 = !(J1 ^ S);
706 uint32_t I2 = !(J2 ^ S);
707 uint32_t imm25 = (S << 24) | (I1 << 23) | (I2 << 22) | (imm10H << 12) + (imm10L << 2);
708 imm32 = llvm::SignExtend32<25>(imm25);
709 target = (pc & 0xfffffffc) + 4 + imm32;
710 context.arg1 = eModeARM; // target instruction set
711 context.arg2 = 4 + imm32; // signed offset
712 break;
713 }
714 case eEncodingA2:
715 lr = pc + 4; // return address
716 imm32 = llvm::SignExtend32<26>(Bits32(opcode, 23, 0) << 2 | Bits32(opcode, 24, 24) << 1);
717 target = pc + 8 + imm32;
718 context.arg1 = eModeThumb; // target instruction set
719 context.arg2 = 8 + imm32; // signed offset
720 break;
721 default:
722 return false;
723 }
724 if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_RA, lr))
725 return false;
726 if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, target))
727 return false;
728 }
729 return true;
730}
731
732// Branch with Link and Exchange (register) calls a subroutine at an address and
733// instruction set specified by a register.
734// BLX (register)
735bool
736EmulateInstructionARM::EmulateBLXRm (ARMEncoding encoding)
737{
738#if 0
739 // ARM pseudo code...
740 if (ConditionPassed())
741 {
742 EncodingSpecificOperations();
743 target = R[m];
744 if CurrentInstrSet() == InstrSet_ARM then
745 next_instr_addr = PC - 4;
746 LR = next_instr_addr;
747 else
748 next_instr_addr = PC - 2;
749 LR = next_instr_addr<31:1> : 1’;
750 BXWritePC(target);
751 }
752#endif
753
754 bool success = false;
755 const uint32_t opcode = OpcodeAsUnsigned (&success);
756 if (!success)
757 return false;
758
759 if (ConditionPassed())
760 {
761 EmulateInstruction::Context context = { EmulateInstruction::eContextAbsoluteBranchRegister, 0, 0, 0};
762 const uint32_t pc = ReadRegisterUnsigned(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, 0, &success);
763 addr_t lr; // next instruction address
764 addr_t target; // target address
765 if (!success)
766 return false;
767 uint32_t Rm; // the register with the target address
768 switch (encoding) {
769 case eEncodingT1:
770 lr = (pc + 2) | 1u; // return address
771 Rm = Bits32(opcode, 6, 3);
772 // if m == 15 then UNPREDICTABLE;
773 if (Rm == 15)
774 return false;
775 target = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + Rm, 0, &success);
776 break;
777 case eEncodingA1:
778 lr = pc + 4; // return address
779 Rm = Bits32(opcode, 3, 0);
780 // if m == 15 then UNPREDICTABLE;
781 if (Rm == 15)
782 return false;
783 target = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + Rm, 0, &success);
784 default:
785 return false;
786 }
787 bool toThumb;
788 if (BitIsSet(target, 0))
789 toThumb = true;
790 else if (BitIsClear(target, 1))
791 toThumb = false;
792 else
793 return false; // address<1:0> == ‘10’ => UNPREDICTABLE
794 context.arg0 = eRegisterKindDWARF;
795 context.arg1 = dwarf_r0 + Rm;
796 context.arg2 = toThumb ? eModeThumb : eModeARM;
797 if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_RA, lr))
798 return false;
799 if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, target))
800 return false;
801 }
802 return true;
803}
804
Johnny Chen0d0148e2011-01-28 02:26:08 +0000805// Set r7 to point to some ip offset.
806// SUB (immediate)
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000807bool
808EmulateInstructionARM::EmulateSubR7IPImmediate (ARMEncoding encoding)
Johnny Chen0d0148e2011-01-28 02:26:08 +0000809{
810#if 0
811 // ARM pseudo code...
812 if (ConditionPassed())
813 {
814 EncodingSpecificOperations();
815 (result, carry, overflow) = AddWithCarry(SP, NOT(imm32), 1’);
816 if d == 15 then // Can only occur for ARM encoding
817 ALUWritePC(result); // setflags is always FALSE here
818 else
819 R[d] = result;
820 if setflags then
821 APSR.N = result<31>;
822 APSR.Z = IsZeroBit(result);
823 APSR.C = carry;
824 APSR.V = overflow;
825 }
826#endif
827
828 bool success = false;
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000829 const uint32_t opcode = OpcodeAsUnsigned (&success);
Johnny Chen0d0148e2011-01-28 02:26:08 +0000830 if (!success)
831 return false;
832
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000833 if (ConditionPassed())
Johnny Chen0d0148e2011-01-28 02:26:08 +0000834 {
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000835 const addr_t ip = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r12, 0, &success);
Johnny Chen0d0148e2011-01-28 02:26:08 +0000836 if (!success)
837 return false;
838 uint32_t imm32;
839 switch (encoding) {
840 case eEncodingA1:
841 imm32 = ARMExpandImm(opcode); // imm32 = ARMExpandImm(imm12)
842 break;
843 default:
844 return false;
845 }
846 addr_t ip_offset = imm32;
847 addr_t addr = ip - ip_offset; // the adjusted ip value
848
849 EmulateInstruction::Context context = { EmulateInstruction::eContextRegisterPlusOffset,
850 eRegisterKindDWARF,
851 dwarf_r12,
852 -ip_offset };
853
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000854 if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r7, addr))
Johnny Chen0d0148e2011-01-28 02:26:08 +0000855 return false;
856 }
857 return true;
858}
859
860// Set ip to point to some stack offset.
861// SUB (SP minus immediate)
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000862bool
863EmulateInstructionARM::EmulateSubIPSPImmediate (ARMEncoding encoding)
Johnny Chen0d0148e2011-01-28 02:26:08 +0000864{
865#if 0
866 // ARM pseudo code...
867 if (ConditionPassed())
868 {
869 EncodingSpecificOperations();
870 (result, carry, overflow) = AddWithCarry(SP, NOT(imm32), 1’);
871 if d == 15 then // Can only occur for ARM encoding
872 ALUWritePC(result); // setflags is always FALSE here
873 else
874 R[d] = result;
875 if setflags then
876 APSR.N = result<31>;
877 APSR.Z = IsZeroBit(result);
878 APSR.C = carry;
879 APSR.V = overflow;
880 }
881#endif
882
883 bool success = false;
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000884 const uint32_t opcode = OpcodeAsUnsigned (&success);
Johnny Chen0d0148e2011-01-28 02:26:08 +0000885 if (!success)
886 return false;
887
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000888 if (ConditionPassed())
Johnny Chen0d0148e2011-01-28 02:26:08 +0000889 {
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000890 const addr_t sp = ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, 0, &success);
Johnny Chen0d0148e2011-01-28 02:26:08 +0000891 if (!success)
892 return false;
893 uint32_t imm32;
894 switch (encoding) {
895 case eEncodingA1:
896 imm32 = ARMExpandImm(opcode); // imm32 = ARMExpandImm(imm12)
897 break;
898 default:
899 return false;
900 }
901 addr_t sp_offset = imm32;
902 addr_t addr = sp - sp_offset; // the adjusted stack pointer value
903
904 EmulateInstruction::Context context = { EmulateInstruction::eContextRegisterPlusOffset,
905 eRegisterKindGeneric,
906 LLDB_REGNUM_GENERIC_SP,
907 -sp_offset };
908
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000909 if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r12, addr))
Johnny Chen0d0148e2011-01-28 02:26:08 +0000910 return false;
911 }
912 return true;
913}
914
Johnny Chen4c0e0bc2011-01-25 22:45:28 +0000915// A sub operation to adjust the SP -- allocate space for local storage.
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000916bool
917EmulateInstructionARM::EmulateSubSPImmdiate (ARMEncoding encoding)
Johnny Chen4c0e0bc2011-01-25 22:45:28 +0000918{
919#if 0
920 // ARM pseudo code...
921 if (ConditionPassed())
922 {
923 EncodingSpecificOperations();
924 (result, carry, overflow) = AddWithCarry(SP, NOT(imm32), 1’);
925 if d == 15 then // Can only occur for ARM encoding
Johnny Chen799dfd02011-01-26 23:14:33 +0000926 ALUWritePC(result); // setflags is always FALSE here
Johnny Chen4c0e0bc2011-01-25 22:45:28 +0000927 else
928 R[d] = result;
929 if setflags then
930 APSR.N = result<31>;
931 APSR.Z = IsZeroBit(result);
932 APSR.C = carry;
933 APSR.V = overflow;
934 }
935#endif
936
937 bool success = false;
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000938 const uint32_t opcode = OpcodeAsUnsigned (&success);
Johnny Chen4c0e0bc2011-01-25 22:45:28 +0000939 if (!success)
940 return false;
941
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000942 if (ConditionPassed())
Johnny Chen4c0e0bc2011-01-25 22:45:28 +0000943 {
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000944 const addr_t sp = ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, 0, &success);
Johnny Chen4c0e0bc2011-01-25 22:45:28 +0000945 if (!success)
946 return false;
947 uint32_t imm32;
948 switch (encoding) {
Johnny Chene4455022011-01-26 00:08:59 +0000949 case eEncodingT1:
950 imm32 = ThumbImmScaled(opcode); // imm32 = ZeroExtend(imm7:'00', 32)
Johnny Chen60c0d622011-01-25 23:49:39 +0000951 case eEncodingT2:
952 imm32 = ThumbExpandImm(opcode); // imm32 = ThumbExpandImm(i:imm3:imm8)
953 break;
954 case eEncodingT3:
955 imm32 = ThumbImm12(opcode); // imm32 = ZeroExtend(i:imm3:imm8, 32)
956 break;
Johnny Chen4c0e0bc2011-01-25 22:45:28 +0000957 case eEncodingA1:
Johnny Chen60c0d622011-01-25 23:49:39 +0000958 imm32 = ARMExpandImm(opcode); // imm32 = ARMExpandImm(imm12)
Johnny Chen4c0e0bc2011-01-25 22:45:28 +0000959 break;
960 default:
961 return false;
962 }
963 addr_t sp_offset = imm32;
964 addr_t addr = sp - sp_offset; // the adjusted stack pointer value
965
966 EmulateInstruction::Context context = { EmulateInstruction::eContextAdjustStackPointer,
967 eRegisterKindGeneric,
968 LLDB_REGNUM_GENERIC_SP,
Johnny Chen5b442b72011-01-27 19:34:30 +0000969 -sp_offset };
Johnny Chen4c0e0bc2011-01-25 22:45:28 +0000970
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000971 if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, addr))
Johnny Chen4c0e0bc2011-01-25 22:45:28 +0000972 return false;
973 }
974 return true;
975}
976
Johnny Chen08c25e82011-01-31 18:02:28 +0000977// A store operation to the stack that also updates the SP.
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000978bool
979EmulateInstructionARM::EmulateSTRRtSP (ARMEncoding encoding)
Johnny Chence1ca772011-01-25 01:13:00 +0000980{
981#if 0
982 // ARM pseudo code...
983 if (ConditionPassed())
984 {
985 EncodingSpecificOperations();
986 offset_addr = if add then (R[n] + imm32) else (R[n] - imm32);
987 address = if index then offset_addr else R[n];
988 MemU[address,4] = if t == 15 then PCStoreValue() else R[t];
989 if wback then R[n] = offset_addr;
990 }
991#endif
992
993 bool success = false;
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000994 const uint32_t opcode = OpcodeAsUnsigned (&success);
Johnny Chence1ca772011-01-25 01:13:00 +0000995 if (!success)
996 return false;
997
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000998 if (ConditionPassed())
Johnny Chence1ca772011-01-25 01:13:00 +0000999 {
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001000 const uint32_t addr_byte_size = GetAddressByteSize();
1001 const addr_t sp = ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, 0, &success);
Johnny Chence1ca772011-01-25 01:13:00 +00001002 if (!success)
1003 return false;
Johnny Chen91d99862011-01-25 19:07:04 +00001004 uint32_t Rt; // the source register
Johnny Chence1ca772011-01-25 01:13:00 +00001005 uint32_t imm12;
1006 switch (encoding) {
1007 case eEncodingA1:
Johnny Chen108d5aa2011-01-26 01:00:55 +00001008 Rt = Bits32(opcode, 15, 12);
1009 imm12 = Bits32(opcode, 11, 0);
Johnny Chence1ca772011-01-25 01:13:00 +00001010 break;
1011 default:
1012 return false;
1013 }
1014 addr_t sp_offset = imm12;
1015 addr_t addr = sp - sp_offset;
1016
1017 EmulateInstruction::Context context = { EmulateInstruction::eContextPushRegisterOnStack, eRegisterKindDWARF, 0, 0 };
Johnny Chen91d99862011-01-25 19:07:04 +00001018 if (Rt != 15)
Johnny Chence1ca772011-01-25 01:13:00 +00001019 {
Johnny Chen91d99862011-01-25 19:07:04 +00001020 context.arg1 = dwarf_r0 + Rt; // arg1 in the context is the DWARF register number
1021 context.arg2 = addr - sp; // arg2 in the context is the stack pointer offset
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001022 uint32_t reg_value = ReadRegisterUnsigned(eRegisterKindDWARF, context.arg1, 0, &success);
Johnny Chence1ca772011-01-25 01:13:00 +00001023 if (!success)
1024 return false;
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001025 if (!WriteMemoryUnsigned (context, addr, reg_value, addr_byte_size))
Johnny Chence1ca772011-01-25 01:13:00 +00001026 return false;
1027 }
1028 else
1029 {
1030 context.arg1 = dwarf_pc; // arg1 in the context is the DWARF register number
1031 context.arg2 = addr - sp; // arg2 in the context is the stack pointer offset
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001032 const uint32_t pc = ReadRegisterUnsigned(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, 0, &success);
Johnny Chence1ca772011-01-25 01:13:00 +00001033 if (!success)
1034 return false;
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001035 if (!WriteMemoryUnsigned (context, addr, pc + 8, addr_byte_size))
Johnny Chence1ca772011-01-25 01:13:00 +00001036 return false;
1037 }
1038
1039 context.type = EmulateInstruction::eContextAdjustStackPointer;
1040 context.arg0 = eRegisterKindGeneric;
1041 context.arg1 = LLDB_REGNUM_GENERIC_SP;
Johnny Chen5b442b72011-01-27 19:34:30 +00001042 context.arg2 = -sp_offset;
Johnny Chence1ca772011-01-25 01:13:00 +00001043
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001044 if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, sp - sp_offset))
Johnny Chence1ca772011-01-25 01:13:00 +00001045 return false;
1046 }
1047 return true;
1048}
1049
Johnny Chen08c25e82011-01-31 18:02:28 +00001050// Vector Push stores multiple extension registers to the stack.
1051// It also updates SP to point to the start of the stored data.
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001052bool
1053EmulateInstructionARM::EmulateVPUSH (ARMEncoding encoding)
Johnny Chen799dfd02011-01-26 23:14:33 +00001054{
1055#if 0
1056 // ARM pseudo code...
1057 if (ConditionPassed())
1058 {
1059 EncodingSpecificOperations(); CheckVFPEnabled(TRUE); NullCheckIfThumbEE(13);
1060 address = SP - imm32;
1061 SP = SP - imm32;
1062 if single_regs then
1063 for r = 0 to regs-1
1064 MemA[address,4] = S[d+r]; address = address+4;
1065 else
1066 for r = 0 to regs-1
1067 // Store as two word-aligned words in the correct order for current endianness.
1068 MemA[address,4] = if BigEndian() then D[d+r]<63:32> else D[d+r]<31:0>;
1069 MemA[address+4,4] = if BigEndian() then D[d+r]<31:0> else D[d+r]<63:32>;
1070 address = address+8;
1071 }
1072#endif
1073
1074 bool success = false;
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001075 const uint32_t opcode = OpcodeAsUnsigned (&success);
Johnny Chen799dfd02011-01-26 23:14:33 +00001076 if (!success)
1077 return false;
1078
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001079 if (ConditionPassed())
Johnny Chen799dfd02011-01-26 23:14:33 +00001080 {
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001081 const uint32_t addr_byte_size = GetAddressByteSize();
1082 const addr_t sp = ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, 0, &success);
Johnny Chen799dfd02011-01-26 23:14:33 +00001083 if (!success)
1084 return false;
1085 bool single_regs;
Johnny Chen587a0a42011-02-01 18:35:28 +00001086 uint32_t d; // UInt(D:Vd) or UInt(Vd:D) starting register
Johnny Chen799dfd02011-01-26 23:14:33 +00001087 uint32_t imm32; // stack offset
1088 uint32_t regs; // number of registers
1089 switch (encoding) {
1090 case eEncodingT1:
1091 case eEncodingA1:
1092 single_regs = false;
Johnny Chen587a0a42011-02-01 18:35:28 +00001093 d = Bits32(opcode, 22, 22) << 4 | Bits32(opcode, 15, 12);
Johnny Chen799dfd02011-01-26 23:14:33 +00001094 imm32 = Bits32(opcode, 7, 0) * addr_byte_size;
1095 // If UInt(imm8) is odd, see "FSTMX".
1096 regs = Bits32(opcode, 7, 0) / 2;
1097 // if regs == 0 || regs > 16 || (d+regs) > 32 then UNPREDICTABLE;
1098 if (regs == 0 || regs > 16 || (d + regs) > 32)
1099 return false;
1100 break;
1101 case eEncodingT2:
1102 case eEncodingA2:
1103 single_regs = true;
1104 d = Bits32(opcode, 15, 12) << 1 | Bits32(opcode, 22, 22);
1105 imm32 = Bits32(opcode, 7, 0) * addr_byte_size;
1106 regs = Bits32(opcode, 7, 0);
1107 // if regs == 0 || regs > 16 || (d+regs) > 32 then UNPREDICTABLE;
1108 if (regs == 0 || regs > 16 || (d + regs) > 32)
1109 return false;
1110 break;
1111 default:
1112 return false;
1113 }
1114 uint32_t start_reg = single_regs ? dwarf_s0 : dwarf_d0;
1115 uint32_t reg_byte_size = single_regs ? addr_byte_size : addr_byte_size * 2;
1116 addr_t sp_offset = imm32;
1117 addr_t addr = sp - sp_offset;
1118 uint32_t i;
1119
1120 EmulateInstruction::Context context = { EmulateInstruction::eContextPushRegisterOnStack, eRegisterKindDWARF, 0, 0 };
1121 for (i=d; i<regs; ++i)
1122 {
1123 context.arg1 = start_reg + i; // arg1 in the context is the DWARF register number
1124 context.arg2 = addr - sp; // arg2 in the context is the stack pointer offset
1125 // uint64_t to accommodate 64-bit registers.
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001126 uint64_t reg_value = ReadRegisterUnsigned(eRegisterKindDWARF, context.arg1, 0, &success);
Johnny Chen799dfd02011-01-26 23:14:33 +00001127 if (!success)
1128 return false;
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001129 if (!WriteMemoryUnsigned (context, addr, reg_value, reg_byte_size))
Johnny Chen799dfd02011-01-26 23:14:33 +00001130 return false;
1131 addr += reg_byte_size;
1132 }
1133
1134 context.type = EmulateInstruction::eContextAdjustStackPointer;
1135 context.arg0 = eRegisterKindGeneric;
1136 context.arg1 = LLDB_REGNUM_GENERIC_SP;
Johnny Chen5b442b72011-01-27 19:34:30 +00001137 context.arg2 = -sp_offset;
Johnny Chen799dfd02011-01-26 23:14:33 +00001138
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001139 if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, sp - sp_offset))
Johnny Chen799dfd02011-01-26 23:14:33 +00001140 return false;
1141 }
1142 return true;
1143}
1144
Johnny Chen587a0a42011-02-01 18:35:28 +00001145// Vector Pop loads multiple extension registers from the stack.
1146// It also updates SP to point just above the loaded data.
1147bool
1148EmulateInstructionARM::EmulateVPOP (ARMEncoding encoding)
1149{
1150#if 0
1151 // ARM pseudo code...
1152 if (ConditionPassed())
1153 {
1154 EncodingSpecificOperations(); CheckVFPEnabled(TRUE); NullCheckIfThumbEE(13);
1155 address = SP;
1156 SP = SP + imm32;
1157 if single_regs then
1158 for r = 0 to regs-1
1159 S[d+r] = MemA[address,4]; address = address+4;
1160 else
1161 for r = 0 to regs-1
1162 word1 = MemA[address,4]; word2 = MemA[address+4,4]; address = address+8;
1163 // Combine the word-aligned words in the correct order for current endianness.
1164 D[d+r] = if BigEndian() then word1:word2 else word2:word1;
1165 }
1166#endif
1167
1168 bool success = false;
1169 const uint32_t opcode = OpcodeAsUnsigned (&success);
1170 if (!success)
1171 return false;
1172
1173 if (ConditionPassed())
1174 {
1175 const uint32_t addr_byte_size = GetAddressByteSize();
1176 const addr_t sp = ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, 0, &success);
1177 if (!success)
1178 return false;
1179 bool single_regs;
1180 uint32_t d; // UInt(D:Vd) or UInt(Vd:D) starting register
1181 uint32_t imm32; // stack offset
1182 uint32_t regs; // number of registers
1183 switch (encoding) {
1184 case eEncodingT1:
1185 case eEncodingA1:
1186 single_regs = false;
1187 d = Bits32(opcode, 22, 22) << 4 | Bits32(opcode, 15, 12);
1188 imm32 = Bits32(opcode, 7, 0) * addr_byte_size;
1189 // If UInt(imm8) is odd, see "FLDMX".
1190 regs = Bits32(opcode, 7, 0) / 2;
1191 // if regs == 0 || regs > 16 || (d+regs) > 32 then UNPREDICTABLE;
1192 if (regs == 0 || regs > 16 || (d + regs) > 32)
1193 return false;
1194 break;
1195 case eEncodingT2:
1196 case eEncodingA2:
1197 single_regs = true;
1198 d = Bits32(opcode, 15, 12) << 1 | Bits32(opcode, 22, 22);
1199 imm32 = Bits32(opcode, 7, 0) * addr_byte_size;
1200 regs = Bits32(opcode, 7, 0);
1201 // if regs == 0 || regs > 16 || (d+regs) > 32 then UNPREDICTABLE;
1202 if (regs == 0 || regs > 16 || (d + regs) > 32)
1203 return false;
1204 break;
1205 default:
1206 return false;
1207 }
1208 uint32_t start_reg = single_regs ? dwarf_s0 : dwarf_d0;
1209 uint32_t reg_byte_size = single_regs ? addr_byte_size : addr_byte_size * 2;
1210 addr_t sp_offset = imm32;
1211 addr_t addr = sp;
1212 uint32_t i;
1213 uint64_t data; // uint64_t to accomodate 64-bit registers.
1214
1215 EmulateInstruction::Context context = { EmulateInstruction::eContextPopRegisterOffStack, eRegisterKindDWARF, 0, 0 };
1216 for (i=d; i<regs; ++i)
1217 {
1218 context.arg1 = start_reg + i; // arg1 in the context is the DWARF register number
1219 context.arg2 = addr - sp; // arg2 in the context is the stack pointer offset
1220 data = ReadMemoryUnsigned(context, addr, reg_byte_size, 0, &success);
1221 if (!success)
1222 return false;
1223 if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, context.arg1, data))
1224 return false;
1225 addr += reg_byte_size;
1226 }
1227
1228 context.type = EmulateInstruction::eContextAdjustStackPointer;
1229 context.arg0 = eRegisterKindGeneric;
1230 context.arg1 = LLDB_REGNUM_GENERIC_SP;
1231 context.arg2 = sp_offset;
1232
1233 if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, sp + sp_offset))
1234 return false;
1235 }
1236 return true;
1237}
1238
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001239EmulateInstructionARM::ARMOpcode*
1240EmulateInstructionARM::GetARMOpcodeForInstruction (const uint32_t opcode)
Greg Clayton64c84432011-01-21 22:02:52 +00001241{
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001242 static ARMOpcode
1243 g_arm_opcodes[] =
1244 {
1245 //----------------------------------------------------------------------
1246 // Prologue instructions
1247 //----------------------------------------------------------------------
Johnny Chenfdd179e2011-01-31 20:09:28 +00001248
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001249 // push register(s)
Johnny Chenc28a76d2011-02-01 18:51:48 +00001250 { 0x0fff0000, 0x092d0000, ARMvAll, eEncodingA1, eSize32, &EmulateInstructionARM::EmulatePush, "push <registers>" },
1251 { 0x0fff0fff, 0x052d0004, ARMvAll, eEncodingA2, eSize32, &EmulateInstructionARM::EmulatePush, "push <register>" },
Johnny Chenbcec3af2011-01-27 01:26:19 +00001252
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001253 // set r7 to point to a stack offset
Johnny Chenc28a76d2011-02-01 18:51:48 +00001254 { 0x0ffff000, 0x028d7000, ARMvAll, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateAddRdSPImmediate, "add r7, sp, #<const>" },
1255 { 0x0ffff000, 0x024c7000, ARMvAll, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateSubR7IPImmediate, "sub r7, ip, #<const>"},
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001256 // set ip to point to a stack offset
Johnny Chenc28a76d2011-02-01 18:51:48 +00001257 { 0x0fffffff, 0x01a0c00d, ARMvAll, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateMovRdSP, "mov ip, sp" },
1258 { 0x0ffff000, 0x028dc000, ARMvAll, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateAddRdSPImmediate, "add ip, sp, #<const>" },
1259 { 0x0ffff000, 0x024dc000, ARMvAll, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateSubIPSPImmediate, "sub ip, sp, #<const>"},
Johnny Chen4c0e0bc2011-01-25 22:45:28 +00001260
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001261 // adjust the stack pointer
Johnny Chenc28a76d2011-02-01 18:51:48 +00001262 { 0x0ffff000, 0x024dd000, ARMvAll, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateSubSPImmdiate, "sub sp, sp, #<const>"},
Johnny Chence1ca772011-01-25 01:13:00 +00001263
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001264 // push one register
1265 // if Rn == '1101' && imm12 == '000000000100' then SEE PUSH;
Johnny Chenc28a76d2011-02-01 18:51:48 +00001266 { 0x0fff0000, 0x052d0000, ARMvAll, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateSTRRtSP, "str Rt, [sp, #-imm12]!" },
Johnny Chen799dfd02011-01-26 23:14:33 +00001267
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001268 // vector push consecutive extension register(s)
Johnny Chen9b8d7832011-02-02 01:13:56 +00001269 { 0x0fbf0f00, 0x0d2d0b00, ARMV6T2_ABOVE, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateVPUSH, "vpush.64 <list>"},
1270 { 0x0fbf0f00, 0x0d2d0a00, ARMV6T2_ABOVE, eEncodingA2, eSize32, &EmulateInstructionARM::EmulateVPUSH, "vpush.32 <list>"},
Johnny Chenef85e912011-01-31 23:07:40 +00001271
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001272 //----------------------------------------------------------------------
Johnny Chen587a0a42011-02-01 18:35:28 +00001273 // Epilogue instructions
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001274 //----------------------------------------------------------------------
Johnny Chenef85e912011-01-31 23:07:40 +00001275
Johnny Chen9b8d7832011-02-02 01:13:56 +00001276 // To resolve ambiguity, "blx <label>" should come before "bl <label>".
1277 { 0xfe000000, 0xfa000000, ARMV5_ABOVE, eEncodingA2, eSize32, &EmulateInstructionARM::EmulateBLXImmediate, "blx <label>"},
1278 { 0x0f000000, 0x0b000000, ARMvAll, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateBLXImmediate, "bl <label>"},
1279 { 0x0ffffff0, 0x012fff30, ARMV5_ABOVE, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateBLXRm, "blx <Rm>"},
Johnny Chenc28a76d2011-02-01 18:51:48 +00001280 { 0x0fff0000, 0x08bd0000, ARMvAll, eEncodingA1, eSize32, &EmulateInstructionARM::EmulatePop, "pop <registers>"},
1281 { 0x0fff0fff, 0x049d0004, ARMvAll, eEncodingA2, eSize32, &EmulateInstructionARM::EmulatePop, "pop <register>"},
Johnny Chen9b8d7832011-02-02 01:13:56 +00001282 { 0x0fbf0f00, 0x0cbd0b00, ARMV6T2_ABOVE, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateVPOP, "vpop.64 <list>"},
1283 { 0x0fbf0f00, 0x0cbd0a00, ARMV6T2_ABOVE, eEncodingA2, eSize32, &EmulateInstructionARM::EmulateVPOP, "vpop.32 <list>"}
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001284 };
1285 static const size_t k_num_arm_opcodes = sizeof(g_arm_opcodes)/sizeof(ARMOpcode);
1286
1287 for (size_t i=0; i<k_num_arm_opcodes; ++i)
1288 {
1289 if ((g_arm_opcodes[i].mask & opcode) == g_arm_opcodes[i].value)
1290 return &g_arm_opcodes[i];
1291 }
1292 return NULL;
1293}
Greg Clayton64c84432011-01-21 22:02:52 +00001294
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001295
1296EmulateInstructionARM::ARMOpcode*
1297EmulateInstructionARM::GetThumbOpcodeForInstruction (const uint32_t opcode)
Johnny Chen347320d2011-01-24 23:40:59 +00001298{
Johnny Chenfdd179e2011-01-31 20:09:28 +00001299
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001300 static ARMOpcode
1301 g_thumb_opcodes[] =
1302 {
1303 //----------------------------------------------------------------------
1304 // Prologue instructions
1305 //----------------------------------------------------------------------
Johnny Chenbcec3af2011-01-27 01:26:19 +00001306
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001307 // push register(s)
Johnny Chenc28a76d2011-02-01 18:51:48 +00001308 { 0xfffffe00, 0x0000b400, ARMvAll, eEncodingT1, eSize16, &EmulateInstructionARM::EmulatePush, "push <registers>" },
1309 { 0xffff0000, 0xe92d0000, ARMv6T2|ARMv7, eEncodingT2, eSize32, &EmulateInstructionARM::EmulatePush, "push.w <registers>" },
1310 { 0xffff0fff, 0xf84d0d04, ARMv6T2|ARMv7, eEncodingT3, eSize32, &EmulateInstructionARM::EmulatePush, "push.w <register>" },
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001311 // move from high register to low register
Johnny Chenc28a76d2011-02-01 18:51:48 +00001312 { 0xffffffc0, 0x00004640, ARMvAll, eEncodingT1, eSize16, &EmulateInstructionARM::EmulateMovLowHigh, "mov r0-r7, r8-r15" },
Johnny Chen788e0552011-01-27 22:52:23 +00001313
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001314 // set r7 to point to a stack offset
Johnny Chenc28a76d2011-02-01 18:51:48 +00001315 { 0xffffff00, 0x0000af00, ARMvAll, eEncodingT1, eSize16, &EmulateInstructionARM::EmulateAddRdSPImmediate, "add r7, sp, #imm" },
1316 { 0xffffffff, 0x0000466f, ARMvAll, eEncodingT1, eSize16, &EmulateInstructionARM::EmulateMovRdSP, "mov r7, sp" },
Johnny Chen60c0d622011-01-25 23:49:39 +00001317
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001318 // PC relative load into register (see also EmulateAddSPRm)
Johnny Chenc28a76d2011-02-01 18:51:48 +00001319 { 0xfffff800, 0x00004800, ARMvAll, eEncodingT1, eSize16, &EmulateInstructionARM::EmulateLDRRdPCRelative, "ldr <Rd>, [PC, #imm]"},
Johnny Chen799dfd02011-01-26 23:14:33 +00001320
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001321 // adjust the stack pointer
Johnny Chenc28a76d2011-02-01 18:51:48 +00001322 { 0xffffff87, 0x00004485, ARMvAll, eEncodingT2, eSize16, &EmulateInstructionARM::EmulateAddSPRm, "add sp, <Rm>"},
1323 { 0xffffff80, 0x0000b080, ARMvAll, eEncodingT1, eSize16, &EmulateInstructionARM::EmulateSubSPImmdiate, "add sp, sp, #imm"},
1324 { 0xfbef8f00, 0xf1ad0d00, ARMv6T2|ARMv7, eEncodingT2, eSize32, &EmulateInstructionARM::EmulateSubSPImmdiate, "sub.w sp, sp, #<const>"},
1325 { 0xfbff8f00, 0xf2ad0d00, ARMv6T2|ARMv7, eEncodingT3, eSize32, &EmulateInstructionARM::EmulateSubSPImmdiate, "subw sp, sp, #imm12"},
Johnny Chenfdd179e2011-01-31 20:09:28 +00001326
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001327 // vector push consecutive extension register(s)
Johnny Chenc28a76d2011-02-01 18:51:48 +00001328 { 0xffbf0f00, 0xed2d0b00, ARMv6T2|ARMv7, eEncodingT1, eSize32, &EmulateInstructionARM::EmulateVPUSH, "vpush.64 <list>"},
1329 { 0xffbf0f00, 0xed2d0a00, ARMv6T2|ARMv7, eEncodingT2, eSize32, &EmulateInstructionARM::EmulateVPUSH, "vpush.32 <list>"},
Johnny Chenfdd179e2011-01-31 20:09:28 +00001330
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001331 //----------------------------------------------------------------------
1332 // Epilogue instructions
1333 //----------------------------------------------------------------------
Johnny Chen347320d2011-01-24 23:40:59 +00001334
Johnny Chenc28a76d2011-02-01 18:51:48 +00001335 { 0xffffff80, 0x0000b000, ARMvAll, eEncodingT2, eSize16, &EmulateInstructionARM::EmulateAddSPImmediate, "add sp, #imm"},
Johnny Chen9b8d7832011-02-02 01:13:56 +00001336 { 0xffffff87, 0x00004780, ARMV5_ABOVE, eEncodingT1, eSize16, &EmulateInstructionARM::EmulateBLXRm, "blx <Rm>"},
1337 // J1 == J2 == 1
1338 { 0xf800e801, 0xf000e800, ARMV5_ABOVE, eEncodingT2, eSize32, &EmulateInstructionARM::EmulateBLXImmediate, "blx <label>"},
Johnny Chenc28a76d2011-02-01 18:51:48 +00001339 { 0xfffffe00, 0x0000bc00, ARMvAll, eEncodingT1, eSize16, &EmulateInstructionARM::EmulatePop, "pop <registers>"},
1340 { 0xffff0000, 0xe8bd0000, ARMv6T2|ARMv7, eEncodingT2, eSize32, &EmulateInstructionARM::EmulatePop, "pop.w <registers>" },
1341 { 0xffff0fff, 0xf85d0d04, ARMv6T2|ARMv7, eEncodingT3, eSize32, &EmulateInstructionARM::EmulatePop, "pop.w <register>" },
1342 { 0xffbf0f00, 0xecbd0b00, ARMv6T2|ARMv7, eEncodingT1, eSize32, &EmulateInstructionARM::EmulateVPOP, "vpop.64 <list>"},
1343 { 0xffbf0f00, 0xecbd0a00, ARMv6T2|ARMv7, eEncodingT2, eSize32, &EmulateInstructionARM::EmulateVPOP, "vpop.32 <list>"}
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001344 };
1345
1346 const size_t k_num_thumb_opcodes = sizeof(g_thumb_opcodes)/sizeof(ARMOpcode);
1347 for (size_t i=0; i<k_num_thumb_opcodes; ++i)
1348 {
1349 if ((g_thumb_opcodes[i].mask & opcode) == g_thumb_opcodes[i].value)
1350 return &g_thumb_opcodes[i];
1351 }
1352 return NULL;
1353}
Greg Clayton64c84432011-01-21 22:02:52 +00001354
Greg Clayton31e2a382011-01-30 20:03:56 +00001355bool
1356EmulateInstructionARM::SetTargetTriple (const ConstString &triple)
1357{
1358 m_arm_isa = 0;
1359 const char *triple_cstr = triple.GetCString();
1360 if (triple_cstr)
1361 {
1362 const char *dash = ::strchr (triple_cstr, '-');
1363 if (dash)
1364 {
1365 std::string arch (triple_cstr, dash);
1366 const char *arch_cstr = arch.c_str();
1367 if (strcasecmp(arch_cstr, "armv4t") == 0)
1368 m_arm_isa = ARMv4T;
1369 else if (strcasecmp(arch_cstr, "armv4") == 0)
1370 m_arm_isa = ARMv4;
1371 else if (strcasecmp(arch_cstr, "armv5tej") == 0)
1372 m_arm_isa = ARMv5TEJ;
1373 else if (strcasecmp(arch_cstr, "armv5te") == 0)
1374 m_arm_isa = ARMv5TE;
1375 else if (strcasecmp(arch_cstr, "armv5t") == 0)
1376 m_arm_isa = ARMv5T;
1377 else if (strcasecmp(arch_cstr, "armv6k") == 0)
1378 m_arm_isa = ARMv6K;
1379 else if (strcasecmp(arch_cstr, "armv6") == 0)
1380 m_arm_isa = ARMv6;
1381 else if (strcasecmp(arch_cstr, "armv6t2") == 0)
1382 m_arm_isa = ARMv6T2;
1383 else if (strcasecmp(arch_cstr, "armv7") == 0)
1384 m_arm_isa = ARMv7;
1385 else if (strcasecmp(arch_cstr, "armv8") == 0)
1386 m_arm_isa = ARMv8;
1387 }
1388 }
1389 return m_arm_isa != 0;
1390}
1391
1392
Greg Clayton64c84432011-01-21 22:02:52 +00001393bool
1394EmulateInstructionARM::ReadInstruction ()
1395{
1396 bool success = false;
1397 m_inst_cpsr = ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FLAGS, 0, &success);
1398 if (success)
1399 {
1400 addr_t pc = ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, LLDB_INVALID_ADDRESS, &success);
1401 if (success)
1402 {
1403 Context read_inst_context = {eContextReadOpcode, 0, 0};
1404 if (m_inst_cpsr & MASK_CPSR_T)
1405 {
1406 m_inst_mode = eModeThumb;
1407 uint32_t thumb_opcode = ReadMemoryUnsigned(read_inst_context, pc, 2, 0, &success);
1408
1409 if (success)
1410 {
1411 if ((m_inst.opcode.inst16 & 0xe000) != 0xe000 || ((m_inst.opcode.inst16 & 0x1800u) == 0))
1412 {
1413 m_inst.opcode_type = eOpcode16;
1414 m_inst.opcode.inst16 = thumb_opcode;
1415 }
1416 else
1417 {
1418 m_inst.opcode_type = eOpcode32;
1419 m_inst.opcode.inst32 = (thumb_opcode << 16) | ReadMemoryUnsigned(read_inst_context, pc + 2, 2, 0, &success);
1420 }
1421 }
1422 }
1423 else
1424 {
1425 m_inst_mode = eModeARM;
1426 m_inst.opcode_type = eOpcode32;
1427 m_inst.opcode.inst32 = ReadMemoryUnsigned(read_inst_context, pc, 4, 0, &success);
1428 }
1429 }
1430 }
1431 if (!success)
1432 {
1433 m_inst_mode = eModeInvalid;
1434 m_inst_pc = LLDB_INVALID_ADDRESS;
1435 }
1436 return success;
1437}
1438
1439uint32_t
1440EmulateInstructionARM::CurrentCond ()
1441{
1442 switch (m_inst_mode)
1443 {
1444 default:
1445 case eModeInvalid:
1446 break;
1447
1448 case eModeARM:
1449 return UnsignedBits(m_inst.opcode.inst32, 31, 28);
1450
1451 case eModeThumb:
1452 return 0x0000000Eu; // Return always for now, we need to handl IT instructions later
1453 }
1454 return UINT32_MAX; // Return invalid value
1455}
1456bool
1457EmulateInstructionARM::ConditionPassed ()
1458{
1459 if (m_inst_cpsr == 0)
1460 return false;
1461
1462 const uint32_t cond = CurrentCond ();
1463
1464 if (cond == UINT32_MAX)
1465 return false;
1466
1467 bool result = false;
1468 switch (UnsignedBits(cond, 3, 1))
1469 {
1470 case 0: result = (m_inst_cpsr & MASK_CPSR_Z) != 0; break;
1471 case 1: result = (m_inst_cpsr & MASK_CPSR_C) != 0; break;
1472 case 2: result = (m_inst_cpsr & MASK_CPSR_N) != 0; break;
1473 case 3: result = (m_inst_cpsr & MASK_CPSR_V) != 0; break;
1474 case 4: result = ((m_inst_cpsr & MASK_CPSR_C) != 0) && ((m_inst_cpsr & MASK_CPSR_Z) == 0); break;
1475 case 5:
1476 {
1477 bool n = (m_inst_cpsr & MASK_CPSR_N);
1478 bool v = (m_inst_cpsr & MASK_CPSR_V);
1479 result = n == v;
1480 }
1481 break;
1482 case 6:
1483 {
1484 bool n = (m_inst_cpsr & MASK_CPSR_N);
1485 bool v = (m_inst_cpsr & MASK_CPSR_V);
1486 result = n == v && ((m_inst_cpsr & MASK_CPSR_Z) == 0);
1487 }
1488 break;
1489 case 7:
1490 result = true;
1491 break;
1492 }
1493
1494 if (cond & 1)
1495 result = !result;
1496 return result;
1497}
1498
1499
1500bool
1501EmulateInstructionARM::EvaluateInstruction ()
1502{
1503 return false;
1504}