|
@@ -25,10 +25,10 @@
|
25
|
25
|
* \param value The value to sign extend.
|
26
|
26
|
* \return The signed-11 bit value stored in a 16bit data type.
|
27
|
27
|
*/
|
28
|
|
-static int16_t signExtend11(uint16_t value) {
|
|
28
|
+static int32_t signExtend11(uint16_t value) {
|
29
|
29
|
|
30
|
30
|
if(value & 0x400) {
|
31
|
|
- value |= 0xf800;
|
|
31
|
+ value |= 0xfffff800;
|
32
|
32
|
}
|
33
|
33
|
|
34
|
34
|
return value;
|
|
@@ -243,6 +243,40 @@ UnwResult UnwStartThumb(UnwState * const state) {
|
243
|
243
|
|
244
|
244
|
UnwPrintd3(" r%d = 0x%08x\n", r, state->regData[r].v);
|
245
|
245
|
}
|
|
246
|
+ /*
|
|
247
|
+ * TBB / TBH
|
|
248
|
+ */
|
|
249
|
+ else if ((instr & 0xfff0) == 0xe8d0 && (instr2 & 0xffe0) == 0xf000) {
|
|
250
|
+ /* We are only interested in
|
|
251
|
+ * the forms
|
|
252
|
+ * TBB [PC, ...]
|
|
253
|
+ * TBH [PC, ..., LSL #1]
|
|
254
|
+ * as those are used by the C compiler to implement
|
|
255
|
+ * the switch clauses
|
|
256
|
+ */
|
|
257
|
+ uint8_t rn = instr & 0xf;
|
|
258
|
+ uint8_t rm = instr2 & 0xf;
|
|
259
|
+ bool H = (instr2 & 0x10) ? true : false;
|
|
260
|
+
|
|
261
|
+ UnwPrintd5("TB%c [r%d,r%d%s]\n", H ? 'H' : 'B', rn, rm, H ? ",LSL #1" : "");
|
|
262
|
+
|
|
263
|
+ // We are only interested if the RN is the PC. Let´s choose the 1st destination
|
|
264
|
+ if (rn == 15) {
|
|
265
|
+ if (H) {
|
|
266
|
+ uint16_t rv;
|
|
267
|
+ if(!state->cb->readH((state->regData[15].v & (~1)) + 2, &rv)) {
|
|
268
|
+ return UNWIND_DREAD_H_FAIL;
|
|
269
|
+ }
|
|
270
|
+ state->regData[15].v += rv * 2;
|
|
271
|
+ } else {
|
|
272
|
+ uint8_t rv;
|
|
273
|
+ if(!state->cb->readB((state->regData[15].v & (~1)) + 2, &rv)) {
|
|
274
|
+ return UNWIND_DREAD_B_FAIL;
|
|
275
|
+ }
|
|
276
|
+ state->regData[15].v += rv * 2;
|
|
277
|
+ }
|
|
278
|
+ }
|
|
279
|
+ }
|
246
|
280
|
/*
|
247
|
281
|
* Unconditional branch
|
248
|
282
|
*/
|
|
@@ -374,6 +408,118 @@ UnwResult UnwStartThumb(UnwState * const state) {
|
374
|
408
|
UnwPrintd2(" New PC=%x", state->regData[15].v + 2);
|
375
|
409
|
}
|
376
|
410
|
}
|
|
411
|
+ /*
|
|
412
|
+ * PC-relative load
|
|
413
|
+ * LDR Rd,[PC, #+/-imm]
|
|
414
|
+ */
|
|
415
|
+ else if((instr & 0xff7f) == 0xf85f) {
|
|
416
|
+ uint8_t rt = (instr2 & 0xf000) >> 12;
|
|
417
|
+ uint8_t imm12 = (instr2 & 0x0fff);
|
|
418
|
+ bool A = (instr & 0x80) ? true : false;
|
|
419
|
+ uint32_t address;
|
|
420
|
+
|
|
421
|
+ /* Compute load address, adding a word to account for prefetch */
|
|
422
|
+ address = (state->regData[15].v & (~0x3)) + 4;
|
|
423
|
+ if (A) address += imm12;
|
|
424
|
+ else address -= imm12;
|
|
425
|
+
|
|
426
|
+ UnwPrintd4("LDR r%d,[PC #%c0x%08x]", rt, A?'+':'-', address);
|
|
427
|
+
|
|
428
|
+ if(!UnwMemReadRegister(state, address, &state->regData[rt])) {
|
|
429
|
+ return UNWIND_DREAD_W_FAIL;
|
|
430
|
+ }
|
|
431
|
+ }
|
|
432
|
+ /*
|
|
433
|
+ * LDR immediate.
|
|
434
|
+ * We are only interested when destination is PC.
|
|
435
|
+ * LDR Rt,[Rn , #n]
|
|
436
|
+ */
|
|
437
|
+ else if ((instr & 0xfff0) == 0xf8d0) {
|
|
438
|
+ uint8_t rn = (instr & 0xf);
|
|
439
|
+ uint8_t rt = (instr2 & 0xf000) >> 12;
|
|
440
|
+ uint16_t imm12 = (instr2 & 0xfff);
|
|
441
|
+
|
|
442
|
+ /* If destination is PC and we don't know the source value, then fail */
|
|
443
|
+ if (!M_IsOriginValid(state->regData[rn].o)) {
|
|
444
|
+ state->regData[rt].o = state->regData[rn].o;
|
|
445
|
+ } else {
|
|
446
|
+ uint32_t address = state->regData[rn].v + imm12;
|
|
447
|
+ if(!UnwMemReadRegister(state, address, &state->regData[rt])) {
|
|
448
|
+ return UNWIND_DREAD_W_FAIL;
|
|
449
|
+ }
|
|
450
|
+ }
|
|
451
|
+ }
|
|
452
|
+ /*
|
|
453
|
+ * LDR immediate
|
|
454
|
+ * We are only interested when destination is PC.
|
|
455
|
+ * LDR Rt,[Rn , #-n]
|
|
456
|
+ * LDR Rt,[Rn], #+/-n]
|
|
457
|
+ * LDR Rt,[Rn, #+/-n]!
|
|
458
|
+ */
|
|
459
|
+ else if ((instr & 0xfff0) == 0xf850 && (instr2 & 0x0800) == 0x0800) {
|
|
460
|
+ uint8_t rn = (instr & 0xf);
|
|
461
|
+ uint8_t rt = (instr2 & 0xf000) >> 12;
|
|
462
|
+ uint16_t imm8 = (instr2 & 0xff);
|
|
463
|
+ bool P = (instr2 & 0x400) ? true : false;
|
|
464
|
+ bool U = (instr2 & 0x200) ? true : false;
|
|
465
|
+ bool W = (instr2 & 0x100) ? true : false;
|
|
466
|
+
|
|
467
|
+ if (!M_IsOriginValid(state->regData[rn].o)) {
|
|
468
|
+ state->regData[rt].o = state->regData[rn].o;
|
|
469
|
+ } else {
|
|
470
|
+ uint32_t offaddress = state->regData[rn].v + imm8;
|
|
471
|
+ if (U) offaddress += imm8;
|
|
472
|
+ else offaddress -= imm8;
|
|
473
|
+
|
|
474
|
+ uint32_t address;
|
|
475
|
+ if (P) {
|
|
476
|
+ address = offaddress;
|
|
477
|
+ } else {
|
|
478
|
+ address = state->regData[rn].v;
|
|
479
|
+ }
|
|
480
|
+
|
|
481
|
+ if(!UnwMemReadRegister(state, address, &state->regData[rt])) {
|
|
482
|
+ return UNWIND_DREAD_W_FAIL;
|
|
483
|
+ }
|
|
484
|
+
|
|
485
|
+ if (W) {
|
|
486
|
+ state->regData[rn].v = offaddress;
|
|
487
|
+ }
|
|
488
|
+ }
|
|
489
|
+ }
|
|
490
|
+ /*
|
|
491
|
+ * LDR (register).
|
|
492
|
+ * We are interested in the form
|
|
493
|
+ * ldr Rt, [Rn, Rm, lsl #x]
|
|
494
|
+ * Where Rt is PC, Rn value is known, Rm is not known or unknown
|
|
495
|
+ */
|
|
496
|
+ else if ((instr & 0xfff0) == 0xf850 && (instr2 & 0x0fc0) == 0x0000) {
|
|
497
|
+ uint8_t rn = (instr & 0xf);
|
|
498
|
+ uint8_t rt = (instr2 & 0xf000) >> 12;
|
|
499
|
+ uint8_t rm = (instr2 & 0xf);
|
|
500
|
+ uint8_t imm2 = (instr2 & 0x30) >> 4;
|
|
501
|
+
|
|
502
|
+ if (!M_IsOriginValid(state->regData[rn].o) ||
|
|
503
|
+ !M_IsOriginValid(state->regData[rm].o)) {
|
|
504
|
+
|
|
505
|
+ /* If Rt is PC, and Rn is known, then do an exception and assume
|
|
506
|
+ Rm equals 0 => This takes the first case in a switch() */
|
|
507
|
+ if (rt == 15 && M_IsOriginValid(state->regData[rn].o)) {
|
|
508
|
+ uint32_t address = state->regData[rn].v;
|
|
509
|
+ if(!UnwMemReadRegister(state, address, &state->regData[rt])) {
|
|
510
|
+ return UNWIND_DREAD_W_FAIL;
|
|
511
|
+ }
|
|
512
|
+ } else {
|
|
513
|
+ /* Propagate unknown value */
|
|
514
|
+ state->regData[rt].o = state->regData[rn].o;
|
|
515
|
+ }
|
|
516
|
+ } else {
|
|
517
|
+ uint32_t address = state->regData[rn].v + (state->regData[rm].v << imm2);
|
|
518
|
+ if(!UnwMemReadRegister(state, address, &state->regData[rt])) {
|
|
519
|
+ return UNWIND_DREAD_W_FAIL;
|
|
520
|
+ }
|
|
521
|
+ }
|
|
522
|
+ }
|
377
|
523
|
else {
|
378
|
524
|
UnwPrintd1("???? (32)");
|
379
|
525
|
|
|
@@ -452,8 +598,8 @@ UnwResult UnwStartThumb(UnwState * const state) {
|
452
|
598
|
}
|
453
|
599
|
|
454
|
600
|
/* Propagate the origin */
|
455
|
|
- if(M_IsOriginValid(state->regData[rs].v) &&
|
456
|
|
- M_IsOriginValid(state->regData[rn].v)) {
|
|
601
|
+ if(M_IsOriginValid(state->regData[rs].o) &&
|
|
602
|
+ M_IsOriginValid(state->regData[rn].o)) {
|
457
|
603
|
state->regData[rd].o = state->regData[rs].o;
|
458
|
604
|
state->regData[rd].o |= REG_VAL_ARITHMETIC;
|
459
|
605
|
}
|
|
@@ -715,8 +861,8 @@ UnwResult UnwStartThumb(UnwState * const state) {
|
715
|
861
|
case 3: /* BX */
|
716
|
862
|
UnwPrintd4("BX r%d\t; r%d %s\n", rhs, rhs, M_Origin2Str(state->regData[rhs].o));
|
717
|
863
|
|
718
|
|
- /* Only follow BX if the data was from the stack */
|
719
|
|
- if(state->regData[rhs].o == REG_VAL_FROM_STACK) {
|
|
864
|
+ /* Only follow BX if the data was from the stack or BX LR */
|
|
865
|
+ if(rhs == 14 || state->regData[rhs].o == REG_VAL_FROM_STACK) {
|
720
|
866
|
UnwPrintd2(" Return PC=0x%x\n", state->regData[rhs].v & (~0x1));
|
721
|
867
|
|
722
|
868
|
/* Report the return address, including mode bit */
|
|
@@ -724,10 +870,6 @@ UnwResult UnwStartThumb(UnwState * const state) {
|
724
|
870
|
return UNWIND_TRUNCATED;
|
725
|
871
|
}
|
726
|
872
|
|
727
|
|
- /* Store return address in LR register */
|
728
|
|
- state->regData[14].v = state->regData[15].v + 2;
|
729
|
|
- state->regData[14].o = REG_VAL_FROM_CONST;
|
730
|
|
-
|
731
|
873
|
/* Update the PC */
|
732
|
874
|
state->regData[15].v = state->regData[rhs].v;
|
733
|
875
|
|
|
@@ -927,7 +1069,7 @@ UnwResult UnwStartThumb(UnwState * const state) {
|
927
|
1069
|
*/
|
928
|
1070
|
else if((instr & 0xf800) == 0xe000) {
|
929
|
1071
|
uint32_t v;
|
930
|
|
- int16_t branchValue = signExtend11(instr & 0x07ff);
|
|
1072
|
+ int32_t branchValue = signExtend11(instr & 0x07ff);
|
931
|
1073
|
|
932
|
1074
|
/* Branch distance is twice that specified in the instruction. */
|
933
|
1075
|
branchValue *= 2;
|