Browse Source

Several fixes to the backtracer. Tested ant it works

etagle 6 years ago
parent
commit
328edea03a

+ 60
- 50
Marlin/src/HAL/HAL_DUE/DebugMonitor_Due.cpp View File

@@ -34,19 +34,6 @@
34 34
 // Serial interrupt routines or any C runtime, as we don't know the
35 35
 // state we are when running them
36 36
 
37
-
38
-/* These symbols point to the start and end of stack */
39
-extern "C" const int _sstack;
40
-extern "C" const int _estack;
41
-
42
-/* These symbols point to the start and end of the code section */
43
-extern "C" const int _sfixed;
44
-extern "C" const int _efixed;
45
-
46
-/* These symbols point to the start and end of initialized data (could be SRAM functions!) */
47
-extern "C" const int _srelocate;
48
-extern "C" const int _erelocate;
49
-
50 37
 // A SW memory barrier, to ensure GCC does not overoptimize loops
51 38
 #define sw_barrier() asm volatile("": : :"memory");
52 39
 
@@ -126,25 +113,20 @@ static void TXDec(uint32_t v) {
126 113
 }
127 114
 
128 115
 /* Validate address */
129
-static bool validate_addr(uint16_t addr) {
130
-
131
-  // PC must point into the text (CODE) area
132
-  if (addr >= (uint32_t)&_sfixed && addr <= (uint32_t)&_efixed)
133
-    return true;
116
+static bool validate_addr(uint32_t addr) {
134 117
 
135
-  // Or into the SRAM function area
136
-  if (addr >= (uint32_t)&_srelocate && addr <= (uint32_t)&_erelocate)
118
+  // Address must be in SRAM (0x20070000 - 0x20088000)
119
+  if (addr >= 0x20070000 && addr < 0x20088000)
137 120
     return true;
138 121
 
139
-  // SP must point into the allocated stack area
140
-  if (addr >= (uint32_t)&_sstack && addr <= (uint32_t)&_estack)
122
+  // Or in FLASH (0x00080000 - 0x00100000)
123
+  if (addr >= 0x00080000 && addr < 0x00100000)
141 124
     return true;
142 125
 
143 126
   return false;
144 127
 }
145 128
 
146 129
 static bool UnwReadW(const uint32_t a, uint32_t *v) {
147
-
148 130
   if (!validate_addr(a))
149 131
     return false;
150 132
 
@@ -153,7 +135,6 @@ static bool UnwReadW(const uint32_t a, uint32_t *v) {
153 135
 }
154 136
 
155 137
 static bool UnwReadH(const uint32_t a, uint16_t *v) {
156
-
157 138
   if (!validate_addr(a))
158 139
     return false;
159 140
 
@@ -162,7 +143,6 @@ static bool UnwReadH(const uint32_t a, uint16_t *v) {
162 143
 }
163 144
 
164 145
 static bool UnwReadB(const uint32_t a, uint8_t *v) {
165
-
166 146
   if (!validate_addr(a))
167 147
     return false;
168 148
 
@@ -173,13 +153,27 @@ static bool UnwReadB(const uint32_t a, uint8_t *v) {
173 153
 
174 154
 // Dump a backtrace entry
175 155
 static bool UnwReportOut(void* ctx, const UnwReport* bte) {
156
+  int* p = (int*)ctx;
176 157
 
177
-  TX(bte->name?bte->name:"unknown"); TX('@');TXHex(bte->function);
158
+  (*p)++;
159
+  TX('#'); TXDec(*p); TX(" : ");
160
+  TX(bte->name?bte->name:"unknown"); TX('@'); TXHex(bte->function);
178 161
   TX('+'); TXDec(bte->address - bte->function);
179 162
   TX(" PC:");TXHex(bte->address); TX('\n');
180 163
   return true;
181 164
 }
182 165
 
166
+#if defined(UNW_DEBUG)
167
+void UnwPrintf(const char* format, ...) {
168
+  char dest[256];
169
+  va_list argptr;
170
+  va_start(argptr, format);
171
+  vsprintf(dest, format, argptr);
172
+  va_end(argptr);
173
+  TX(&dest[0]);
174
+}
175
+#endif
176
+
183 177
 /* Table of function pointers for passing to the unwinder */
184 178
 static const UnwindCallbacks UnwCallbacks = {
185 179
   UnwReportOut,
@@ -187,7 +181,7 @@ static const UnwindCallbacks UnwCallbacks = {
187 181
   UnwReadH,
188 182
   UnwReadB
189 183
 #if defined(UNW_DEBUG)
190
- ,printf
184
+ ,UnwPrintf
191 185
 #endif
192 186
 };
193 187
 
@@ -201,24 +195,27 @@ static const UnwindCallbacks UnwCallbacks = {
201 195
  * The function ends with a BKPT instruction to force control back into the debugger
202 196
  */
203 197
 extern "C"
204
-void HardFault_HandlerC(unsigned long *hardfault_args, unsigned long cause) {
198
+void HardFault_HandlerC(unsigned long *sp, unsigned long lr, unsigned long cause) {
205 199
 
206 200
   static const char* causestr[] = {
207 201
     "NMI","Hard","Mem","Bus","Usage","Debug","WDT","RSTC"
208 202
   };
209 203
 
204
+  UnwindFrame btf;
205
+
210 206
   // Dump report to the Programming port (interrupts are DISABLED)
211 207
   TXBegin();
212 208
   TX("\n\n## Software Fault detected ##\n");
213 209
   TX("Cause: "); TX(causestr[cause]); TX('\n');
214
-  TX("R0   : "); TXHex(((unsigned long)hardfault_args[0])); TX('\n');
215
-  TX("R1   : "); TXHex(((unsigned long)hardfault_args[1])); TX('\n');
216
-  TX("R2   : "); TXHex(((unsigned long)hardfault_args[2])); TX('\n');
217
-  TX("R3   : "); TXHex(((unsigned long)hardfault_args[3])); TX('\n');
218
-  TX("R12  : "); TXHex(((unsigned long)hardfault_args[4])); TX('\n');
219
-  TX("LR   : "); TXHex(((unsigned long)hardfault_args[5])); TX('\n');
220
-  TX("PC   : "); TXHex(((unsigned long)hardfault_args[6])); TX('\n');
221
-  TX("PSR  : "); TXHex(((unsigned long)hardfault_args[7])); TX('\n');
210
+
211
+  TX("R0   : "); TXHex(((unsigned long)sp[0])); TX('\n');
212
+  TX("R1   : "); TXHex(((unsigned long)sp[1])); TX('\n');
213
+  TX("R2   : "); TXHex(((unsigned long)sp[2])); TX('\n');
214
+  TX("R3   : "); TXHex(((unsigned long)sp[3])); TX('\n');
215
+  TX("R12  : "); TXHex(((unsigned long)sp[4])); TX('\n');
216
+  TX("LR   : "); TXHex(((unsigned long)sp[5])); TX('\n');
217
+  TX("PC   : "); TXHex(((unsigned long)sp[6])); TX('\n');
218
+  TX("PSR  : "); TXHex(((unsigned long)sp[7])); TX('\n');
222 219
 
223 220
   // Configurable Fault Status Register
224 221
   // Consists of MMSR, BFSR and UFSR
@@ -241,14 +238,18 @@ void HardFault_HandlerC(unsigned long *hardfault_args, unsigned long cause) {
241 238
   // Bus Fault Address Register
242 239
   TX("BFAR : "); TXHex((*((volatile unsigned long *)(0xE000ED38)))); TX('\n');
243 240
 
241
+  TX("ExcLR: "); TXHex(lr); TX('\n');
242
+  TX("ExcSP: "); TXHex((unsigned long)sp); TX('\n');
243
+
244
+  btf.sp = ((unsigned long)sp) + 8*4; // The original stack pointer
245
+  btf.fp = btf.sp;
246
+  btf.lr = ((unsigned long)sp[5]);
247
+  btf.pc = ((unsigned long)sp[6]) | 1; // Force Thumb, as CORTEX only support it
248
+
244 249
   // Perform a backtrace
245 250
   TX("\nBacktrace:\n\n");
246
-  UnwindFrame btf;
247
-  btf.sp = ((unsigned long)hardfault_args[7]);
248
-  btf.fp = btf.sp;
249
-  btf.lr = ((unsigned long)hardfault_args[5]);
250
-  btf.pc = ((unsigned long)hardfault_args[6]);
251
-  UnwindStart(&btf, &UnwCallbacks, nullptr);
251
+  int ctr = 0;
252
+  UnwindStart(&btf, &UnwCallbacks, &ctr);
252 253
 
253 254
   // Disable all NVIC interrupts
254 255
   NVIC->ICER[0] = 0xFFFFFFFF;
@@ -274,7 +275,8 @@ __attribute__((naked)) void NMI_Handler(void) {
274 275
     " ite eq                \n"
275 276
     " mrseq r0, msp         \n"
276 277
     " mrsne r0, psp         \n"
277
-    " mov r1,#0             \n"
278
+    " mov r1,lr             \n"
279
+    " mov r2,#0             \n"
278 280
     " b HardFault_HandlerC  \n"
279 281
   );
280 282
 }
@@ -285,7 +287,8 @@ __attribute__((naked)) void HardFault_Handler(void) {
285 287
     " ite eq                \n"
286 288
     " mrseq r0, msp         \n"
287 289
     " mrsne r0, psp         \n"
288
-    " mov r1,#1             \n"
290
+    " mov r1,lr             \n"
291
+    " mov r2,#1             \n"
289 292
     " b HardFault_HandlerC  \n"
290 293
   );
291 294
 }
@@ -296,7 +299,8 @@ __attribute__((naked)) void MemManage_Handler(void) {
296 299
     " ite eq                \n"
297 300
     " mrseq r0, msp         \n"
298 301
     " mrsne r0, psp         \n"
299
-    " mov r1,#2             \n"
302
+    " mov r1,lr             \n"
303
+    " mov r2,#2             \n"
300 304
     " b HardFault_HandlerC  \n"
301 305
   );
302 306
 }
@@ -307,7 +311,8 @@ __attribute__((naked)) void BusFault_Handler(void) {
307 311
     " ite eq                \n"
308 312
     " mrseq r0, msp         \n"
309 313
     " mrsne r0, psp         \n"
310
-    " mov r1,#3             \n"
314
+    " mov r1,lr             \n"
315
+    " mov r2,#3             \n"
311 316
     " b HardFault_HandlerC  \n"
312 317
   );
313 318
 }
@@ -318,7 +323,8 @@ __attribute__((naked)) void UsageFault_Handler(void) {
318 323
     " ite eq                \n"
319 324
     " mrseq r0, msp         \n"
320 325
     " mrsne r0, psp         \n"
321
-    " mov r1,#4             \n"
326
+    " mov r1,lr             \n"
327
+    " mov r2,#4             \n"
322 328
     " b HardFault_HandlerC  \n"
323 329
   );
324 330
 }
@@ -329,18 +335,21 @@ __attribute__((naked)) void DebugMon_Handler(void) {
329 335
     " ite eq                \n"
330 336
     " mrseq r0, msp         \n"
331 337
     " mrsne r0, psp         \n"
332
-    " mov r1,#5             \n"
338
+    " mov r1,lr             \n"
339
+    " mov r2,#5             \n"
333 340
     " b HardFault_HandlerC  \n"
334 341
   );
335 342
 }
336 343
 
344
+/* This is NOT an exception, it is an interrupt handler - Nevertheless, the framing is the same */
337 345
 __attribute__((naked)) void WDT_Handler(void) {
338 346
   __asm volatile (
339 347
     " tst lr, #4            \n"
340 348
     " ite eq                \n"
341 349
     " mrseq r0, msp         \n"
342 350
     " mrsne r0, psp         \n"
343
-    " mov r1,#6             \n"
351
+    " mov r1,lr             \n"
352
+    " mov r2,#6             \n"
344 353
     " b HardFault_HandlerC  \n"
345 354
   );
346 355
 }
@@ -351,7 +360,8 @@ __attribute__((naked)) void RSTC_Handler(void) {
351 360
     " ite eq                \n"
352 361
     " mrseq r0, msp         \n"
353 362
     " mrsne r0, psp         \n"
354
-    " mov r1,#7             \n"
363
+    " mov r1,lr             \n"
364
+    " mov r2,#7             \n"
355 365
     " b HardFault_HandlerC  \n"
356 366
   );
357 367
 }

+ 3
- 3
Marlin/src/HAL/HAL_DUE/backtrace/unwarm.c View File

@@ -79,7 +79,7 @@ void UnwInitState(UnwState * const state,     /**< Pointer to structure to fill.
79 79
 // Detect if function names are available
80 80
 static int __attribute__ ((noinline)) has_function_names(void) {
81 81
 
82
-  uint32_t flag_word = ((uint32_t*)&has_function_names)[-1];
82
+  uint32_t flag_word = ((uint32_t*)(((uint32_t)(&has_function_names)) & (-4))) [-1];
83 83
   return ((flag_word & 0xff000000) == 0xff000000) ? 1 : 0;
84 84
 }
85 85
 
@@ -93,7 +93,7 @@ bool UnwReportRetAddr(UnwState * const state, uint32_t addr) {
93 93
 
94 94
   // We found two acceptable values.
95 95
   entry.name = NULL;
96
-  entry.address = addr;
96
+  entry.address = addr & 0xFFFFFFFE; // Remove Thumb bit
97 97
   entry.function = 0;
98 98
 
99 99
   // If there are function names, try to solve name
@@ -108,7 +108,7 @@ bool UnwReportRetAddr(UnwState * const state, uint32_t addr) {
108 108
     uint32_t v;
109 109
     while(state->cb->readW(pf-4,&v)) {
110 110
 
111
-      // Check if name descriptor is valid and name is terminated in 0.
111
+      // Check if name descriptor is valid
112 112
       if ((v & 0xffffff00) == 0xff000000 &&
113 113
           (v & 0xff) > 1) {
114 114
 

+ 370
- 9
Marlin/src/HAL/HAL_DUE/backtrace/unwarm_thumb.c View File

@@ -38,6 +38,8 @@ UnwResult UnwStartThumb(UnwState * const state) {
38 38
 
39 39
   bool found = false;
40 40
   uint16_t t = UNW_MAX_INSTR_COUNT;
41
+  uint32_t lastJumpAddr = 0;  // Last JUMP address, to try to detect infinite loops
42
+  bool loopDetected = false;  // If a loop was detected
41 43
 
42 44
   do {
43 45
     uint16_t instr;
@@ -61,12 +63,332 @@ UnwResult UnwStartThumb(UnwState * const state) {
61 63
       return UNWIND_INCONSISTENT;
62 64
     }
63 65
 
66
+    /*
67
+     * Detect 32bit thumb instructions
68
+     */
69
+    if ((instr & 0xe000) == 0xe000 && (instr & 0x1800) != 0) {
70
+      uint16_t instr2;
71
+
72
+      /* Check next address */
73
+      state->regData[15].v += 2;
74
+
75
+      /* Attempt to read the 2nd part of the instruction */
76
+      if(!state->cb->readH(state->regData[15].v & (~0x1), &instr2)) {
77
+        return UNWIND_IREAD_H_FAIL;
78
+      }
79
+
80
+      UnwPrintd3(" %x %04x:", state->regData[15].v, instr2);
81
+
82
+      /*
83
+       * Load/Store multiple: Only interpret
84
+       *  PUSH and POP
85
+       */
86
+      if ((instr & 0xfe6f) == 0xe82d) {
87
+        bool     L     = (instr &  0x10) ? true : false;
88
+        uint16_t rList = instr2;
89
+
90
+        if(L) {
91
+          uint8_t r;
92
+
93
+          /* Load from memory: POP */
94
+          UnwPrintd1("POP {Rlist}\n");
95
+
96
+          /* Load registers from stack */
97
+          for(r = 0; r < 16; r++) {
98
+            if(rList & (0x1 << r)) {
99
+
100
+              /* Read the word */
101
+              if(!UnwMemReadRegister(state, state->regData[13].v, &state->regData[r])) {
102
+                return UNWIND_DREAD_W_FAIL;
103
+              }
104
+
105
+              /* Alter the origin to be from the stack if it was valid */
106
+              if(M_IsOriginValid(state->regData[r].o)) {
107
+
108
+                state->regData[r].o = REG_VAL_FROM_STACK;
109
+
110
+                /* If restoring the PC */
111
+                if (r == 15) {
112
+
113
+                  /* The bottom bit should have been set to indicate that
114
+                   *  the caller was from Thumb.  This would allow return
115
+                   *  by BX for interworking APCS.
116
+                   */
117
+                  if((state->regData[15].v & 0x1) == 0) {
118
+                    UnwPrintd2("Warning: Return address not to Thumb: 0x%08x\n", state->regData[15].v);
119
+
120
+                    /* Pop into the PC will not switch mode */
121
+                    return UNWIND_INCONSISTENT;
122
+                  }
123
+
124
+                  /* Store the return address */
125
+                  if(!UnwReportRetAddr(state, state->regData[15].v)) {
126
+                    return UNWIND_TRUNCATED;
127
+                  }
128
+
129
+                  /* Now have the return address */
130
+                  UnwPrintd2(" Return PC=%x\n", state->regData[15].v);
131
+
132
+                  /* Compensate for the auto-increment, which isn't needed here */
133
+                  state->regData[15].v -= 2;
134
+
135
+                }
136
+
137
+              } else {
138
+
139
+                if (r == 15) {
140
+                  /* Return address is not valid */
141
+                  UnwPrintd1("PC popped with invalid address\n");
142
+                  return UNWIND_FAILURE;
143
+                }
144
+              }
145
+
146
+              state->regData[13].v += 4;
147
+
148
+              UnwPrintd3("  r%d = 0x%08x\n", r, state->regData[r].v);
149
+            }
150
+          }
151
+        }
152
+        else {
153
+          int8_t r;
154
+
155
+          /* Store to memory: PUSH */
156
+          UnwPrintd1("PUSH {Rlist}");
157
+
158
+          for(r = 15; r >= 0; r--) {
159
+            if(rList & (0x1 << r)) {
160
+              UnwPrintd4("\n  r%d = 0x%08x\t; %s", r, state->regData[r].v, M_Origin2Str(state->regData[r].o));
161
+
162
+              state->regData[13].v -= 4;
163
+
164
+              if(!UnwMemWriteRegister(state, state->regData[13].v, &state->regData[r])) {
165
+                return UNWIND_DWRITE_W_FAIL;
166
+              }
167
+            }
168
+          }
169
+        }
170
+      }
171
+      /*
172
+       * PUSH register
173
+       */
174
+      else if (instr == 0xf84d && (instr2 & 0x0fff) == 0x0d04) {
175
+        uint8_t r = instr2 >> 12;
176
+
177
+        /* Store to memory: PUSH */
178
+        UnwPrintd2("PUSH {R%d}\n", r);
179
+        UnwPrintd4("\n  r%d = 0x%08x\t; %s", r, state->regData[r].v, M_Origin2Str(state->regData[r].o));
180
+
181
+        state->regData[13].v -= 4;
182
+
183
+        if(!UnwMemWriteRegister(state, state->regData[13].v, &state->regData[r])) {
184
+          return UNWIND_DWRITE_W_FAIL;
185
+        }
186
+      }
187
+      /*
188
+       * POP register
189
+       */
190
+      else if (instr == 0xf85d && (instr2 & 0x0fff) == 0x0b04) {
191
+        uint8_t r = instr2 >> 12;
192
+
193
+        /* Load from memory: POP */
194
+        UnwPrintd2("POP {R%d}\n", r);
195
+
196
+        /* Read the word */
197
+        if(!UnwMemReadRegister(state, state->regData[13].v, &state->regData[r])) {
198
+          return UNWIND_DREAD_W_FAIL;
199
+        }
200
+
201
+        /* Alter the origin to be from the stack if it was valid */
202
+        if(M_IsOriginValid(state->regData[r].o)) {
203
+
204
+          state->regData[r].o = REG_VAL_FROM_STACK;
205
+
206
+          /* If restoring the PC */
207
+          if (r == 15) {
208
+
209
+            /* The bottom bit should have been set to indicate that
210
+             *  the caller was from Thumb.  This would allow return
211
+             *  by BX for interworking APCS.
212
+             */
213
+            if((state->regData[15].v & 0x1) == 0) {
214
+              UnwPrintd2("Warning: Return address not to Thumb: 0x%08x\n", state->regData[15].v);
215
+
216
+              /* Pop into the PC will not switch mode */
217
+              return UNWIND_INCONSISTENT;
218
+            }
219
+
220
+            /* Store the return address */
221
+            if(!UnwReportRetAddr(state, state->regData[15].v)) {
222
+              return UNWIND_TRUNCATED;
223
+            }
224
+
225
+            /* Now have the return address */
226
+            UnwPrintd2(" Return PC=%x\n", state->regData[15].v);
227
+
228
+            /* Compensate for the auto-increment, which isn't needed here */
229
+            state->regData[15].v -= 2;
230
+
231
+          }
232
+
233
+        } else {
234
+
235
+          if (r == 15) {
236
+            /* Return address is not valid */
237
+            UnwPrintd1("PC popped with invalid address\n");
238
+            return UNWIND_FAILURE;
239
+          }
240
+        }
241
+
242
+        state->regData[13].v += 4;
243
+
244
+        UnwPrintd3("  r%d = 0x%08x\n", r, state->regData[r].v);
245
+      }
246
+      /*
247
+       * Unconditional branch
248
+       */
249
+      else if ((instr & 0xf800) == 0xf000 && (instr2 & 0xd000) == 0x9000) {
250
+        uint32_t v;
251
+
252
+        uint8_t      S = (instr & 0x400) >> 10;
253
+        uint16_t imm10 = (instr & 0x3ff);
254
+        uint8_t     J1 = (instr2 & 0x2000) >> 13;
255
+        uint8_t     J2 = (instr2 & 0x0800) >> 11;
256
+        uint16_t imm11 = (instr2 & 0x7ff);
257
+
258
+        uint8_t I1 = J1 ^ S ^ 1;
259
+        uint8_t I2 = J2 ^ S ^ 1;
260
+        uint32_t imm32 = (S << 24) | (I1 << 23) | (I2 << 22) |(imm10 << 12) | (imm11 << 1);
261
+        if (S) imm32 |= 0xfe000000;
262
+
263
+        UnwPrintd2("B %d \n", imm32);
264
+
265
+        /* Update PC */
266
+        state->regData[15].v += imm32;
267
+
268
+        /* Need to advance by a word to account for pre-fetch.
269
+         *  Advance by a half word here, allowing the normal address
270
+         *  advance to account for the other half word.
271
+         */
272
+        state->regData[15].v += 2;
273
+
274
+        /* Compute the jump address */
275
+        v = state->regData[15].v + 2;
276
+
277
+        /* Display PC of next instruction */
278
+        UnwPrintd2(" New PC=%x", v);
279
+
280
+        /* Did we detect an infinite loop ? */
281
+        loopDetected = lastJumpAddr == v;
282
+
283
+        /* Remember the last address we jumped to  */
284
+        lastJumpAddr = v;
285
+      }
286
+
287
+      /*
288
+       * Branch with link
289
+       */
290
+      else if ((instr & 0xf800) == 0xf000 && (instr2 & 0xd000) == 0xd000) {
291
+
292
+        uint8_t      S = (instr & 0x400) >> 10;
293
+        uint16_t imm10 = (instr & 0x3ff);
294
+        uint8_t     J1 = (instr2 & 0x2000) >> 13;
295
+        uint8_t     J2 = (instr2 & 0x0800) >> 11;
296
+        uint16_t imm11 = (instr2 & 0x7ff);
297
+
298
+        uint8_t I1 = J1 ^ S ^ 1;
299
+        uint8_t I2 = J2 ^ S ^ 1;
300
+        uint32_t imm32 = (S << 24) | (I1 << 23) | (I2 << 22) |(imm10 << 12) | (imm11 << 1);
301
+        if (S) imm32 |= 0xfe000000;
302
+
303
+        UnwPrintd2("BL %d \n", imm32);
304
+
305
+        /* Never taken, as we are unwinding the stack */
306
+        if (0) {
307
+
308
+          /* Store return address in LR register */
309
+          state->regData[14].v = state->regData[15].v + 2;
310
+          state->regData[14].o = REG_VAL_FROM_CONST;
311
+
312
+          /* Update PC */
313
+          state->regData[15].v += imm32;
314
+
315
+          /* Need to advance by a word to account for pre-fetch.
316
+           *  Advance by a half word here, allowing the normal address
317
+           *  advance to account for the other half word.
318
+           */
319
+          state->regData[15].v += 2;
320
+
321
+          /* Display PC of next instruction */
322
+          UnwPrintd2(" Return PC=%x", state->regData[15].v);
323
+
324
+          /* Report the return address, including mode bit */
325
+          if(!UnwReportRetAddr(state, state->regData[15].v)) {
326
+            return UNWIND_TRUNCATED;
327
+          }
328
+
329
+          /* Determine the new mode */
330
+          if(state->regData[15].v & 0x1) {
331
+            /* Branching to THUMB */
332
+
333
+            /* Account for the auto-increment which isn't needed */
334
+            state->regData[15].v -= 2;
335
+          }
336
+          else {
337
+            /* Branch to ARM */
338
+            return UnwStartArm(state);
339
+          }
340
+        }
341
+      }
342
+
343
+      /*
344
+       * Conditional branches. Usually not taken, unless infinite loop is detected
345
+       */
346
+      else if ((instr & 0xf800) == 0xf000 && (instr2 & 0xd000) == 0x8000) {
347
+
348
+        uint8_t      S = (instr & 0x400) >> 10;
349
+        uint16_t  imm6 = (instr &  0x3f);
350
+        uint8_t     J1 = (instr2 & 0x2000) >> 13;
351
+        uint8_t     J2 = (instr2 & 0x0800) >> 11;
352
+        uint16_t imm11 = (instr2 & 0x7ff);
353
+
354
+        uint8_t I1 = J1 ^ S ^ 1;
355
+        uint8_t I2 = J2 ^ S ^ 1;
356
+        uint32_t imm32 = (S << 20) | (I1 << 19) | (I2 << 18) |(imm6 << 12) | (imm11 << 1);
357
+        if (S) imm32 |= 0xffe00000;
358
+
359
+        UnwPrintd2("Bcond %d\n", imm32);
360
+
361
+        /* Take the jump only if a loop is detected */
362
+        if (loopDetected) {
363
+
364
+          /* Update PC */
365
+          state->regData[15].v += imm32;
366
+
367
+          /* Need to advance by a word to account for pre-fetch.
368
+           *  Advance by a half word here, allowing the normal address
369
+           *  advance to account for the other half word.
370
+           */
371
+          state->regData[15].v += 2;
372
+
373
+          /* Display PC of next instruction */
374
+          UnwPrintd2(" New PC=%x", state->regData[15].v + 2);
375
+        }
376
+      }
377
+      else {
378
+        UnwPrintd1("???? (32)");
379
+
380
+        /* Unknown/undecoded.  May alter some register, so invalidate file */
381
+        UnwInvalidateRegisterFile(state->regData);
382
+      }
383
+      /* End of thumb 32bit code */
384
+
385
+    }
64 386
     /* Format 1: Move shifted register
65 387
      *  LSL Rd, Rs, #Offset5
66 388
      *  LSR Rd, Rs, #Offset5
67 389
      *  ASR Rd, Rs, #Offset5
68 390
      */
69
-    if((instr & 0xe000) == 0x0000 && (instr & 0x1800) != 0x1800) {
391
+    else if((instr & 0xe000) == 0x0000 && (instr & 0x1800) != 0x1800) {
70 392
       bool signExtend;
71 393
       uint8_t op      = (instr & 0x1800) >> 11;
72 394
       uint8_t offset5 = (instr & 0x07c0) >>  6;
@@ -355,8 +677,8 @@ UnwResult UnwStartThumb(UnwState * const state) {
355 677
     }
356 678
     /* Format 5: Hi register operations/branch exchange
357 679
      *  ADD Rd, Hs
358
-     *  ADD Hd, Rs
359
-     *  ADD Hd, Hs
680
+     *  CMP Hd, Rs
681
+     *  MOV Hd, Hs
360 682
      */
361 683
     else if((instr & 0xfc00) == 0x4400) {
362 684
       uint8_t op  = (instr & 0x0300) >> 8;
@@ -371,11 +693,6 @@ UnwResult UnwStartThumb(UnwState * const state) {
371 693
       if(h1)
372 694
         rhd += 8;
373 695
 
374
-      if(op != 3 && !h1 && !h2) {
375
-        UnwPrintd1("\nError: h1 or h2 must be set for ADD, CMP or MOV\n");
376
-        return UNWIND_ILLEGAL_INSTR;
377
-      }
378
-
379 696
       switch(op) {
380 697
         case 0: /* ADD */
381 698
           UnwPrintd5("ADD r%d, r%d\t; r%d %s", rhd, rhs, rhs, M_Origin2Str(state->regData[rhs].o));
@@ -407,6 +724,10 @@ UnwResult UnwStartThumb(UnwState * const state) {
407 724
               return UNWIND_TRUNCATED;
408 725
             }
409 726
 
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
+
410 731
             /* Update the PC */
411 732
             state->regData[15].v = state->regData[rhs].v;
412 733
 
@@ -570,10 +891,42 @@ UnwResult UnwStartThumb(UnwState * const state) {
570 891
         }
571 892
       }
572 893
     }
894
+
895
+    /*
896
+     * Conditional branches
897
+     * Bcond
898
+     */
899
+    else if((instr & 0xf000) == 0xd000) {
900
+      int32_t branchValue = (instr & 0xff);
901
+      if (branchValue & 0x80) branchValue |= 0xffffff00;
902
+
903
+      /* Branch distance is twice that specified in the instruction. */
904
+      branchValue *= 2;
905
+
906
+      UnwPrintd2("Bcond %d \n", branchValue);
907
+
908
+      /* Only take the branch if a loop was detected */
909
+      if (loopDetected) {
910
+
911
+        /* Update PC */
912
+        state->regData[15].v += branchValue;
913
+
914
+        /* Need to advance by a word to account for pre-fetch.
915
+         *  Advance by a half word here, allowing the normal address
916
+         *  advance to account for the other half word.
917
+         */
918
+        state->regData[15].v += 2;
919
+
920
+        /* Display PC of next instruction */
921
+        UnwPrintd2(" New PC=%x", state->regData[15].v + 2);
922
+      }
923
+    }
924
+
573 925
     /* Format 18: unconditional branch
574 926
      *  B label
575 927
      */
576 928
     else if((instr & 0xf800) == 0xe000) {
929
+      uint32_t v;
577 930
       int16_t branchValue = signExtend11(instr & 0x07ff);
578 931
 
579 932
       /* Branch distance is twice that specified in the instruction. */
@@ -590,9 +943,17 @@ UnwResult UnwStartThumb(UnwState * const state) {
590 943
        */
591 944
       state->regData[15].v += 2;
592 945
 
946
+      /* Compute the jump address */
947
+      v = state->regData[15].v + 2;
948
+
593 949
       /* Display PC of next instruction */
594
-      UnwPrintd2(" New PC=%x", state->regData[15].v + 2);
950
+      UnwPrintd2(" New PC=%x", v);
951
+
952
+      /* Did we detect an infinite loop ? */
953
+      loopDetected = lastJumpAddr == v;
595 954
 
955
+      /* Remember the last address we jumped to  */
956
+      lastJumpAddr = v;
596 957
     }
597 958
     else {
598 959
       UnwPrintd1("????");

+ 4
- 41
Marlin/src/HAL/HAL_DUE/backtrace/unwinder.c View File

@@ -22,55 +22,18 @@
22 22
 #include "unwarm.h"
23 23
 #include "unwarmbytab.h"
24 24
 
25
-
26
-/* These symbols point to the start and end of stack */
27
-extern const int _sstack;
28
-extern const int _estack;
29
-
30
-/* These symbols point to the start and end of the code section */
31
-extern const int _sfixed;
32
-extern const int _efixed;
33
-
34
-/* These symbols point to the start and end of initialized data (could be SRAM functions!) */
35
-extern const int _srelocate;
36
-extern const int _erelocate;
37
-
38
-
39
-/* Validate stack pointer (SP): It must be in the stack area */
40
-static inline __attribute__((always_inline)) UnwResult validate_sp(const void* sp) {
41
-
42
-  // SP must point into the allocated stack area
43
-  if ((uint32_t)sp >= (uint32_t)&_sstack && (uint32_t)sp <= (uint32_t)&_estack)
44
-    return UNWIND_SUCCESS;
45
-
46
-  return UNWIND_INVALID_SP;
47
-}
48
-
49
-/* Validate code pointer (PC): It must be either in TEXT or in SRAM */
50
-static inline __attribute__((always_inline)) UnwResult validate_pc(const void* pc) {
51
-
52
-  // PC must point into the text (CODE) area
53
-  if ((uint32_t)pc >= (uint32_t)&_sfixed && (uint32_t)pc <= (uint32_t)&_efixed)
54
-    return UNWIND_SUCCESS;
55
-
56
-  // Or into the SRAM function area
57
-  if ((uint32_t)pc >= (uint32_t)&_srelocate && (uint32_t)pc <= (uint32_t)&_erelocate)
58
-    return UNWIND_SUCCESS;
59
-
60
-  return UNWIND_INVALID_PC;
61
-}
62
-
63 25
 /* These symbols point to the unwind index and should be provide by the linker script */
64 26
 extern const UnwTabEntry __exidx_start[];
65 27
 extern const UnwTabEntry __exidx_end[];
66 28
 
67 29
 // Detect if unwind information is present or not
68 30
 static int HasUnwindTableInfo(void) {
69
-  return ((char*)(&__exidx_end) - (char*)(&__exidx_start)) > 16 ? 1 : 0; // 16 because there are default entries we can´t supress
31
+  // > 16 because there are default entries we can´t supress
32
+  return ((char*)(&__exidx_end) - (char*)(&__exidx_start)) > 16 ? 1 : 0;
70 33
 }
71 34
 
72
-UnwResult UnwindStart(UnwindFrame* frame, const UnwindCallbacks *cb, void *data)
73
-{
35
+UnwResult UnwindStart(UnwindFrame* frame, const UnwindCallbacks *cb, void *data) {
36
+
74 37
   if (HasUnwindTableInfo()) {
75 38
 
76 39
     /* We have unwind information tables */

+ 6
- 1
Marlin/src/HAL/HAL_DUE/backtrace/unwinder.h View File

@@ -149,7 +149,7 @@ typedef struct {
149 149
 
150 150
 #if defined(UNW_DEBUG)
151 151
   /** Print a formatted line for debug. */
152
-  int (*printf)(const char *format, ...);
152
+  void (*printf)(const char *format, ...);
153 153
 #endif
154 154
 } UnwindCallbacks;
155 155
 
@@ -169,6 +169,11 @@ extern "C" {
169 169
  * This will unwind the stack starting at the PC value supplied to in the
170 170
  * link register (i.e. not a normal register) and the stack pointer value
171 171
  * supplied.
172
+ *
173
+ * -If the program was compiled with -funwind-tables , it will use them to
174
+ * perform the traceback. Otherwise, brute force will be employed
175
+ * -If the program was compiled with -mpoke-function-name, then you will
176
+ * get function names in the traceback. Otherwise, you will not.
172 177
  */
173 178
 UnwResult UnwindStart(UnwindFrame* frame, const UnwindCallbacks *cb, void *data);
174 179
 

Loading…
Cancel
Save