Browse Source

Added some missing Thumb instructions to the traceback follower, so now it is able to traceback through switch() statements

etagle 7 years ago
parent
commit
8934a2c49b
1 changed files with 153 additions and 11 deletions
  1. 153
    11
      Marlin/src/HAL/HAL_DUE/backtrace/unwarm_thumb.c

+ 153
- 11
Marlin/src/HAL/HAL_DUE/backtrace/unwarm_thumb.c View File

@@ -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;

Loading…
Cancel
Save