浏览代码

Tons of fixes to the backtracker code, and also added an extra backtracker that does not require unwind tables to work and it is used if unwind tables are absent

ejtagle 6 年前
父节点
当前提交
9a24c0ae3f

+ 79
- 7
Marlin/src/HAL/HAL_DUE/DebugMonitor_Due.cpp 查看文件

@@ -24,7 +24,7 @@
24 24
 
25 25
 #include "../../inc/MarlinConfig.h"
26 26
 #include "../../Marlin.h"
27
-#include "backtrace/backtrace.h"
27
+#include "backtrace/unwinder.h"
28 28
 
29 29
 // Debug monitor that dumps to the Programming port all status when
30 30
 // an exception or WDT timeout happens - And then resets the board
@@ -34,6 +34,19 @@
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
+
37 50
 // A SW memory barrier, to ensure GCC does not overoptimize loops
38 51
 #define sw_barrier() asm volatile("": : :"memory");
39 52
 
@@ -112,13 +125,72 @@ static void TXDec(uint32_t v) {
112 125
   } while (p != &nbrs[0]);
113 126
 }
114 127
 
128
+/* 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;
134
+
135
+  // Or into the SRAM function area
136
+  if (addr >= (uint32_t)&_srelocate && addr <= (uint32_t)&_erelocate)
137
+    return true;
138
+
139
+  // SP must point into the allocated stack area
140
+  if (addr >= (uint32_t)&_sstack && addr <= (uint32_t)&_estack)
141
+    return true;
142
+
143
+  return false;
144
+}
145
+
146
+static bool UnwReadW(const uint32_t a, uint32_t *v) {
147
+
148
+  if (!validate_addr(a))
149
+    return false;
150
+
151
+  *v = *(uint32_t *)a;
152
+  return true;
153
+}
154
+
155
+static bool UnwReadH(const uint32_t a, uint16_t *v) {
156
+
157
+  if (!validate_addr(a))
158
+    return false;
159
+
160
+  *v = *(uint16_t *)a;
161
+  return true;
162
+}
163
+
164
+static bool UnwReadB(const uint32_t a, uint8_t *v) {
165
+
166
+  if (!validate_addr(a))
167
+    return false;
168
+
169
+  *v = *(uint8_t *)a;
170
+  return true;
171
+}
172
+
173
+
115 174
 // Dump a backtrace entry
116
-static void backtrace_dump_fn(int idx, const backtrace_t* bte, void* ctx) {
117
-  TX('#'); TXDec(idx); TX(' ');
118
-  TX(bte->name); TX('@');TXHex((uint32_t)bte->function); TX('+'); TXDec((uint32_t)bte->address - (uint32_t)bte->function);
119
-  TX(" PC:");TXHex((uint32_t)bte->address); TX('\n');
175
+static bool UnwReportOut(void* ctx, const UnwReport* bte) {
176
+
177
+  TX(bte->name?bte->name:"unknown"); TX('@');TXHex(bte->function);
178
+  TX('+'); TXDec(bte->address - bte->function);
179
+  TX(" PC:");TXHex(bte->address); TX('\n');
180
+  return true;
120 181
 }
121 182
 
183
+/* Table of function pointers for passing to the unwinder */
184
+static const UnwindCallbacks UnwCallbacks = {
185
+  UnwReportOut,
186
+  UnwReadW,
187
+  UnwReadH,
188
+  UnwReadB
189
+#if defined(UNW_DEBUG)
190
+ ,printf
191
+#endif
192
+};
193
+
122 194
 /**
123 195
  * HardFaultHandler_C:
124 196
  * This is called from the HardFault_HandlerAsm with a pointer the Fault stack
@@ -171,12 +243,12 @@ void HardFault_HandlerC(unsigned long *hardfault_args, unsigned long cause) {
171 243
 
172 244
   // Perform a backtrace
173 245
   TX("\nBacktrace:\n\n");
174
-  backtrace_frame_t btf;
246
+  UnwindFrame btf;
175 247
   btf.sp = ((unsigned long)hardfault_args[7]);
176 248
   btf.fp = btf.sp;
177 249
   btf.lr = ((unsigned long)hardfault_args[5]);
178 250
   btf.pc = ((unsigned long)hardfault_args[6]);
179
-  backtrace_dump(&btf, backtrace_dump_fn, nullptr);
251
+  UnwindStart(&btf, &UnwCallbacks, nullptr);
180 252
 
181 253
   // Disable all NVIC interrupts
182 254
   NVIC->ICER[0] = 0xFFFFFFFF;

+ 0
- 544
Marlin/src/HAL/HAL_DUE/backtrace/backtrace.c 查看文件

@@ -1,544 +0,0 @@
1
-/*
2
- * Libbacktrace
3
- * Copyright 2015 Stephen Street <stephen@redrocketcomputing.com>
4
- *
5
- * This Source Code Form is subject to the terms of the Mozilla Public
6
- * License, v. 2.0. If a copy of the MPL was not distributed with this
7
- * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8
- *
9
- * This library was modified, some bugs fixed, stack address validated
10
- * and adapted to be used in Marlin 3D printer firmware as backtracer
11
- * for exceptions for debugging purposes in 2018 by Eduardo José Tagle.
12
- */
13
-
14
-#ifdef ARDUINO_ARCH_SAM
15
-
16
-#include "backtrace.h"
17
-
18
-#include <stdint.h>
19
-#include <string.h>
20
-
21
-typedef struct unwind_control_block {
22
-  uint32_t vrs[16];
23
-  const uint32_t *current;
24
-  int remaining;
25
-  int byte;
26
-} unwind_control_block_t;
27
-
28
-typedef struct unwind_index {
29
-  uint32_t addr_offset;
30
-  uint32_t insn;
31
-} unwind_index_t;
32
-
33
-/* These symbols point to the unwind index and should be provide by the linker script */
34
-extern const unwind_index_t __exidx_start[];
35
-extern const unwind_index_t __exidx_end[];
36
-
37
-/* This prevents the linking of libgcc unwinder code */
38
-void __aeabi_unwind_cpp_pr0(void) {};
39
-void __aeabi_unwind_cpp_pr1(void) {};
40
-void __aeabi_unwind_cpp_pr2(void) {};
41
-
42
-/* These symbols point to the start and end of stack */
43
-extern const int _sstack;
44
-extern const int _estack;
45
-
46
-/* These symbols point to the start and end of the code section */
47
-extern const int _sfixed;
48
-extern const int _efixed;
49
-
50
-/* These symbols point to the start and end of initialized data (could be SRAM functions!) */
51
-extern const int _srelocate;
52
-extern const int _erelocate;
53
-
54
-/* Validate stack pointer (SP): It must be in the stack area */
55
-static inline __attribute__((always_inline)) int validate_sp(const void* sp) {
56
-  // SP must point into the allocated stack area
57
-  if ((uint32_t)sp >= (uint32_t)&_sstack && (uint32_t)sp <= (uint32_t)&_estack)
58
-    return 0;
59
-  return -1;
60
-}
61
-
62
-/* Validate code pointer (PC): It must be either in TEXT or in SRAM */
63
-static inline __attribute__((always_inline)) int validate_pc(const void* pc) {
64
-  // PC must point into the text (CODE) area
65
-  if ((uint32_t)pc >= (uint32_t)&_sfixed && (uint32_t)pc <= (uint32_t)&_efixed)
66
-    return 0;
67
-  // Or into the SRAM function area
68
-  if ((uint32_t)pc >= (uint32_t)&_srelocate && (uint32_t)pc <= (uint32_t)&_erelocate)
69
-    return 0;
70
-  return 0;
71
-}
72
-
73
-static inline __attribute__((always_inline)) uint32_t prel31_to_addr(const uint32_t *prel31) {
74
-  int32_t offset = (((int32_t)(*prel31)) << 1) >> 1;
75
-  return ((uint32_t)prel31 + offset) & 0x7fffffff;
76
-}
77
-
78
-static const struct unwind_index *unwind_search_index(const unwind_index_t *start, const unwind_index_t *end, uint32_t ip) {
79
-  const struct unwind_index *middle;
80
-
81
-  /* Perform a binary search of the unwind index */
82
-  while (start < end - 1) {
83
-    middle = start + ((end - start + 1) >> 1);
84
-    if (ip < prel31_to_addr(&middle->addr_offset))
85
-      end = middle;
86
-    else
87
-      start = middle;
88
-  }
89
-  return start;
90
-}
91
-
92
-static const char *unwind_get_function_name(void *address) {
93
-  uint32_t flag_word = *(uint32_t *)(address - 4);
94
-  if ((flag_word & 0xff000000) == 0xff000000) {
95
-    return (const char *)(address - 4 - (flag_word & 0x00ffffff));
96
-  }
97
-  return "unknown";
98
-}
99
-
100
-static int unwind_get_next_byte(unwind_control_block_t *ucb) {
101
-  int instruction;
102
-
103
-  /* Are there more instructions */
104
-  if (ucb->remaining == 0)
105
-    return -1;
106
-
107
-  /* Extract the current instruction */
108
-  instruction = ((*ucb->current) >> (ucb->byte << 3)) & 0xff;
109
-
110
-  /* Move the next byte */
111
-  --ucb->byte;
112
-  if (ucb->byte < 0) {
113
-    ++ucb->current;
114
-    ucb->byte = 3;
115
-  }
116
-  --ucb->remaining;
117
-
118
-  return instruction;
119
-}
120
-
121
-static int unwind_control_block_init(unwind_control_block_t *ucb, const uint32_t *instructions, const backtrace_frame_t *frame) {
122
-  /* Initialize control block */
123
-  memset(ucb, 0, sizeof(unwind_control_block_t));
124
-  ucb->current = instructions;
125
-
126
-  /* Is a short unwind description */
127
-  if ((*instructions & 0xff000000) == 0x80000000) {
128
-    ucb->remaining = 3;
129
-    ucb->byte = 2;
130
-  /* Is a long unwind description */
131
-  } else if ((*instructions & 0xff000000) == 0x81000000) {
132
-    ucb->remaining = ((*instructions & 0x00ff0000) >> 14) + 2;
133
-    ucb->byte = 1;
134
-  } else
135
-    return -1;
136
-
137
-  /* Initialize the virtual register set */
138
-  ucb->vrs[7] = frame->fp;
139
-  ucb->vrs[13] = frame->sp;
140
-  ucb->vrs[14] = frame->lr;
141
-  ucb->vrs[15] = 0;
142
-
143
-  /* All good */
144
-  return 0;
145
-}
146
-
147
-static int unwind_execute_instruction(unwind_control_block_t *ucb) {
148
-
149
-  int instruction;
150
-  uint32_t mask;
151
-  uint32_t reg;
152
-  uint32_t *vsp;
153
-
154
-  /* Consume all instruction byte */
155
-  while ((instruction = unwind_get_next_byte(ucb)) != -1) {
156
-
157
-    if ((instruction & 0xc0) == 0x00) { // ARM_EXIDX_CMD_DATA_POP
158
-      /* vsp = vsp + (xxxxxx << 2) + 4 */
159
-      ucb->vrs[13] += ((instruction & 0x3f) << 2) + 4;
160
-    } else
161
-    if ((instruction & 0xc0) == 0x40) { // ARM_EXIDX_CMD_DATA_PUSH
162
-      /* vsp = vsp - (xxxxxx << 2) - 4 */
163
-      ucb->vrs[13] -= ((instruction & 0x3f) << 2) - 4;
164
-    } else
165
-    if ((instruction & 0xf0) == 0x80) {
166
-      /* pop under mask {r15-r12},{r11-r4} or refuse to unwind */
167
-      instruction = instruction << 8 | unwind_get_next_byte(ucb);
168
-
169
-      /* Check for refuse to unwind */
170
-      if (instruction == 0x8000)        // ARM_EXIDX_CMD_REFUSED
171
-        return 0;
172
-
173
-      /* Pop registers using mask */    // ARM_EXIDX_CMD_REG_POP
174
-      vsp = (uint32_t *)ucb->vrs[13];
175
-      mask = instruction & 0xfff;
176
-
177
-      reg = 4;
178
-      while (mask) {
179
-        if ((mask & 1) != 0) {
180
-          if (validate_sp(vsp))
181
-            return -1;
182
-          ucb->vrs[reg] = *vsp++;
183
-        }
184
-        mask >>= 1;
185
-        ++reg;
186
-      }
187
-
188
-      /* Patch up the vrs sp if it was in the mask */
189
-      if ((instruction & (1 << (13 - 4))) != 0)
190
-        ucb->vrs[13] = (uint32_t)vsp;
191
-
192
-    } else
193
-    if ((instruction & 0xf0) == 0x90 && // ARM_EXIDX_CMD_REG_TO_SP
194
-        instruction != 0x9d &&
195
-        instruction != 0x9f) {
196
-      /* vsp = r[nnnn] */
197
-      ucb->vrs[13] = ucb->vrs[instruction & 0x0f];
198
-    } else
199
-    if ((instruction & 0xf0) == 0xa0) { // ARM_EXIDX_CMD_REG_POP
200
-      /* pop r4-r[4+nnn] or pop r4-r[4+nnn], r14*/
201
-      vsp = (uint32_t *)ucb->vrs[13];
202
-
203
-      for (reg = 4; reg <= (instruction & 0x07) + 4; ++reg) {
204
-        if (validate_sp(vsp))
205
-          return -1;
206
-        ucb->vrs[reg] = *vsp++;
207
-      }
208
-
209
-      if (instruction & 0x08) { // ARM_EXIDX_CMD_REG_POP
210
-        if (validate_sp(vsp))
211
-          return -1;
212
-        ucb->vrs[14] = *vsp++;
213
-      }
214
-
215
-      ucb->vrs[13] = (uint32_t)vsp;
216
-
217
-    } else
218
-    if (instruction == 0xb0) { // ARM_EXIDX_CMD_FINISH
219
-      /* finished */
220
-      if (ucb->vrs[15] == 0)
221
-        ucb->vrs[15] = ucb->vrs[14];
222
-
223
-      /* All done unwinding */
224
-      return 0;
225
-
226
-    } else
227
-    if (instruction == 0xb1) { // ARM_EXIDX_CMD_REG_POP
228
-      /* pop register under mask {r3,r2,r1,r0} */
229
-      vsp = (uint32_t *)ucb->vrs[13];
230
-      mask = unwind_get_next_byte(ucb);
231
-
232
-      reg = 0;
233
-      while (mask) {
234
-        if ((mask & 1) != 0) {
235
-          if (validate_sp(vsp))
236
-            return -1;
237
-          ucb->vrs[reg] = *vsp++;
238
-        }
239
-        mask >>= 1;
240
-        ++reg;
241
-      }
242
-      ucb->vrs[13] = (uint32_t)vsp;
243
-
244
-    } else
245
-    if (instruction == 0xb2) { // ARM_EXIDX_CMD_DATA_POP
246
-      /* vps = vsp + 0x204 + (uleb128 << 2) */
247
-      ucb->vrs[13] += 0x204 + (unwind_get_next_byte(ucb) << 2);
248
-
249
-    } else
250
-    if (instruction == 0xb3 || // ARM_EXIDX_CMD_VFP_POP
251
-      instruction == 0xc8 ||
252
-      instruction == 0xc9) {
253
-
254
-      /* pop VFP double-precision registers */
255
-      vsp = (uint32_t *)ucb->vrs[13];
256
-
257
-      /* D[ssss]-D[ssss+cccc] */
258
-      if (validate_sp(vsp))
259
-        return -1;
260
-      ucb->vrs[14] = *vsp++;
261
-
262
-      if (instruction == 0xc8) {
263
-        /* D[16+sssss]-D[16+ssss+cccc] */
264
-        ucb->vrs[14] |= 1 << 16;
265
-      }
266
-
267
-      if (instruction != 0xb3) {
268
-        /* D[sssss]-D[ssss+cccc] */
269
-        ucb->vrs[14] |= 1 << 17;
270
-      }
271
-
272
-      ucb->vrs[13] = (uint32_t)vsp;
273
-
274
-    } else
275
-    if ((instruction & 0xf8) == 0xb8 ||
276
-        (instruction & 0xf8) == 0xd0) {
277
-
278
-      /* Pop VFP double precision registers D[8]-D[8+nnn] */
279
-      ucb->vrs[14] = 0x80 | (instruction & 0x07);
280
-
281
-      if ((instruction & 0xf8) == 0xd0) {
282
-        ucb->vrs[14] = 1 << 17;
283
-      }
284
-
285
-    } else
286
-      return -1;
287
-  }
288
-
289
-  return instruction != -1;
290
-}
291
-
292
-static inline __attribute__((always_inline)) uint32_t *read_psp(void) {
293
-  /* Read the current PSP and return its value as a pointer */
294
-  uint32_t psp;
295
-
296
-  __asm volatile (
297
-    "   mrs %0, psp \n"
298
-    : "=r" (psp) : :
299
-  );
300
-
301
-  return (uint32_t*)psp;
302
-}
303
-
304
-static int unwind_frame(backtrace_frame_t *frame) {
305
-
306
-  unwind_control_block_t ucb;
307
-  const unwind_index_t *index;
308
-  const uint32_t *instructions;
309
-  int execution_result;
310
-
311
-  /* Search the unwind index for the matching unwind table */
312
-  index = unwind_search_index(__exidx_start, __exidx_end, frame->pc);
313
-  if (index == NULL)
314
-    return -1;
315
-
316
-  /* Make sure we can unwind this frame */
317
-  if (index->insn == 0x00000001)
318
-    return 0;
319
-
320
-  /* Get the pointer to the first unwind instruction */
321
-  if (index->insn & 0x80000000)
322
-    instructions = &index->insn;
323
-  else
324
-    instructions = (uint32_t *)prel31_to_addr(&index->insn);
325
-
326
-  /* Initialize the unwind control block */
327
-  if (unwind_control_block_init(&ucb, instructions, frame) < 0)
328
-    return -1;
329
-
330
-  /* Execute the unwind instructions */
331
-  while ((execution_result = unwind_execute_instruction(&ucb)) > 0);
332
-  if (execution_result == -1)
333
-    return -1;
334
-
335
-  /* Set the virtual pc to the virtual lr if this is the first unwind */
336
-  if (ucb.vrs[15] == 0)
337
-    ucb.vrs[15] = ucb.vrs[14];
338
-
339
-  /* Check for exception return */
340
-  /* TODO Test with other ARM processors to verify this method. */
341
-  if ((ucb.vrs[15] & 0xf0000000) == 0xf0000000) {
342
-    /* According to the Cortex Programming Manual (p.44), the stack address is always 8-byte aligned (Cortex-M7).
343
-       Depending on where the exception came from (MSP or PSP), we need the right SP value to work with.
344
-
345
-       ucb.vrs[7] contains the right value, so take it and align it by 8 bytes, store it as the current
346
-       SP to work with (ucb.vrs[13]) which is then saved as the current (virtual) frame's SP.
347
-    */
348
-    uint32_t *stack;
349
-    ucb.vrs[13] = (ucb.vrs[7] & ~7);
350
-
351
-    /* If we need to start from the MSP, we need to go down X words to find the PC, where:
352
-        X=2  if it was a non-floating-point exception
353
-        X=20 if it was a floating-point (VFP) exception
354
-
355
-       If we need to start from the PSP, we need to go up exactly 6 words to find the PC.
356
-       See the ARMv7-M Architecture Reference Manual p.594 and Cortex-M7 Processor Programming Manual p.44/p.45 for details.
357
-    */
358
-    if ((ucb.vrs[15] & 0xc) == 0) {
359
-      /* Return to Handler Mode: MSP (0xffffff-1) */
360
-      stack = (uint32_t*)(ucb.vrs[13]);
361
-
362
-      /* The PC is always 2 words down from the MSP, if it was a non-floating-point exception */
363
-      stack -= 2;
364
-
365
-      /* If there was a VFP exception (0xffffffe1), the PC is located another 18 words down */
366
-      if ((ucb.vrs[15] & 0xf0) == 0xe0) {
367
-        stack -= 18;
368
-      }
369
-    }
370
-    else {
371
-      /* Return to Thread Mode: PSP (0xffffff-d) */
372
-      stack = read_psp();
373
-
374
-      /* The PC is always 6 words up from the PSP */
375
-      stack += 6;
376
-    }
377
-
378
-    /* Store the PC */
379
-    ucb.vrs[15] = *stack--;
380
-
381
-    /* Store the LR */
382
-    ucb.vrs[14] = *stack--;
383
-  }
384
-
385
-  /* We are done if current frame pc is equal to the virtual pc, prevent infinite loop */
386
-  if (frame->pc == ucb.vrs[15])
387
-    return 0;
388
-
389
-  /* Update the frame */
390
-  frame->fp = ucb.vrs[7];
391
-  frame->sp = ucb.vrs[13];
392
-  frame->lr = ucb.vrs[14];
393
-  frame->pc = ucb.vrs[15];
394
-
395
-  /* All good */
396
-  return 1;
397
-}
398
-
399
-// Detect if function names are available
400
-static int __attribute__ ((noinline)) has_function_names(void) {
401
-  uint32_t flag_word = ((uint32_t*)&has_function_names)[-1];
402
-  return ((flag_word & 0xff000000) == 0xff000000) ? 1 : 0;
403
-}
404
-
405
-// Detect if unwind information is present or not
406
-static int has_unwind_info(void) {
407
-  return ((char*)(&__exidx_end) - (char*)(&__exidx_start)) > 16 ? 1 : 0; // 16 because there are default entries we can´t supress
408
-}
409
-
410
-int backtrace_dump(backtrace_frame_t *frame, backtrace_dump_fn_t dump_entry, void* ctx )
411
-{
412
-  backtrace_t entry;
413
-  int count = 1;
414
-
415
-  /* If there is no unwind information, perform a RAW try at it. Idea was taken from
416
-   * https://stackoverflow.com/questions/3398664/how-to-get-a-call-stack-backtrace-deeply-embedded-no-library-support
417
-   *
418
-   * And requires code to be compiled with the following flags:
419
-   * -mtpcs-frame -mtpcs-leaf-frame -fno-omit-frame-pointer
420
-   *  With these options, the Stack pointer is automatically
421
-   * pushed to the stack at the beginning of each function.
422
-   */
423
-  if (!has_unwind_info()) {
424
-
425
-    /*
426
-     *  We basically iterate through the current stack finding the
427
-     * following combination of values:
428
-     *  - <Frame Address>
429
-     *  - <Link Address>
430
-     * This combination will occur for each function in the call stack
431
-     */
432
-
433
-    uint32_t previous_frame_address = (uint32_t)frame->sp;
434
-    uint32_t* stack_pointer = (uint32_t*)frame->sp;
435
-
436
-    // loop following stack frames
437
-    while (1) {
438
-
439
-      // Validate stack address
440
-      if (validate_sp(stack_pointer))
441
-        break;
442
-
443
-      // Attempt to obtain next stack pointer
444
-      // The link address should come immediately after
445
-      const uint32_t possible_frame_address = *stack_pointer;
446
-      const uint32_t possible_link_address = *(stack_pointer+1);
447
-
448
-      // Next check that the frame addresss (i.e. stack pointer for the function)
449
-      // and Link address are within an acceptable range
450
-      if(possible_frame_address > previous_frame_address &&
451
-         validate_sp((const void *)possible_frame_address) == 0 &&
452
-        (possible_link_address & 1) != 0 && // in THUMB mode the address will be odd
453
-         validate_pc((const void *)possible_link_address) == 0) {
454
-
455
-        // We found two acceptable values.
456
-        entry.name = "unknown";
457
-        entry.address = (void*)possible_link_address;
458
-        entry.function = 0;
459
-
460
-        // If there are function names, try to solve name
461
-        if (has_function_names()) {
462
-          // Lets find the function name, if possible
463
-
464
-          // Align address to 4 bytes
465
-          uint32_t* pf = (uint32_t*) (((uint32_t)possible_link_address) & (-4));
466
-
467
-          // Scan backwards until we find the function name
468
-          while(validate_pc(pf-1) == 0) {
469
-
470
-            // Get name descriptor value
471
-            uint32_t v = pf[-1];
472
-
473
-            // Check if name descriptor is valid and name is terminated in 0.
474
-            if ((v & 0xffffff00) == 0xff000000 &&
475
-                (v & 0xff) > 1) {
476
-
477
-              // Assume the name was found!
478
-              entry.name = ((const char*)pf) - 4 - (v & 0xff);
479
-              entry.function = (void*)pf;
480
-              break;
481
-            }
482
-
483
-            // Go backwards to the previous word
484
-            --pf;
485
-          }
486
-        }
487
-        dump_entry(count, &entry, ctx);
488
-        ++count;
489
-
490
-        // Update the book-keeping registers for the next search
491
-        previous_frame_address = possible_frame_address;
492
-        stack_pointer = (uint32_t*)(possible_frame_address + 4);
493
-
494
-      } else {
495
-        // Keep iterating through the stack until we find an acceptable combination
496
-        ++stack_pointer;
497
-      }
498
-    }
499
-
500
-  } else {
501
-
502
-    /* Otherwise, unwind information is present. Use it to unwind frames */
503
-    do {
504
-      if (frame->pc == 0) {
505
-        /* Reached __exidx_end. */
506
-        entry.name = "<reached end of unwind table>";
507
-        entry.address = 0;
508
-        entry.function = 0;
509
-        dump_entry(count, &entry, ctx);
510
-        break;
511
-      }
512
-
513
-      if (frame->pc == 0x00000001) {
514
-        /* Reached .cantunwind instruction. */
515
-        entry.name = "<reached .cantunwind>";
516
-        entry.address = 0;
517
-        entry.function = 0;
518
-        dump_entry(count, &entry, ctx);
519
-        break;
520
-      }
521
-
522
-      /* Find the unwind index of the current frame pc */
523
-      const unwind_index_t *index = unwind_search_index(__exidx_start, __exidx_end, frame->pc);
524
-
525
-      /* Clear last bit (Thumb indicator) */
526
-      frame->pc &= 0xfffffffeU;
527
-
528
-      /* Generate the backtrace information */
529
-      entry.address = (void *)frame->pc;
530
-      entry.function = (void *)prel31_to_addr(&index->addr_offset);
531
-      entry.name = unwind_get_function_name(entry.function);
532
-      dump_entry(count, &entry, ctx);
533
-
534
-      /* Next backtrace frame */
535
-      ++count;
536
-
537
-    } while (unwind_frame(frame) == 1);
538
-  }
539
-
540
-  /* All done */
541
-  return count;
542
-}
543
-
544
-#endif

+ 0
- 53
Marlin/src/HAL/HAL_DUE/backtrace/backtrace.h 查看文件

@@ -1,53 +0,0 @@
1
-/*
2
- * Libbacktrace
3
- * Copyright 2015 Stephen Street <stephen@redrocketcomputing.com>
4
- *
5
- * This Source Code Form is subject to the terms of the Mozilla Public
6
- * License, v. 2.0. If a copy of the MPL was not distributed with this
7
- * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8
- *
9
- * This library was modified and adapted to be used in Marlin 3D printer
10
- * firmware as backtracer for exceptions for debugging purposes in 2018
11
- * by Eduardo José Tagle.
12
- */
13
-
14
-/*
15
- * For this library to work, you need to compile with the following options
16
- * -funwind-tables => So we will have unwind information to perform the stack trace
17
- * -mpoke-function-name => So we will have function names in the trace
18
- */
19
-
20
-#ifndef _BACKTRACE_H_
21
-#define _BACKTRACE_H_
22
-
23
-#include <stdint.h>
24
-
25
-#ifdef __cplusplus
26
-extern "C" {
27
-#endif
28
-
29
-/* A frame */
30
-typedef struct backtrace_frame {
31
-  uint32_t fp;
32
-  uint32_t sp;
33
-  uint32_t lr;
34
-  uint32_t pc;
35
-} backtrace_frame_t;
36
-
37
-/* A backtrace */
38
-typedef struct backtrace {
39
-  void *function;
40
-  void *address;
41
-  const char *name;
42
-} backtrace_t;
43
-
44
-typedef void (*backtrace_dump_fn_t)(int idx, const backtrace_t* bte, void* ctx);
45
-
46
-/* Perform a backtrace, given the specified stack start frame */
47
-int backtrace_dump(backtrace_frame_t *startframe, backtrace_dump_fn_t fn, void* ctx );
48
-
49
-#ifdef __cplusplus
50
-}
51
-#endif
52
-
53
-#endif // _BACKTRACE_H_

+ 179
- 0
Marlin/src/HAL/HAL_DUE/backtrace/unwarm.c 查看文件

@@ -0,0 +1,179 @@
1
+/***************************************************************************
2
+ * ARM Stack Unwinder, Michael.McTernan.2001@cs.bris.ac.uk
3
+ * Updated, adapted and several bug fixes on 2018 by Eduardo José Tagle
4
+ *
5
+ * This program is PUBLIC DOMAIN.
6
+ * This means that there is no copyright and anyone is able to take a copy
7
+ * for free and use it as they wish, with or without modifications, and in
8
+ * any context, commercially or otherwise. The only limitation is that I
9
+ * don't guarantee that the software is fit for any purpose or accept any
10
+ * liability for it's use or misuse - this software is without warranty.
11
+ ***************************************************************************
12
+ * File Description: Utility functions and glue for ARM unwinding sub-modules.
13
+ **************************************************************************/
14
+
15
+#ifdef ARDUINO_ARCH_SAM
16
+
17
+#define MODULE_NAME "UNWARM"
18
+
19
+#include <stdint.h>
20
+#include <stdbool.h>
21
+#include <stdio.h>
22
+#include <stdarg.h>
23
+#include <string.h>
24
+#include "unwarm.h"
25
+#include "unwarmmem.h"
26
+
27
+#if defined(UNW_DEBUG)
28
+
29
+/** Printf wrapper.
30
+ * This is used such that alternative outputs for any output can be selected
31
+ * by modification of this wrapper function.
32
+ */
33
+void UnwPrintf(const char *format, ...) {
34
+  va_list args;
35
+
36
+  va_start( args, format );
37
+  vprintf(format, args );
38
+}
39
+#endif
40
+
41
+/** Invalidate all general purpose registers.
42
+ */
43
+void UnwInvalidateRegisterFile(RegData *regFile) {
44
+
45
+  uint8_t t = 0;
46
+  do {
47
+    regFile[t].o = REG_VAL_INVALID;
48
+    t++;
49
+  } while(t < 13);
50
+}
51
+
52
+
53
+/** Initialise the data used for unwinding.
54
+ */
55
+void UnwInitState(UnwState * const state,     /**< Pointer to structure to fill. */
56
+                  const UnwindCallbacks *cb,  /**< Callbacks. */
57
+                  void *rptData,              /**< Data to pass to report function. */
58
+                  uint32_t pcValue,           /**< PC at which to start unwinding. */
59
+                  uint32_t spValue) {         /**< SP at which to start unwinding. */
60
+
61
+  UnwInvalidateRegisterFile(state->regData);
62
+
63
+  /* Store the pointer to the callbacks */
64
+  state->cb = cb;
65
+  state->reportData = rptData;
66
+
67
+  /* Setup the SP and PC */
68
+  state->regData[13].v = spValue;
69
+  state->regData[13].o = REG_VAL_FROM_CONST;
70
+  state->regData[15].v = pcValue;
71
+  state->regData[15].o = REG_VAL_FROM_CONST;
72
+
73
+  UnwPrintd3("\nInitial: PC=0x%08x SP=0x%08x\n", pcValue, spValue);
74
+
75
+  /* Invalidate all memory addresses */
76
+  memset(state->memData.used, 0, sizeof(state->memData.used));
77
+}
78
+
79
+// Detect if function names are available
80
+static int __attribute__ ((noinline)) has_function_names(void) {
81
+
82
+  uint32_t flag_word = ((uint32_t*)&has_function_names)[-1];
83
+  return ((flag_word & 0xff000000) == 0xff000000) ? 1 : 0;
84
+}
85
+
86
+/** Call the report function to indicate some return address.
87
+ * This returns the value of the report function, which if true
88
+ * indicates that unwinding may continue.
89
+ */
90
+bool UnwReportRetAddr(UnwState * const state, uint32_t addr) {
91
+
92
+  UnwReport entry;
93
+
94
+  // We found two acceptable values.
95
+  entry.name = NULL;
96
+  entry.address = addr;
97
+  entry.function = 0;
98
+
99
+  // If there are function names, try to solve name
100
+  if (has_function_names()) {
101
+
102
+    // Lets find the function name, if possible
103
+
104
+    // Align address to 4 bytes
105
+    uint32_t pf = addr & (-4);
106
+
107
+    // Scan backwards until we find the function name
108
+    uint32_t v;
109
+    while(state->cb->readW(pf-4,&v)) {
110
+
111
+      // Check if name descriptor is valid and name is terminated in 0.
112
+      if ((v & 0xffffff00) == 0xff000000 &&
113
+          (v & 0xff) > 1) {
114
+
115
+        // Assume the name was found!
116
+        entry.name = ((const char*)pf) - 4 - (v & 0xff);
117
+        entry.function = pf;
118
+        break;
119
+      }
120
+
121
+      // Go backwards to the previous word
122
+      pf -= 4;;
123
+    }
124
+  }
125
+
126
+  /* Cast away const from reportData.
127
+   *  The const is only to prevent the unw module modifying the data.
128
+   */
129
+  return state->cb->report((void *)state->reportData, &entry);
130
+}
131
+
132
+
133
+/** Write some register to memory.
134
+ * This will store some register and meta data onto the virtual stack.
135
+ * The address for the write
136
+ * \param state [in/out]  The unwinding state.
137
+ * \param wAddr [in]  The address at which to write the data.
138
+ * \param reg   [in]  The register to store.
139
+ * \return true if the write was successful, false otherwise.
140
+ */
141
+bool UnwMemWriteRegister(UnwState * const state, const uint32_t addr, const RegData * const reg) {
142
+  return UnwMemHashWrite(&state->memData, addr, reg->v, M_IsOriginValid(reg->o));
143
+}
144
+
145
+/** Read a register from memory.
146
+ * This will read a register from memory, and setup the meta data.
147
+ * If the register has been previously written to memory using
148
+ * UnwMemWriteRegister, the local hash will be used to return the
149
+ * value while respecting whether the data was valid or not.  If the
150
+ * register was previously written and was invalid at that point,
151
+ * REG_VAL_INVALID will be returned in *reg.
152
+ * \param state [in]  The unwinding state.
153
+ * \param addr  [in]  The address to read.
154
+ * \param reg   [out] The result, containing the data value and the origin
155
+ *                     which will be REG_VAL_FROM_MEMORY, or REG_VAL_INVALID.
156
+ * \return true if the address could be read and *reg has been filled in.
157
+ *         false is the data could not be read.
158
+ */
159
+bool UnwMemReadRegister(UnwState * const state, const uint32_t addr, RegData * const reg) {
160
+
161
+  bool tracked;
162
+
163
+  /* Check if the value can be found in the hash */
164
+  if(UnwMemHashRead(&state->memData, addr, &reg->v, &tracked)) {
165
+    reg->o = tracked ? REG_VAL_FROM_MEMORY : REG_VAL_INVALID;
166
+    return true;
167
+  }
168
+  /* Not in the hash, so read from real memory */
169
+  else if(state->cb->readW(addr, &reg->v)) {
170
+    reg->o = REG_VAL_FROM_MEMORY;
171
+    return true;
172
+  }
173
+  /* Not in the hash, and failed to read from memory */
174
+  else {
175
+    return false;
176
+  }
177
+}
178
+#endif
179
+

+ 155
- 0
Marlin/src/HAL/HAL_DUE/backtrace/unwarm.h 查看文件

@@ -0,0 +1,155 @@
1
+/***************************************************************************
2
+ * ARM Stack Unwinder, Michael.McTernan.2001@cs.bris.ac.uk
3
+ *
4
+ * This program is PUBLIC DOMAIN.
5
+ * This means that there is no copyright and anyone is able to take a copy
6
+ * for free and use it as they wish, with or without modifications, and in
7
+ * any context, commerically or otherwise. The only limitation is that I
8
+ * don't guarantee that the software is fit for any purpose or accept any
9
+ * liablity for it's use or misuse - this software is without warranty.
10
+ ***************************************************************************
11
+ * File Description: Internal interface between the ARM unwinding sub-modules.
12
+ **************************************************************************/
13
+
14
+#ifndef UNWARM_H
15
+#define UNWARM_H
16
+
17
+#include "unwinder.h"
18
+
19
+/** The maximum number of instructions to interpet in a function.
20
+ * Unwinding will be unconditionally stopped and UNWIND_EXHAUSTED returned
21
+ * if more than this number of instructions are interpreted in a single
22
+ * function without unwinding a stack frame.  This prevents infinite loops
23
+ * or corrupted program memory from preventing unwinding from progressing.
24
+ */
25
+#define UNW_MAX_INSTR_COUNT 500
26
+
27
+/** The size of the hash used to track reads and writes to memory.
28
+ * This should be a prime value for efficiency.
29
+ */
30
+#define MEM_HASH_SIZE       31
31
+
32
+/***************************************************************************
33
+ * Type Definitions
34
+ **************************************************************************/
35
+
36
+typedef enum {
37
+  /** Invalid value. */
38
+  REG_VAL_INVALID     = 0x00,
39
+  REG_VAL_FROM_STACK  = 0x01,
40
+  REG_VAL_FROM_MEMORY = 0x02,
41
+  REG_VAL_FROM_CONST  = 0x04,
42
+  REG_VAL_ARITHMETIC  = 0x80
43
+} RegValOrigin;
44
+
45
+
46
+/** Type for tracking information about a register.
47
+ * This stores the register value, as well as other data that helps unwinding.
48
+ */
49
+typedef struct {
50
+
51
+  /** The value held in the register. */
52
+  uint32_t v;
53
+
54
+  /** The origin of the register value.
55
+   * This is used to track how the value in the register was loaded.
56
+   */
57
+  RegValOrigin o;
58
+} RegData;
59
+
60
+
61
+/** Structure used to track reads and writes to memory.
62
+ * This structure is used as a hash to store a small number of writes
63
+ * to memory.
64
+ */
65
+typedef struct {
66
+  /** Memory contents. */
67
+  uint32_t v[MEM_HASH_SIZE];
68
+
69
+  /** Address at which v[n] represents. */
70
+  uint32_t a[MEM_HASH_SIZE];
71
+
72
+  /** Indicates whether the data in v[n] and a[n] is occupied.
73
+   * Each bit represents one hash value.
74
+   */
75
+  uint8_t used[(MEM_HASH_SIZE + 7) / 8];
76
+
77
+  /** Indicates whether the data in v[n] is valid.
78
+   * This allows a[n] to be set, but for v[n] to be marked as invalid.
79
+   * Specifically this is needed for when an untracked register value
80
+   * is written to memory.
81
+   */
82
+  uint8_t tracked[(MEM_HASH_SIZE + 7) / 8];
83
+} MemData;
84
+
85
+
86
+/** Structure that is used to keep track of unwinding meta-data.
87
+ * This data is passed between all the unwinding functions.
88
+ */
89
+typedef struct {
90
+  /** The register values and meta-data. */
91
+  RegData regData[16];
92
+
93
+  /** Memory tracking data. */
94
+  MemData memData;
95
+
96
+  /** Pointer to the callback functions */
97
+  const UnwindCallbacks *cb;
98
+
99
+  /** Pointer to pass to the report function. */
100
+  const void *reportData;
101
+} UnwState;
102
+
103
+/***************************************************************************
104
+ *  Macros
105
+ **************************************************************************/
106
+
107
+#define M_IsOriginValid(v) (((v) & 0x7f) ? true : false)
108
+#define M_Origin2Str(v)    ((v) ? "VALID" : "INVALID")
109
+
110
+#if defined(UNW_DEBUG)
111
+#define UnwPrintd1(a)               state->cb->printf(a)
112
+#define UnwPrintd2(a,b)             state->cb->printf(a,b)
113
+#define UnwPrintd3(a,b,c)           state->cb->printf(a,b,c)
114
+#define UnwPrintd4(a,b,c,d)         state->cb->printf(a,b,c,d)
115
+#define UnwPrintd5(a,b,c,d,e)       state->cb->printf(a,b,c,d,e)
116
+#define UnwPrintd6(a,b,c,d,e,f)     state->cb->printf(a,b,c,d,e,f)
117
+#define UnwPrintd7(a,b,c,d,e,f,g)   state->cb->printf(a,b,c,d,e,f,g)
118
+#define UnwPrintd8(a,b,c,d,e,f,g,h) state->cb->printf(a,b,c,d,e,f,g,h)
119
+#else
120
+#define UnwPrintd1(a)
121
+#define UnwPrintd2(a,b)
122
+#define UnwPrintd3(a,b,c)
123
+#define UnwPrintd4(a,b,c,d)
124
+#define UnwPrintd5(a,b,c,d,e)
125
+#define UnwPrintd6(a,b,c,d,e,f)
126
+#define UnwPrintd7(a,b,c,d,e,f,g)
127
+#define UnwPrintd8(a,b,c,d,e,f,g,h)
128
+#endif
129
+
130
+/***************************************************************************
131
+ *  Function Prototypes
132
+ **************************************************************************/
133
+
134
+#ifdef __cplusplus
135
+extern "C" {
136
+#endif
137
+
138
+UnwResult UnwStartArm(UnwState * const state);
139
+UnwResult UnwStartThumb(UnwState * const state);
140
+void UnwInvalidateRegisterFile(RegData *regFile);
141
+void UnwInitState(UnwState * const state, const UnwindCallbacks *cb, void *rptData, uint32_t pcValue, uint32_t spValue);
142
+bool UnwReportRetAddr(UnwState * const state, uint32_t addr);
143
+bool UnwMemWriteRegister(UnwState * const state, const uint32_t addr, const RegData * const reg);
144
+bool UnwMemReadRegister(UnwState * const state, const uint32_t addr, RegData * const reg);
145
+void UnwMemHashGC(UnwState * const state);
146
+
147
+#ifdef __cplusplus
148
+}
149
+#endif
150
+
151
+#endif /* UNWARM_H */
152
+
153
+/* END OF FILE */
154
+
155
+

+ 597
- 0
Marlin/src/HAL/HAL_DUE/backtrace/unwarm_arm.c 查看文件

@@ -0,0 +1,597 @@
1
+/***************************************************************************
2
+ * ARM Stack Unwinder, Michael.McTernan.2001@cs.bris.ac.uk
3
+ * Updated, adapted and several bug fixes on 2018 by Eduardo José Tagle
4
+ *
5
+ * This program is PUBLIC DOMAIN.
6
+ * This means that there is no copyright and anyone is able to take a copy
7
+ * for free and use it as they wish, with or without modifications, and in
8
+ * any context, commercially or otherwise. The only limitation is that I
9
+ * don't guarantee that the software is fit for any purpose or accept any
10
+ * liability for it's use or misuse - this software is without warranty.
11
+ ***************************************************************************
12
+ * File Description: Abstract interpreter for ARM mode.
13
+ **************************************************************************/
14
+
15
+#ifdef ARDUINO_ARCH_SAM
16
+
17
+#define MODULE_NAME "UNWARM_ARM"
18
+
19
+#include <stdio.h>
20
+#include "unwarm.h"
21
+
22
+/** Check if some instruction is a data-processing instruction.
23
+ * Decodes the passed instruction, checks if it is a data-processing and
24
+ * verifies that the parameters and operation really indicate a data-
25
+ * processing instruction.  This is needed because some parts of the
26
+ * instruction space under this instruction can be extended or represent
27
+ * other operations such as MRS, MSR.
28
+ *
29
+ * \param[in] inst  The instruction word.
30
+ * \retval true  Further decoding of the instruction indicates that this is
31
+ *                a valid data-processing instruction.
32
+ * \retval false This is not a data-processing instruction,
33
+ */
34
+static bool isDataProc(uint32_t instr) {
35
+
36
+  uint8_t opcode = (instr & 0x01e00000) >> 21;
37
+  bool    S      = (instr & 0x00100000) ? true : false;
38
+
39
+  if((instr & 0xfc000000) != 0xe0000000) {
40
+    return false;
41
+  } else
42
+  if(!S && opcode >= 8 && opcode <= 11) {
43
+    /* TST, TEQ, CMP and CMN all require S to be set */
44
+    return false;
45
+  } else {
46
+    return true;
47
+  }
48
+}
49
+
50
+UnwResult UnwStartArm(UnwState * const state) {
51
+
52
+  bool found = false;
53
+  uint16_t   t = UNW_MAX_INSTR_COUNT;
54
+
55
+  do {
56
+    uint32_t instr;
57
+
58
+    /* Attempt to read the instruction */
59
+    if(!state->cb->readW(state->regData[15].v, &instr)) {
60
+      return UNWIND_IREAD_W_FAIL;
61
+    }
62
+
63
+    UnwPrintd4("A %x %x %08x:", state->regData[13].v, state->regData[15].v, instr);
64
+
65
+    /* Check that the PC is still on Arm alignment */
66
+    if(state->regData[15].v & 0x3) {
67
+      UnwPrintd1("\nError: PC misalignment\n");
68
+      return UNWIND_INCONSISTENT;
69
+    }
70
+
71
+    /* Check that the SP and PC have not been invalidated */
72
+    if(!M_IsOriginValid(state->regData[13].o) || !M_IsOriginValid(state->regData[15].o)) {
73
+      UnwPrintd1("\nError: PC or SP invalidated\n");
74
+      return UNWIND_INCONSISTENT;
75
+    }
76
+
77
+    /* Branch and Exchange (BX)
78
+     *  This is tested prior to data processing to prevent
79
+     *  mis-interpretation as an invalid TEQ instruction.
80
+     */
81
+    if((instr & 0xfffffff0) == 0xe12fff10) {
82
+      uint8_t rn = instr & 0xf;
83
+
84
+      UnwPrintd4("BX r%d\t ; r%d %s\n", rn, rn, M_Origin2Str(state->regData[rn].o));
85
+
86
+      if(!M_IsOriginValid(state->regData[rn].o)) {
87
+        UnwPrintd1("\nUnwind failure: BX to untracked register\n");
88
+        return UNWIND_FAILURE;
89
+      }
90
+
91
+      /* Set the new PC value */
92
+      state->regData[15].v = state->regData[rn].v;
93
+
94
+      /* Check if the return value is from the stack */
95
+      if(state->regData[rn].o == REG_VAL_FROM_STACK) {
96
+
97
+        /* Now have the return address */
98
+        UnwPrintd2(" Return PC=%x\n", state->regData[15].v & (~0x1));
99
+
100
+        /* Report the return address */
101
+        if(!UnwReportRetAddr(state, state->regData[rn].v)) {
102
+            return UNWIND_TRUNCATED;
103
+        }
104
+      }
105
+
106
+      /* Determine the return mode */
107
+      if(state->regData[rn].v & 0x1) {
108
+
109
+        /* Branching to THUMB */
110
+        return UnwStartThumb(state);
111
+      }
112
+      else {
113
+
114
+        /* Branch to ARM */
115
+
116
+        /* Account for the auto-increment which isn't needed */
117
+        state->regData[15].v -= 4;
118
+      }
119
+    }
120
+    /* Branch */
121
+    else if((instr & 0xff000000) == 0xea000000) {
122
+
123
+      int32_t offset = (instr & 0x00ffffff);
124
+
125
+      /* Shift value */
126
+      offset = offset << 2;
127
+
128
+      /* Sign extend if needed */
129
+      if(offset & 0x02000000) {
130
+        offset |= 0xfc000000;
131
+      }
132
+
133
+      UnwPrintd2("B %d\n", offset);
134
+
135
+      /* Adjust PC */
136
+      state->regData[15].v += offset;
137
+
138
+      /* Account for pre-fetch, where normally the PC is 8 bytes
139
+       *  ahead of the instruction just executed.
140
+       */
141
+      state->regData[15].v += 4;
142
+    }
143
+
144
+    /* MRS */
145
+    else if((instr & 0xffbf0fff) == 0xe10f0000) {
146
+#if defined(UNW_DEBUG)
147
+      bool R     = (instr & 0x00400000) ? true : false;
148
+#endif
149
+      uint8_t rd = (instr & 0x0000f000) >> 12;
150
+
151
+      UnwPrintd4("MRS r%d,%s\t; r%d invalidated", rd, R ? "SPSR" : "CPSR", rd);
152
+
153
+      /* Status registers untracked */
154
+      state->regData[rd].o = REG_VAL_INVALID;
155
+    }
156
+    /* MSR */
157
+    else if((instr & 0xffb0f000) == 0xe120f000) {
158
+#if defined(UNW_DEBUG)
159
+      bool R = (instr & 0x00400000) ? true : false;
160
+
161
+      UnwPrintd2("MSR %s_?, ???", R ? "SPSR" : "CPSR");
162
+#endif
163
+      /* Status registers untracked.
164
+       *  Potentially this could change processor mode and switch
165
+       *  banked registers r8-r14.  Most likely is that r13 (sp) will
166
+       *  be banked.  However, invalidating r13 will stop unwinding
167
+       *  when potentially this write is being used to disable/enable
168
+       *  interrupts (a common case).  Therefore no invalidation is
169
+       *  performed.
170
+       */
171
+    }
172
+    /* Data processing */
173
+    else if(isDataProc(instr)) {
174
+      bool            I = (instr & 0x02000000) ? true : false;
175
+      uint8_t    opcode = (instr & 0x01e00000) >> 21;
176
+#if defined(UNW_DEBUG)
177
+      bool            S = (instr & 0x00100000) ? true : false;
178
+#endif
179
+      uint8_t        rn = (instr & 0x000f0000) >> 16;
180
+      uint8_t        rd = (instr & 0x0000f000) >> 12;
181
+      uint16_t operand2 = (instr & 0x00000fff);
182
+      uint32_t        op2val;
183
+      RegValOrigin op2origin;
184
+
185
+      switch(opcode) {
186
+        case  0: UnwPrintd4("AND%s r%d,r%d,", S ? "S" : "", rd, rn); break;
187
+        case  1: UnwPrintd4("EOR%s r%d,r%d,", S ? "S" : "", rd, rn); break;
188
+        case  2: UnwPrintd4("SUB%s r%d,r%d,", S ? "S" : "", rd, rn); break;
189
+        case  3: UnwPrintd4("RSB%s r%d,r%d,", S ? "S" : "", rd, rn); break;
190
+        case  4: UnwPrintd4("ADD%s r%d,r%d,", S ? "S" : "", rd, rn); break;
191
+        case  5: UnwPrintd4("ADC%s r%d,r%d,", S ? "S" : "", rd, rn); break;
192
+        case  6: UnwPrintd4("SBC%s r%d,r%d,", S ? "S" : "", rd, rn); break;
193
+        case  7: UnwPrintd4("RSC%s r%d,r%d,", S ? "S" : "", rd, rn); break;
194
+        case  8: UnwPrintd3("TST%s r%d,", S ? "S" : "", rn); break;
195
+        case  9: UnwPrintd3("TEQ%s r%d,", S ? "S" : "", rn); break;
196
+        case 10: UnwPrintd3("CMP%s r%d,", S ? "S" : "", rn); break;
197
+        case 11: UnwPrintd3("CMN%s r%d,", S ? "S" : "", rn); break;
198
+        case 12: UnwPrintd3("ORR%s r%d,", S ? "S" : "", rn); break;
199
+        case 13: UnwPrintd3("MOV%s r%d,", S ? "S" : "", rd); break;
200
+        case 14: UnwPrintd4("BIC%s r%d,r%d", S ? "S" : "", rd, rn); break;
201
+        case 15: UnwPrintd3("MVN%s r%d,", S ? "S" : "", rd); break;
202
+      }
203
+
204
+      /* Decode operand 2 */
205
+      if (I) {
206
+        uint8_t shiftDist  = (operand2 & 0x0f00) >> 8;
207
+        uint8_t shiftConst = (operand2 & 0x00ff);
208
+
209
+        /* rotate const right by 2 * shiftDist */
210
+        shiftDist *= 2;
211
+        op2val    = (shiftConst >> shiftDist) |
212
+                    (shiftConst << (32 - shiftDist));
213
+        op2origin = REG_VAL_FROM_CONST;
214
+
215
+        UnwPrintd2("#0x%x", op2val);
216
+      }
217
+      else {
218
+
219
+        /* Register and shift */
220
+        uint8_t  rm        = (operand2 & 0x000f);
221
+        uint8_t  regShift  = (operand2 & 0x0010) ? true : false;
222
+        uint8_t  shiftType = (operand2 & 0x0060) >> 5;
223
+        uint32_t shiftDist;
224
+#if defined(UNW_DEBUG)
225
+        const char * const shiftMnu[4] = { "LSL", "LSR", "ASR", "ROR" };
226
+#endif
227
+        UnwPrintd2("r%d ", rm);
228
+
229
+        /* Get the shift distance */
230
+        if(regShift) {
231
+
232
+          uint8_t rs = (operand2 & 0x0f00) >> 8;
233
+
234
+          if(operand2 & 0x00800) {
235
+
236
+            UnwPrintd1("\nError: Bit should be zero\n");
237
+            return UNWIND_ILLEGAL_INSTR;
238
+          }
239
+          else if(rs == 15) {
240
+
241
+            UnwPrintd1("\nError: Cannot use R15 with register shift\n");
242
+            return UNWIND_ILLEGAL_INSTR;
243
+          }
244
+
245
+          /* Get shift distance */
246
+          shiftDist = state->regData[rs].v;
247
+          op2origin = state->regData[rs].o;
248
+
249
+          UnwPrintd7("%s r%d\t; r%d %s r%d %s", shiftMnu[shiftType], rs, rm, M_Origin2Str(state->regData[rm].o), rs, M_Origin2Str(state->regData[rs].o));
250
+        }
251
+        else {
252
+          shiftDist = (operand2 & 0x0f80) >> 7;
253
+          op2origin = REG_VAL_FROM_CONST;
254
+
255
+          if(shiftDist) {
256
+            UnwPrintd3("%s #%d", shiftMnu[shiftType], shiftDist);
257
+          }
258
+          UnwPrintd3("\t; r%d %s", rm, M_Origin2Str(state->regData[rm].o));
259
+        }
260
+
261
+        /* Apply the shift type to the source register */
262
+        switch(shiftType) {
263
+          case 0: /* logical left */
264
+            op2val = state->regData[rm].v << shiftDist;
265
+            break;
266
+
267
+          case 1: /* logical right */
268
+            if(!regShift && shiftDist == 0) {
269
+              shiftDist = 32;
270
+            }
271
+
272
+            op2val = state->regData[rm].v >> shiftDist;
273
+            break;
274
+
275
+          case 2: /* arithmetic right */
276
+            if(!regShift && shiftDist == 0) {
277
+              shiftDist = 32;
278
+            }
279
+
280
+            if(state->regData[rm].v & 0x80000000) {
281
+
282
+              /* Register shifts maybe greater than 32 */
283
+              if(shiftDist >= 32) {
284
+                op2val = 0xffffffff;
285
+              }
286
+              else {
287
+                op2val = state->regData[rm].v >> shiftDist;
288
+                op2val |= 0xffffffff << (32 - shiftDist);
289
+              }
290
+            }
291
+            else {
292
+              op2val = state->regData[rm].v >> shiftDist;
293
+            }
294
+            break;
295
+
296
+          case 3: /* rotate right */
297
+
298
+            if(!regShift && shiftDist == 0) {
299
+              /* Rotate right with extend.
300
+               *  This uses the carry bit and so always has an
301
+               *  untracked result.
302
+               */
303
+              op2origin = REG_VAL_INVALID;
304
+              op2val    = 0;
305
+            }
306
+            else {
307
+              /* Limit shift distance to 0-31 incase of register shift */
308
+              shiftDist &= 0x1f;
309
+
310
+              op2val = (state->regData[rm].v >> shiftDist) |
311
+                       (state->regData[rm].v << (32 - shiftDist));
312
+            }
313
+            break;
314
+
315
+          default:
316
+            UnwPrintd2("\nError: Invalid shift type: %d\n", shiftType);
317
+            return UNWIND_FAILURE;
318
+        }
319
+
320
+        /* Decide the data origin */
321
+        if(M_IsOriginValid(op2origin) &&
322
+           M_IsOriginValid(state->regData[rm].o)) {
323
+
324
+          op2origin = state->regData[rm].o;
325
+          op2origin |= REG_VAL_ARITHMETIC;
326
+        }
327
+        else {
328
+          op2origin = REG_VAL_INVALID;
329
+        }
330
+      }
331
+
332
+      /* Propagate register validity */
333
+      switch(opcode) {
334
+        case  0: /* AND: Rd := Op1 AND Op2 */
335
+        case  1: /* EOR: Rd := Op1 EOR Op2 */
336
+        case  2: /* SUB: Rd:= Op1 - Op2 */
337
+        case  3: /* RSB: Rd:= Op2 - Op1 */
338
+        case  4: /* ADD: Rd:= Op1 + Op2 */
339
+        case 12: /* ORR: Rd:= Op1 OR Op2 */
340
+        case 14: /* BIC: Rd:= Op1 AND NOT Op2 */
341
+          if(!M_IsOriginValid(state->regData[rn].o) ||
342
+             !M_IsOriginValid(op2origin)) {
343
+            state->regData[rd].o = REG_VAL_INVALID;
344
+          }
345
+          else {
346
+            state->regData[rd].o = state->regData[rn].o;
347
+            state->regData[rd].o |= op2origin;
348
+          }
349
+          break;
350
+
351
+        case  5: /* ADC: Rd:= Op1 + Op2 + C */
352
+        case  6: /* SBC: Rd:= Op1 - Op2 + C */
353
+        case  7: /* RSC: Rd:= Op2 - Op1 + C */
354
+          /* CPSR is not tracked */
355
+          state->regData[rd].o = REG_VAL_INVALID;
356
+          break;
357
+
358
+        case  8: /* TST: set condition codes on Op1 AND Op2 */
359
+        case  9: /* TEQ: set condition codes on Op1 EOR Op2 */
360
+        case 10: /* CMP: set condition codes on Op1 - Op2 */
361
+        case 11: /* CMN: set condition codes on Op1 + Op2 */
362
+          break;
363
+
364
+        case 13: /* MOV: Rd:= Op2 */
365
+        case 15: /* MVN: Rd:= NOT Op2 */
366
+          state->regData[rd].o = op2origin;
367
+          break;
368
+      }
369
+
370
+      /* Account for pre-fetch by temporarily adjusting PC */
371
+      if(rn == 15) {
372
+
373
+        /* If the shift amount is specified in the instruction,
374
+         *  the PC will be 8 bytes ahead. If a register is used
375
+         *  to specify the shift amount the PC will be 12 bytes
376
+         *  ahead.
377
+         */
378
+        if(!I && (operand2 & 0x0010))
379
+          state->regData[rn].v += 12;
380
+        else
381
+          state->regData[rn].v += 8;
382
+      }
383
+
384
+      /* Compute values */
385
+      switch(opcode) {
386
+        case  0: /* AND: Rd := Op1 AND Op2 */
387
+          state->regData[rd].v = state->regData[rn].v & op2val;
388
+          break;
389
+
390
+        case  1: /* EOR: Rd := Op1 EOR Op2 */
391
+          state->regData[rd].v = state->regData[rn].v ^ op2val;
392
+          break;
393
+
394
+        case  2: /* SUB: Rd:= Op1 - Op2 */
395
+          state->regData[rd].v = state->regData[rn].v - op2val;
396
+          break;
397
+        case  3: /* RSB: Rd:= Op2 - Op1 */
398
+          state->regData[rd].v = op2val - state->regData[rn].v;
399
+          break;
400
+
401
+        case  4: /* ADD: Rd:= Op1 + Op2 */
402
+          state->regData[rd].v = state->regData[rn].v + op2val;
403
+          break;
404
+
405
+        case  5: /* ADC: Rd:= Op1 + Op2 + C */
406
+        case  6: /* SBC: Rd:= Op1 - Op2 + C */
407
+        case  7: /* RSC: Rd:= Op2 - Op1 + C */
408
+        case  8: /* TST: set condition codes on Op1 AND Op2 */
409
+        case  9: /* TEQ: set condition codes on Op1 EOR Op2 */
410
+        case 10: /* CMP: set condition codes on Op1 - Op2 */
411
+        case 11: /* CMN: set condition codes on Op1 + Op2 */
412
+          UnwPrintd1("\t; ????");
413
+          break;
414
+
415
+        case 12: /* ORR: Rd:= Op1 OR Op2 */
416
+          state->regData[rd].v = state->regData[rn].v | op2val;
417
+          break;
418
+
419
+        case 13: /* MOV: Rd:= Op2 */
420
+          state->regData[rd].v = op2val;
421
+          break;
422
+
423
+        case 14: /* BIC: Rd:= Op1 AND NOT Op2 */
424
+          state->regData[rd].v = state->regData[rn].v & (~op2val);
425
+          break;
426
+
427
+        case 15: /* MVN: Rd:= NOT Op2 */
428
+          state->regData[rd].v = ~op2val;
429
+          break;
430
+      }
431
+
432
+      /* Remove the prefetch offset from the PC */
433
+      if(rd != 15 && rn == 15) {
434
+        if(!I && (operand2 & 0x0010))
435
+          state->regData[rn].v -= 12;
436
+        else
437
+          state->regData[rn].v -= 8;
438
+      }
439
+    }
440
+
441
+    /* Block Data Transfer
442
+     *  LDM, STM
443
+     */
444
+    else if((instr & 0xfe000000) == 0xe8000000) {
445
+
446
+      bool     P         = (instr & 0x01000000) ? true : false;
447
+      bool     U         = (instr & 0x00800000) ? true : false;
448
+      bool     S         = (instr & 0x00400000) ? true : false;
449
+      bool     W         = (instr & 0x00200000) ? true : false;
450
+      bool     L         = (instr & 0x00100000) ? true : false;
451
+      uint16_t baseReg   = (instr & 0x000f0000) >> 16;
452
+      uint16_t regList   = (instr & 0x0000ffff);
453
+      uint32_t addr      = state->regData[baseReg].v;
454
+      bool     addrValid = M_IsOriginValid(state->regData[baseReg].o);
455
+      int8_t r;
456
+
457
+#if defined(UNW_DEBUG)
458
+      /* Display the instruction */
459
+      if(L) {
460
+        UnwPrintd6("LDM%c%c r%d%s, {reglist}%s\n", P ? 'E' : 'F', U ? 'D' : 'A', baseReg, W ? "!" : "", S ? "^" : "");
461
+      }
462
+      else {
463
+        UnwPrintd6("STM%c%c r%d%s, {reglist}%s\n", !P ? 'E' : 'F', !U ? 'D' : 'A', baseReg, W ? "!" : "", S ? "^" : "");
464
+      }
465
+#endif
466
+      /* S indicates that banked registers (untracked) are used, unless
467
+       *  this is a load including the PC when the S-bit indicates that
468
+       *  that CPSR is loaded from SPSR (also untracked, but ignored).
469
+       */
470
+      if(S && (!L || (regList & (0x01 << 15)) == 0)) {
471
+        UnwPrintd1("\nError:S-bit set requiring banked registers\n");
472
+        return UNWIND_FAILURE;
473
+      }
474
+      else if(baseReg == 15) {
475
+        UnwPrintd1("\nError: r15 used as base register\n");
476
+        return UNWIND_FAILURE;
477
+      }
478
+      else if(regList == 0) {
479
+        UnwPrintd1("\nError: Register list empty\n");
480
+        return UNWIND_FAILURE;
481
+      }
482
+
483
+      /* Check if ascending or descending.
484
+       *  Registers are loaded/stored in order of address.
485
+       *  i.e. r0 is at the lowest address, r15 at the highest.
486
+       */
487
+      r = U ? 0 : 15;
488
+      do {
489
+
490
+        /* Check if the register is to be transferred */
491
+        if(regList & (0x01 << r)) {
492
+
493
+          if(P)
494
+            addr += U ? 4 : -4;
495
+
496
+          if(L) {
497
+
498
+            if(addrValid) {
499
+
500
+              if(!UnwMemReadRegister(state, addr, &state->regData[r])) {
501
+                return UNWIND_DREAD_W_FAIL;
502
+              }
503
+
504
+              /* Update the origin if read via the stack pointer */
505
+              if(M_IsOriginValid(state->regData[r].o) && baseReg == 13) {
506
+                state->regData[r].o = REG_VAL_FROM_STACK;
507
+              }
508
+
509
+              UnwPrintd5(" R%d = 0x%08x\t; r%d %s\n",r,state->regData[r].v,r, M_Origin2Str(state->regData[r].o));
510
+            }
511
+            else {
512
+
513
+              /* Invalidate the register as the base reg was invalid */
514
+              state->regData[r].o = REG_VAL_INVALID;
515
+
516
+              UnwPrintd2(" R%d = ???\n", r);
517
+            }
518
+          }
519
+          else {
520
+            if(addrValid) {
521
+              if(!UnwMemWriteRegister(state, state->regData[13].v, &state->regData[r])) {
522
+                return UNWIND_DWRITE_W_FAIL;
523
+              }
524
+            }
525
+
526
+            UnwPrintd2(" R%d = 0x%08x\n", r);
527
+          }
528
+
529
+          if(!P)
530
+            addr += U ? 4 : -4;
531
+        }
532
+
533
+        /* Check the next register */
534
+        r += U ? 1 : -1;
535
+
536
+      } while(r >= 0 && r <= 15);
537
+
538
+      /* Check the writeback bit */
539
+      if(W)
540
+        state->regData[baseReg].v = addr;
541
+
542
+      /* Check if the PC was loaded */
543
+      if(L && (regList & (0x01 << 15))) {
544
+        if(!M_IsOriginValid(state->regData[15].o)) {
545
+          /* Return address is not valid */
546
+          UnwPrintd1("PC popped with invalid address\n");
547
+          return UNWIND_FAILURE;
548
+        }
549
+        else {
550
+          /* Store the return address */
551
+          if(!UnwReportRetAddr(state, state->regData[15].v)) {
552
+            return UNWIND_TRUNCATED;
553
+          }
554
+
555
+          UnwPrintd2("  Return PC=0x%x", state->regData[15].v);
556
+
557
+          /* Determine the return mode */
558
+          if(state->regData[15].v & 0x1) {
559
+            /* Branching to THUMB */
560
+            return UnwStartThumb(state);
561
+          }
562
+          else {
563
+            /* Branch to ARM */
564
+
565
+            /* Account for the auto-increment which isn't needed */
566
+            state->regData[15].v -= 4;
567
+          }
568
+        }
569
+      }
570
+    }
571
+    else {
572
+      UnwPrintd1("????");
573
+
574
+      /* Unknown/undecoded.  May alter some register, so invalidate file */
575
+      UnwInvalidateRegisterFile(state->regData);
576
+    }
577
+
578
+    UnwPrintd1("\n");
579
+
580
+    /* Should never hit the reset vector */
581
+    if(state->regData[15].v == 0) return UNWIND_RESET;
582
+
583
+    /* Check next address */
584
+    state->regData[15].v += 4;
585
+
586
+    /* Garbage collect the memory hash (used only for the stack) */
587
+    UnwMemHashGC(state);
588
+
589
+    t--;
590
+    if(t == 0)
591
+      return UNWIND_EXHAUSTED;
592
+
593
+  } while(!found);
594
+
595
+  return UNWIND_UNSUPPORTED;
596
+}
597
+#endif

+ 626
- 0
Marlin/src/HAL/HAL_DUE/backtrace/unwarm_thumb.c 查看文件

@@ -0,0 +1,626 @@
1
+/***************************************************************************
2
+ * ARM Stack Unwinder, Michael.McTernan.2001@cs.bris.ac.uk
3
+ * Updated, adapted and several bug fixes on 2018 by Eduardo José Tagle
4
+ *
5
+ * This program is PUBLIC DOMAIN.
6
+ * This means that there is no copyright and anyone is able to take a copy
7
+ * for free and use it as they wish, with or without modifications, and in
8
+ * any context, commercially or otherwise. The only limitation is that I
9
+ * don't guarantee that the software is fit for any purpose or accept any
10
+ * liability for it's use or misuse - this software is without warranty.
11
+ ***************************************************************************
12
+ * File Description: Abstract interpretation for Thumb mode.
13
+ **************************************************************************/
14
+
15
+#ifdef ARDUINO_ARCH_SAM
16
+
17
+#define MODULE_NAME "UNWARM_THUMB"
18
+
19
+#include <stdio.h>
20
+#include "unwarm.h"
21
+
22
+/** Sign extend an 11 bit value.
23
+ * This function simply inspects bit 11 of the input \a value, and if
24
+ * set, the top 5 bits are set to give a 2's compliment signed value.
25
+ * \param value   The value to sign extend.
26
+ * \return The signed-11 bit value stored in a 16bit data type.
27
+ */
28
+static int16_t signExtend11(uint16_t value) {
29
+
30
+  if(value & 0x400) {
31
+    value |= 0xf800;
32
+  }
33
+
34
+  return value;
35
+}
36
+
37
+UnwResult UnwStartThumb(UnwState * const state) {
38
+
39
+  bool found = false;
40
+  uint16_t t = UNW_MAX_INSTR_COUNT;
41
+
42
+  do {
43
+    uint16_t instr;
44
+
45
+    /* Attempt to read the instruction */
46
+    if(!state->cb->readH(state->regData[15].v & (~0x1), &instr)) {
47
+      return UNWIND_IREAD_H_FAIL;
48
+    }
49
+
50
+    UnwPrintd4("T %x %x %04x:", state->regData[13].v, state->regData[15].v, instr);
51
+
52
+    /* Check that the PC is still on Thumb alignment */
53
+    if(!(state->regData[15].v & 0x1)) {
54
+      UnwPrintd1("\nError: PC misalignment\n");
55
+      return UNWIND_INCONSISTENT;
56
+    }
57
+
58
+    /* Check that the SP and PC have not been invalidated */
59
+    if(!M_IsOriginValid(state->regData[13].o) || !M_IsOriginValid(state->regData[15].o)) {
60
+      UnwPrintd1("\nError: PC or SP invalidated\n");
61
+      return UNWIND_INCONSISTENT;
62
+    }
63
+
64
+    /* Format 1: Move shifted register
65
+     *  LSL Rd, Rs, #Offset5
66
+     *  LSR Rd, Rs, #Offset5
67
+     *  ASR Rd, Rs, #Offset5
68
+     */
69
+    if((instr & 0xe000) == 0x0000 && (instr & 0x1800) != 0x1800) {
70
+      bool signExtend;
71
+      uint8_t op      = (instr & 0x1800) >> 11;
72
+      uint8_t offset5 = (instr & 0x07c0) >>  6;
73
+      uint8_t rs      = (instr & 0x0038) >>  3;
74
+      uint8_t rd      = (instr & 0x0007);
75
+
76
+      switch(op) {
77
+        case 0: /* LSL */
78
+          UnwPrintd6("LSL r%d, r%d, #%d\t; r%d %s", rd, rs, offset5, rs, M_Origin2Str(state->regData[rs].o));
79
+          state->regData[rd].v = state->regData[rs].v << offset5;
80
+          state->regData[rd].o = state->regData[rs].o;
81
+          state->regData[rd].o |= REG_VAL_ARITHMETIC;
82
+          break;
83
+
84
+        case 1: /* LSR */
85
+          UnwPrintd6("LSR r%d, r%d, #%d\t; r%d %s", rd, rs, offset5, rs, M_Origin2Str(state->regData[rs].o));
86
+          state->regData[rd].v = state->regData[rs].v >> offset5;
87
+          state->regData[rd].o = state->regData[rs].o;
88
+          state->regData[rd].o |= REG_VAL_ARITHMETIC;
89
+          break;
90
+
91
+        case 2: /* ASR */
92
+          UnwPrintd6("ASL r%d, r%d, #%d\t; r%d %s", rd, rs, offset5, rs, M_Origin2Str(state->regData[rs].o));
93
+
94
+          signExtend = (state->regData[rs].v & 0x8000) ? true : false;
95
+          state->regData[rd].v = state->regData[rs].v >> offset5;
96
+          if(signExtend) {
97
+            state->regData[rd].v |= 0xffffffff << (32 - offset5);
98
+          }
99
+          state->regData[rd].o = state->regData[rs].o;
100
+          state->regData[rd].o |= REG_VAL_ARITHMETIC;
101
+          break;
102
+      }
103
+    }
104
+    /* Format 2: add/subtract
105
+     *  ADD Rd, Rs, Rn
106
+     *  ADD Rd, Rs, #Offset3
107
+     *  SUB Rd, Rs, Rn
108
+     *  SUB Rd, Rs, #Offset3
109
+     */
110
+    else if((instr & 0xf800) == 0x1800) {
111
+      bool    I  = (instr & 0x0400) ? true : false;
112
+      bool    op = (instr & 0x0200) ? true : false;
113
+      uint8_t rn = (instr & 0x01c0) >> 6;
114
+      uint8_t rs = (instr & 0x0038) >> 3;
115
+      uint8_t rd = (instr & 0x0007);
116
+
117
+      /* Print decoding */
118
+      UnwPrintd6("%s r%d, r%d, %c%d\t;",op ? "SUB" : "ADD",rd, rs,I ? '#' : 'r',rn);
119
+      UnwPrintd5("r%d %s, r%d %s",rd, M_Origin2Str(state->regData[rd].o),rs, M_Origin2Str(state->regData[rs].o));
120
+      if(!I) {
121
+
122
+        UnwPrintd3(", r%d %s", rn, M_Origin2Str(state->regData[rn].o));
123
+
124
+        /* Perform calculation */
125
+        if(op) {
126
+          state->regData[rd].v = state->regData[rs].v - state->regData[rn].v;
127
+        }
128
+        else {
129
+          state->regData[rd].v = state->regData[rs].v + state->regData[rn].v;
130
+        }
131
+
132
+        /* Propagate the origin */
133
+        if(M_IsOriginValid(state->regData[rs].v) &&
134
+           M_IsOriginValid(state->regData[rn].v)) {
135
+          state->regData[rd].o = state->regData[rs].o;
136
+          state->regData[rd].o |= REG_VAL_ARITHMETIC;
137
+        }
138
+        else {
139
+          state->regData[rd].o = REG_VAL_INVALID;
140
+        }
141
+      }
142
+      else {
143
+        /* Perform calculation */
144
+        if(op) {
145
+          state->regData[rd].v = state->regData[rs].v - rn;
146
+        }
147
+        else {
148
+          state->regData[rd].v = state->regData[rs].v + rn;
149
+        }
150
+
151
+        /* Propagate the origin */
152
+        state->regData[rd].o = state->regData[rs].o;
153
+        state->regData[rd].o |= REG_VAL_ARITHMETIC;
154
+      }
155
+    }
156
+    /* Format 3: move/compare/add/subtract immediate
157
+     *  MOV Rd, #Offset8
158
+     *  CMP Rd, #Offset8
159
+     *  ADD Rd, #Offset8
160
+     *  SUB Rd, #Offset8
161
+     */
162
+    else if((instr & 0xe000) == 0x2000) {
163
+
164
+      uint8_t op      = (instr & 0x1800) >> 11;
165
+      uint8_t rd      = (instr & 0x0700) >>  8;
166
+      uint8_t offset8 = (instr & 0x00ff);
167
+
168
+      switch(op) {
169
+        case 0: /* MOV */
170
+          UnwPrintd3("MOV r%d, #0x%x", rd, offset8);
171
+          state->regData[rd].v = offset8;
172
+          state->regData[rd].o = REG_VAL_FROM_CONST;
173
+          break;
174
+
175
+        case 1: /* CMP */
176
+          /* Irrelevant to unwinding */
177
+          UnwPrintd1("CMP ???");
178
+          break;
179
+
180
+        case 2: /* ADD */
181
+          UnwPrintd5("ADD r%d, #0x%x\t; r%d %s", rd, offset8, rd, M_Origin2Str(state->regData[rd].o));
182
+          state->regData[rd].v += offset8;
183
+          state->regData[rd].o |= REG_VAL_ARITHMETIC;
184
+          break;
185
+
186
+        case 3: /* SUB */
187
+          UnwPrintd5("SUB r%d, #0x%d\t; r%d %s", rd, offset8, rd, M_Origin2Str(state->regData[rd].o));
188
+          state->regData[rd].v -= offset8;
189
+          state->regData[rd].o |= REG_VAL_ARITHMETIC;
190
+          break;
191
+      }
192
+    }
193
+    /* Format 4: ALU operations
194
+     *  AND Rd, Rs
195
+     *  EOR Rd, Rs
196
+     *  LSL Rd, Rs
197
+     *  LSR Rd, Rs
198
+     *  ASR Rd, Rs
199
+     *  ADC Rd, Rs
200
+     *  SBC Rd, Rs
201
+     *  ROR Rd, Rs
202
+     *  TST Rd, Rs
203
+     *  NEG Rd, Rs
204
+     *  CMP Rd, Rs
205
+     *  CMN Rd, Rs
206
+     *  ORR Rd, Rs
207
+     *  MUL Rd, Rs
208
+     *  BIC Rd, Rs
209
+     *  MVN Rd, Rs
210
+     */
211
+    else if((instr & 0xfc00) == 0x4000) {
212
+      uint8_t op = (instr & 0x03c0) >> 6;
213
+      uint8_t rs = (instr & 0x0038) >> 3;
214
+      uint8_t rd = (instr & 0x0007);
215
+
216
+#if defined(UNW_DEBUG)
217
+      static const char * const mnu[16] = {
218
+        "AND", "EOR", "LSL", "LSR",
219
+        "ASR", "ADC", "SBC", "ROR",
220
+        "TST", "NEG", "CMP", "CMN",
221
+        "ORR", "MUL", "BIC", "MVN" };
222
+#endif
223
+      /* Print the mnemonic and registers */
224
+      switch(op) {
225
+        case 0: /* AND */
226
+        case 1: /* EOR */
227
+        case 2: /* LSL */
228
+        case 3: /* LSR */
229
+        case 4: /* ASR */
230
+        case 7: /* ROR */
231
+        case 9: /* NEG */
232
+        case 12: /* ORR */
233
+        case 13: /* MUL */
234
+        case 15: /* MVN */
235
+          UnwPrintd8("%s r%d ,r%d\t; r%d %s, r%d %s",mnu[op],rd, rs, rd, M_Origin2Str(state->regData[rd].o), rs, M_Origin2Str(state->regData[rs].o));
236
+          break;
237
+
238
+        case 5: /* ADC */
239
+        case 6: /* SBC */
240
+          UnwPrintd4("%s r%d, r%d", mnu[op], rd, rs);
241
+          break;
242
+
243
+        case 8: /* TST */
244
+        case 10: /* CMP */
245
+        case 11: /* CMN */
246
+          /* Irrelevant to unwinding */
247
+          UnwPrintd2("%s ???", mnu[op]);
248
+          break;
249
+
250
+        case 14: /* BIC */
251
+          UnwPrintd5("r%d ,r%d\t; r%d %s", rd, rs, rs, M_Origin2Str(state->regData[rs].o));
252
+          break;
253
+      }
254
+
255
+      /* Perform operation */
256
+      switch(op) {
257
+        case 0: /* AND */
258
+          state->regData[rd].v &= state->regData[rs].v;
259
+          break;
260
+
261
+        case 1: /* EOR */
262
+          state->regData[rd].v ^= state->regData[rs].v;
263
+          break;
264
+
265
+        case 2: /* LSL */
266
+          state->regData[rd].v <<= state->regData[rs].v;
267
+          break;
268
+
269
+        case 3: /* LSR */
270
+          state->regData[rd].v >>= state->regData[rs].v;
271
+          break;
272
+
273
+        case 4: /* ASR */
274
+          if(state->regData[rd].v & 0x80000000) {
275
+            state->regData[rd].v >>= state->regData[rs].v;
276
+            state->regData[rd].v |= 0xffffffff << (32 - state->regData[rs].v);
277
+          }
278
+          else {
279
+            state->regData[rd].v >>= state->regData[rs].v;
280
+          }
281
+
282
+          break;
283
+
284
+        case 5: /* ADC */
285
+        case 6: /* SBC */
286
+        case 8: /* TST */
287
+        case 10: /* CMP */
288
+        case 11: /* CMN */
289
+          break;
290
+
291
+        case 7: /* ROR */
292
+          state->regData[rd].v = (state->regData[rd].v >> state->regData[rs].v) |
293
+                          (state->regData[rd].v << (32 - state->regData[rs].v));
294
+          break;
295
+
296
+        case 9: /* NEG */
297
+          state->regData[rd].v = -state->regData[rs].v;
298
+          break;
299
+
300
+        case 12: /* ORR */
301
+          state->regData[rd].v |= state->regData[rs].v;
302
+          break;
303
+
304
+        case 13: /* MUL */
305
+          state->regData[rd].v *= state->regData[rs].v;
306
+          break;
307
+
308
+        case 14: /* BIC */
309
+          state->regData[rd].v &= ~state->regData[rs].v;
310
+          break;
311
+
312
+        case 15: /* MVN */
313
+          state->regData[rd].v = ~state->regData[rs].v;
314
+          break;
315
+      }
316
+
317
+      /* Propagate data origins */
318
+      switch(op) {
319
+        case 0: /* AND */
320
+        case 1: /* EOR */
321
+        case 2: /* LSL */
322
+        case 3: /* LSR */
323
+        case 4: /* ASR */
324
+        case 7: /* ROR */
325
+        case 12: /* ORR */
326
+        case 13: /* MUL */
327
+        case 14: /* BIC */
328
+          if(M_IsOriginValid(state->regData[rd].o) && M_IsOriginValid(state->regData[rs].o)) {
329
+            state->regData[rd].o = state->regData[rs].o;
330
+            state->regData[rd].o |= REG_VAL_ARITHMETIC;
331
+          }
332
+          else {
333
+            state->regData[rd].o = REG_VAL_INVALID;
334
+          }
335
+          break;
336
+
337
+        case 5: /* ADC */
338
+        case 6: /* SBC */
339
+          /* C-bit not tracked */
340
+          state->regData[rd].o = REG_VAL_INVALID;
341
+          break;
342
+
343
+        case 8: /* TST */
344
+        case 10: /* CMP */
345
+        case 11: /* CMN */
346
+          /* Nothing propagated */
347
+          break;
348
+
349
+        case 9: /* NEG */
350
+        case 15: /* MVN */
351
+          state->regData[rd].o = state->regData[rs].o;
352
+          state->regData[rd].o |= REG_VAL_ARITHMETIC;
353
+          break;
354
+      }
355
+    }
356
+    /* Format 5: Hi register operations/branch exchange
357
+     *  ADD Rd, Hs
358
+     *  ADD Hd, Rs
359
+     *  ADD Hd, Hs
360
+     */
361
+    else if((instr & 0xfc00) == 0x4400) {
362
+      uint8_t op  = (instr & 0x0300) >> 8;
363
+      bool    h1  = (instr & 0x0080) ? true: false;
364
+      bool    h2  = (instr & 0x0040) ? true: false;
365
+      uint8_t rhs = (instr & 0x0038) >> 3;
366
+      uint8_t rhd = (instr & 0x0007);
367
+
368
+      /* Adjust the register numbers */
369
+      if(h2)
370
+        rhs += 8;
371
+      if(h1)
372
+        rhd += 8;
373
+
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
+      switch(op) {
380
+        case 0: /* ADD */
381
+          UnwPrintd5("ADD r%d, r%d\t; r%d %s", rhd, rhs, rhs, M_Origin2Str(state->regData[rhs].o));
382
+          state->regData[rhd].v += state->regData[rhs].v;
383
+          state->regData[rhd].o  =  state->regData[rhs].o;
384
+          state->regData[rhd].o |= REG_VAL_ARITHMETIC;
385
+          break;
386
+
387
+        case 1: /* CMP */
388
+          /* Irrelevant to unwinding */
389
+          UnwPrintd1("CMP ???");
390
+          break;
391
+
392
+        case 2: /* MOV */
393
+          UnwPrintd5("MOV r%d, r%d\t; r%d %s", rhd, rhs, rhd, M_Origin2Str(state->regData[rhs].o));
394
+          state->regData[rhd].v  = state->regData[rhs].v;
395
+          state->regData[rhd].o  = state->regData[rhd].o;
396
+          break;
397
+
398
+        case 3: /* BX */
399
+          UnwPrintd4("BX r%d\t; r%d %s\n", rhs, rhs, M_Origin2Str(state->regData[rhs].o));
400
+
401
+          /* Only follow BX if the data was from the stack */
402
+          if(state->regData[rhs].o == REG_VAL_FROM_STACK) {
403
+            UnwPrintd2(" Return PC=0x%x\n", state->regData[rhs].v & (~0x1));
404
+
405
+            /* Report the return address, including mode bit */
406
+            if(!UnwReportRetAddr(state, state->regData[rhs].v)) {
407
+              return UNWIND_TRUNCATED;
408
+            }
409
+
410
+            /* Update the PC */
411
+            state->regData[15].v = state->regData[rhs].v;
412
+
413
+            /* Determine the new mode */
414
+            if(state->regData[rhs].v & 0x1) {
415
+              /* Branching to THUMB */
416
+
417
+              /* Account for the auto-increment which isn't needed */
418
+              state->regData[15].v -= 2;
419
+            }
420
+            else {
421
+              /* Branch to ARM */
422
+              return UnwStartArm(state);
423
+            }
424
+          }
425
+          else {
426
+            UnwPrintd4("\nError: BX to invalid register: r%d = 0x%x (%s)\n", rhs, state->regData[rhs].o, M_Origin2Str(state->regData[rhs].o));
427
+            return UNWIND_FAILURE;
428
+          }
429
+      }
430
+    }
431
+    /* Format 9: PC-relative load
432
+     *  LDR Rd,[PC, #imm]
433
+     */
434
+    else if((instr & 0xf800) == 0x4800) {
435
+      uint8_t  rd    = (instr & 0x0700) >> 8;
436
+      uint8_t  word8 = (instr & 0x00ff);
437
+      uint32_t address;
438
+
439
+      /* Compute load address, adding a word to account for prefetch */
440
+      address = (state->regData[15].v & (~0x3)) + 4 + (word8 << 2);
441
+
442
+      UnwPrintd3("LDR r%d, 0x%08x", rd, address);
443
+
444
+      if(!UnwMemReadRegister(state, address, &state->regData[rd])) {
445
+        return UNWIND_DREAD_W_FAIL;
446
+      }
447
+    }
448
+    /* Format 13: add offset to Stack Pointer
449
+     *  ADD sp,#+imm
450
+     *  ADD sp,#-imm
451
+     */
452
+    else if((instr & 0xff00) == 0xB000) {
453
+      uint8_t value = (instr & 0x7f) * 4;
454
+
455
+      /* Check the negative bit */
456
+      if((instr & 0x80) != 0) {
457
+        UnwPrintd2("SUB sp,#0x%x", value);
458
+        state->regData[13].v -= value;
459
+      }
460
+      else {
461
+        UnwPrintd2("ADD sp,#0x%x", value);
462
+        state->regData[13].v += value;
463
+      }
464
+    }
465
+    /* Format 14: push/pop registers
466
+     *  PUSH {Rlist}
467
+     *  PUSH {Rlist, LR}
468
+     *  POP {Rlist}
469
+     *  POP {Rlist, PC}
470
+     */
471
+    else if((instr & 0xf600) == 0xb400) {
472
+      bool    L     = (instr & 0x0800) ? true : false;
473
+      bool    R     = (instr & 0x0100) ? true : false;
474
+      uint8_t rList = (instr & 0x00ff);
475
+
476
+      if(L) {
477
+        uint8_t r;
478
+
479
+        /* Load from memory: POP */
480
+        UnwPrintd2("POP {Rlist%s}\n", R ? ", PC" : "");
481
+
482
+        for(r = 0; r < 8; r++) {
483
+          if(rList & (0x1 << r)) {
484
+
485
+            /* Read the word */
486
+            if(!UnwMemReadRegister(state, state->regData[13].v, &state->regData[r])) {
487
+              return UNWIND_DREAD_W_FAIL;
488
+            }
489
+
490
+            /* Alter the origin to be from the stack if it was valid */
491
+            if(M_IsOriginValid(state->regData[r].o)) {
492
+              state->regData[r].o = REG_VAL_FROM_STACK;
493
+            }
494
+
495
+            state->regData[13].v += 4;
496
+
497
+            UnwPrintd3("  r%d = 0x%08x\n", r, state->regData[r].v);
498
+          }
499
+        }
500
+
501
+        /* Check if the PC is to be popped */
502
+        if(R) {
503
+          /* Get the return address */
504
+          if(!UnwMemReadRegister(state, state->regData[13].v, &state->regData[15])) {
505
+            return UNWIND_DREAD_W_FAIL;
506
+          }
507
+
508
+          /* Alter the origin to be from the stack if it was valid */
509
+          if(!M_IsOriginValid(state->regData[15].o)) {
510
+            /* Return address is not valid */
511
+            UnwPrintd1("PC popped with invalid address\n");
512
+            return UNWIND_FAILURE;
513
+          }
514
+          else {
515
+            /* The bottom bit should have been set to indicate that
516
+             *  the caller was from Thumb.  This would allow return
517
+             *  by BX for interworking APCS.
518
+             */
519
+            if((state->regData[15].v & 0x1) == 0) {
520
+              UnwPrintd2("Warning: Return address not to Thumb: 0x%08x\n", state->regData[15].v);
521
+
522
+              /* Pop into the PC will not switch mode */
523
+              return UNWIND_INCONSISTENT;
524
+            }
525
+
526
+            /* Store the return address */
527
+            if(!UnwReportRetAddr(state, state->regData[15].v)) {
528
+              return UNWIND_TRUNCATED;
529
+            }
530
+
531
+            /* Now have the return address */
532
+            UnwPrintd2(" Return PC=%x\n", state->regData[15].v);
533
+
534
+            /* Update the pc */
535
+            state->regData[13].v += 4;
536
+
537
+            /* Compensate for the auto-increment, which isn't needed here */
538
+            state->regData[15].v -= 2;
539
+          }
540
+        }
541
+      }
542
+      else {
543
+        int8_t r;
544
+
545
+        /* Store to memory: PUSH */
546
+        UnwPrintd2("PUSH {Rlist%s}", R ? ", LR" : "");
547
+
548
+        /* Check if the LR is to be pushed */
549
+        if(R) {
550
+          UnwPrintd3("\n  lr = 0x%08x\t; %s", state->regData[14].v, M_Origin2Str(state->regData[14].o));
551
+
552
+          state->regData[13].v -= 4;
553
+
554
+          /* Write the register value to memory */
555
+          if(!UnwMemWriteRegister(state, state->regData[13].v, &state->regData[14])) {
556
+            return UNWIND_DWRITE_W_FAIL;
557
+          }
558
+        }
559
+
560
+        for(r = 7; r >= 0; r--) {
561
+          if(rList & (0x1 << r)) {
562
+            UnwPrintd4("\n  r%d = 0x%08x\t; %s", r, state->regData[r].v, M_Origin2Str(state->regData[r].o));
563
+
564
+            state->regData[13].v -= 4;
565
+
566
+            if(!UnwMemWriteRegister(state, state->regData[13].v, &state->regData[r])) {
567
+              return UNWIND_DWRITE_W_FAIL;
568
+            }
569
+          }
570
+        }
571
+      }
572
+    }
573
+    /* Format 18: unconditional branch
574
+     *  B label
575
+     */
576
+    else if((instr & 0xf800) == 0xe000) {
577
+      int16_t branchValue = signExtend11(instr & 0x07ff);
578
+
579
+      /* Branch distance is twice that specified in the instruction. */
580
+      branchValue *= 2;
581
+
582
+      UnwPrintd2("B %d \n", branchValue);
583
+
584
+      /* Update PC */
585
+      state->regData[15].v += branchValue;
586
+
587
+      /* Need to advance by a word to account for pre-fetch.
588
+       *  Advance by a half word here, allowing the normal address
589
+       *  advance to account for the other half word.
590
+       */
591
+      state->regData[15].v += 2;
592
+
593
+      /* Display PC of next instruction */
594
+      UnwPrintd2(" New PC=%x", state->regData[15].v + 2);
595
+
596
+    }
597
+    else {
598
+      UnwPrintd1("????");
599
+
600
+      /* Unknown/undecoded.  May alter some register, so invalidate file */
601
+      UnwInvalidateRegisterFile(state->regData);
602
+    }
603
+
604
+    UnwPrintd1("\n");
605
+
606
+    /* Should never hit the reset vector */
607
+    if(state->regData[15].v == 0)
608
+      return UNWIND_RESET;
609
+
610
+    /* Check next address */
611
+    state->regData[15].v += 2;
612
+
613
+    /* Garbage collect the memory hash (used only for the stack) */
614
+    UnwMemHashGC(state);
615
+
616
+    t--;
617
+    if(t == 0)
618
+      return UNWIND_EXHAUSTED;
619
+
620
+  } while(!found);
621
+
622
+  return UNWIND_SUCCESS;
623
+}
624
+
625
+#endif
626
+

+ 443
- 0
Marlin/src/HAL/HAL_DUE/backtrace/unwarmbytab.c 查看文件

@@ -0,0 +1,443 @@
1
+/*
2
+ * Libbacktrace
3
+ * Copyright 2015 Stephen Street <stephen@redrocketcomputing.com>
4
+ *
5
+ * This Source Code Form is subject to the terms of the Mozilla Public
6
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
7
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8
+ *
9
+ * This library was modified, some bugs fixed, stack address validated
10
+ * and adapted to be used in Marlin 3D printer firmware as backtracer
11
+ * for exceptions for debugging purposes in 2018 by Eduardo José Tagle.
12
+ */
13
+
14
+#ifdef ARDUINO_ARCH_SAM
15
+
16
+#include "unwarmbytab.h"
17
+
18
+#include <stdint.h>
19
+#include <string.h>
20
+
21
+/* These symbols point to the unwind index and should be provide by the linker script */
22
+extern const UnwTabEntry __exidx_start[];
23
+extern const UnwTabEntry __exidx_end[];
24
+
25
+/* This prevents the linking of libgcc unwinder code */
26
+void __aeabi_unwind_cpp_pr0(void) {};
27
+void __aeabi_unwind_cpp_pr1(void) {};
28
+void __aeabi_unwind_cpp_pr2(void) {};
29
+
30
+static inline __attribute__((always_inline)) uint32_t prel31_to_addr(const uint32_t *prel31) {
31
+  uint32_t offset = (((uint32_t)(*prel31)) << 1) >> 1;
32
+  return ((uint32_t)prel31 + offset) & 0x7fffffff;
33
+}
34
+
35
+static const UnwTabEntry *UnwTabSearchIndex(const UnwTabEntry *start, const UnwTabEntry *end, uint32_t ip) {
36
+  const UnwTabEntry *middle;
37
+
38
+  /* Perform a binary search of the unwind index */
39
+  while (start < end - 1) {
40
+    middle = start + ((end - start + 1) >> 1);
41
+    if (ip < prel31_to_addr(&middle->addr_offset))
42
+      end = middle;
43
+    else
44
+      start = middle;
45
+  }
46
+  return start;
47
+}
48
+
49
+/*
50
+ * Get the function name or NULL if not found
51
+ */
52
+static const char *UnwTabGetFunctionName(const UnwindCallbacks *cb, uint32_t address) {
53
+  uint32_t flag_word = 0;
54
+  if (!cb->readW(address-4,&flag_word))
55
+    return NULL;
56
+
57
+  if ((flag_word & 0xff000000) == 0xff000000) {
58
+    return (const char *)(address - 4 - (flag_word & 0x00ffffff));
59
+  }
60
+  return NULL;
61
+}
62
+
63
+/**
64
+ * Get the next frame unwinding instruction
65
+ *
66
+ * Return either the instruction or -1 to signal no more instructions
67
+ * are available
68
+ */
69
+static int UnwTabGetNextInstruction(const UnwindCallbacks *cb, UnwTabState *ucb) {
70
+  int instruction;
71
+
72
+  /* Are there more instructions */
73
+  if (ucb->remaining == 0)
74
+    return -1;
75
+
76
+  /* Extract the current instruction */
77
+  uint32_t v = 0;
78
+  if (!cb->readW(ucb->current, &v))
79
+    return -1;
80
+  instruction = (v >> (ucb->byte << 3)) & 0xff;
81
+
82
+  /* Move the next byte */
83
+  --ucb->byte;
84
+  if (ucb->byte < 0) {
85
+    ucb->current += 4;
86
+    ucb->byte = 3;
87
+  }
88
+  --ucb->remaining;
89
+
90
+  return instruction;
91
+}
92
+
93
+/**
94
+ * Initialize the frame unwinding state
95
+ */
96
+static UnwResult UnwTabStateInit(const UnwindCallbacks *cb, UnwTabState *ucb, uint32_t instructions, const UnwindFrame *frame) {
97
+
98
+  /* Initialize control block */
99
+  memset(ucb, 0, sizeof(UnwTabState));
100
+  ucb->current = instructions;
101
+
102
+  /* Is a short unwind description */
103
+  uint32_t v = 0;
104
+  if (!cb->readW(instructions, &v))
105
+    return UNWIND_DREAD_W_FAIL;
106
+
107
+  if ((v & 0xff000000) == 0x80000000) {
108
+    ucb->remaining = 3;
109
+    ucb->byte = 2;
110
+  /* Is a long unwind description */
111
+  } else if ((v & 0xff000000) == 0x81000000) {
112
+    ucb->remaining = ((v & 0x00ff0000) >> 14) + 2;
113
+    ucb->byte = 1;
114
+  } else
115
+    return UNWIND_UNSUPPORTED_DWARF_PERSONALITY;
116
+
117
+  /* Initialize the virtual register set */
118
+  ucb->vrs[7] = frame->fp;
119
+  ucb->vrs[13] = frame->sp;
120
+  ucb->vrs[14] = frame->lr;
121
+  ucb->vrs[15] = 0;
122
+
123
+  /* All good */
124
+  return UNWIND_SUCCESS;
125
+}
126
+
127
+/*
128
+ * Execute unwinding instructions
129
+ */
130
+static UnwResult UnwTabExecuteInstructions(const UnwindCallbacks *cb, UnwTabState *ucb) {
131
+
132
+  UnwResult err;
133
+  int instruction;
134
+  uint32_t mask;
135
+  uint32_t reg;
136
+  uint32_t vsp;
137
+
138
+  /* Consume all instruction byte */
139
+  while ((instruction = UnwTabGetNextInstruction(cb, ucb)) != -1) {
140
+
141
+    if ((instruction & 0xc0) == 0x00) { // ARM_EXIDX_CMD_DATA_POP
142
+      /* vsp = vsp + (xxxxxx << 2) + 4 */
143
+      ucb->vrs[13] += ((instruction & 0x3f) << 2) + 4;
144
+    } else
145
+    if ((instruction & 0xc0) == 0x40) { // ARM_EXIDX_CMD_DATA_PUSH
146
+      /* vsp = vsp - (xxxxxx << 2) - 4 */
147
+      ucb->vrs[13] -= ((instruction & 0x3f) << 2) - 4;
148
+    } else
149
+    if ((instruction & 0xf0) == 0x80) {
150
+      /* pop under mask {r15-r12},{r11-r4} or refuse to unwind */
151
+      instruction = instruction << 8 | UnwTabGetNextInstruction(cb, ucb);
152
+
153
+      /* Check for refuse to unwind */
154
+      if (instruction == 0x8000)        // ARM_EXIDX_CMD_REFUSED
155
+        return UNWIND_REFUSED;
156
+
157
+      /* Pop registers using mask */    // ARM_EXIDX_CMD_REG_POP
158
+      vsp = ucb->vrs[13];
159
+      mask = instruction & 0xfff;
160
+
161
+      reg = 4;
162
+      while (mask) {
163
+        if ((mask & 1) != 0) {
164
+          uint32_t v;
165
+          if (!cb->readW(vsp,&v))
166
+            return UNWIND_DREAD_W_FAIL;
167
+          ucb->vrs[reg] = v;
168
+          v += 4;
169
+        }
170
+        mask >>= 1;
171
+        ++reg;
172
+      }
173
+
174
+      /* Patch up the vrs sp if it was in the mask */
175
+      if ((instruction & (1 << (13 - 4))) != 0)
176
+        ucb->vrs[13] = vsp;
177
+
178
+    } else
179
+    if ((instruction & 0xf0) == 0x90 && // ARM_EXIDX_CMD_REG_TO_SP
180
+        instruction != 0x9d &&
181
+        instruction != 0x9f) {
182
+      /* vsp = r[nnnn] */
183
+      ucb->vrs[13] = ucb->vrs[instruction & 0x0f];
184
+    } else
185
+    if ((instruction & 0xf0) == 0xa0) { // ARM_EXIDX_CMD_REG_POP
186
+      /* pop r4-r[4+nnn] or pop r4-r[4+nnn], r14*/
187
+      vsp = ucb->vrs[13];
188
+
189
+      for (reg = 4; reg <= (instruction & 0x07) + 4; ++reg) {
190
+        uint32_t v;
191
+        if (!cb->readW(vsp,&v))
192
+          return UNWIND_DREAD_W_FAIL;
193
+
194
+        ucb->vrs[reg] = v;
195
+        vsp += 4;
196
+      }
197
+
198
+      if (instruction & 0x08) { // ARM_EXIDX_CMD_REG_POP
199
+        uint32_t v;
200
+        if (!cb->readW(vsp,&v))
201
+          return UNWIND_DREAD_W_FAIL;
202
+        ucb->vrs[14] = v;
203
+        vsp += 4;
204
+      }
205
+
206
+      ucb->vrs[13] = vsp;
207
+
208
+    } else
209
+    if (instruction == 0xb0) { // ARM_EXIDX_CMD_FINISH
210
+      /* finished */
211
+      if (ucb->vrs[15] == 0)
212
+        ucb->vrs[15] = ucb->vrs[14];
213
+
214
+      /* All done unwinding */
215
+      return UNWIND_SUCCESS;
216
+
217
+    } else
218
+    if (instruction == 0xb1) { // ARM_EXIDX_CMD_REG_POP
219
+      /* pop register under mask {r3,r2,r1,r0} */
220
+      vsp = ucb->vrs[13];
221
+      mask = UnwTabGetNextInstruction(cb, ucb);
222
+
223
+      reg = 0;
224
+      while (mask) {
225
+        if ((mask & 1) != 0) {
226
+          uint32_t v;
227
+          if (!cb->readW(vsp,&v))
228
+            return UNWIND_DREAD_W_FAIL;
229
+
230
+          ucb->vrs[reg] = v;
231
+          vsp += 4;
232
+        }
233
+        mask >>= 1;
234
+        ++reg;
235
+      }
236
+      ucb->vrs[13] = (uint32_t)vsp;
237
+
238
+    } else
239
+    if (instruction == 0xb2) { // ARM_EXIDX_CMD_DATA_POP
240
+      /* vps = vsp + 0x204 + (uleb128 << 2) */
241
+      ucb->vrs[13] += 0x204 + (UnwTabGetNextInstruction(cb, ucb) << 2);
242
+
243
+    } else
244
+    if (instruction == 0xb3 || // ARM_EXIDX_CMD_VFP_POP
245
+      instruction == 0xc8 ||
246
+      instruction == 0xc9) {
247
+
248
+      /* pop VFP double-precision registers */
249
+      vsp = ucb->vrs[13];
250
+
251
+      /* D[ssss]-D[ssss+cccc] */
252
+      uint32_t v;
253
+      if (!cb->readW(vsp,&v))
254
+        return UNWIND_DREAD_W_FAIL;
255
+
256
+      ucb->vrs[14] = v;
257
+      vsp += 4;
258
+
259
+      if (instruction == 0xc8) {
260
+        /* D[16+sssss]-D[16+ssss+cccc] */
261
+        ucb->vrs[14] |= 1 << 16;
262
+      }
263
+
264
+      if (instruction != 0xb3) {
265
+        /* D[sssss]-D[ssss+cccc] */
266
+        ucb->vrs[14] |= 1 << 17;
267
+      }
268
+
269
+      ucb->vrs[13] = vsp;
270
+
271
+    } else
272
+    if ((instruction & 0xf8) == 0xb8 ||
273
+        (instruction & 0xf8) == 0xd0) {
274
+
275
+      /* Pop VFP double precision registers D[8]-D[8+nnn] */
276
+      ucb->vrs[14] = 0x80 | (instruction & 0x07);
277
+
278
+      if ((instruction & 0xf8) == 0xd0) {
279
+        ucb->vrs[14] = 1 << 17;
280
+      }
281
+
282
+    } else
283
+      return UNWIND_UNSUPPORTED_DWARF_INSTR;
284
+  }
285
+
286
+  return UNWIND_SUCCESS;
287
+}
288
+
289
+static inline __attribute__((always_inline)) uint32_t read_psp(void) {
290
+
291
+  /* Read the current PSP and return its value as a pointer */
292
+  uint32_t psp;
293
+
294
+  __asm volatile (
295
+    "   mrs %0, psp \n"
296
+    : "=r" (psp) : :
297
+  );
298
+
299
+  return psp;
300
+}
301
+
302
+/*
303
+ * Unwind the specified frame and goto the previous one
304
+ */
305
+static UnwResult UnwTabUnwindFrame(const UnwindCallbacks *cb, UnwindFrame *frame) {
306
+
307
+  UnwResult err;
308
+  UnwTabState ucb;
309
+  const UnwTabEntry *index;
310
+  uint32_t instructions;
311
+
312
+  /* Search the unwind index for the matching unwind table */
313
+  index = UnwTabSearchIndex(__exidx_start, __exidx_end, frame->pc);
314
+
315
+  /* Make sure we can unwind this frame */
316
+  if (index->insn == 0x00000001)
317
+    return UNWIND_SUCCESS;
318
+
319
+  /* Get the pointer to the first unwind instruction */
320
+  if (index->insn & 0x80000000)
321
+    instructions = (uint32_t)&index->insn;
322
+  else
323
+    instructions = prel31_to_addr(&index->insn);
324
+
325
+  /* Initialize the unwind control block */
326
+  if ((err = UnwTabStateInit(cb, &ucb, instructions, frame)) < 0)
327
+    return err;
328
+
329
+  /* Execute the unwind instructions */
330
+  err = UnwTabExecuteInstructions(cb, &ucb);
331
+  if (err < 0)
332
+    return err;
333
+
334
+  /* Set the virtual pc to the virtual lr if this is the first unwind */
335
+  if (ucb.vrs[15] == 0)
336
+    ucb.vrs[15] = ucb.vrs[14];
337
+
338
+  /* Check for exception return */
339
+  /* TODO Test with other ARM processors to verify this method. */
340
+  if ((ucb.vrs[15] & 0xf0000000) == 0xf0000000) {
341
+    /* According to the Cortex Programming Manual (p.44), the stack address is always 8-byte aligned (Cortex-M7).
342
+       Depending on where the exception came from (MSP or PSP), we need the right SP value to work with.
343
+
344
+       ucb.vrs[7] contains the right value, so take it and align it by 8 bytes, store it as the current
345
+       SP to work with (ucb.vrs[13]) which is then saved as the current (virtual) frame's SP.
346
+    */
347
+    uint32_t stack;
348
+    ucb.vrs[13] = (ucb.vrs[7] & ~7);
349
+
350
+    /* If we need to start from the MSP, we need to go down X words to find the PC, where:
351
+        X=2  if it was a non-floating-point exception
352
+        X=20 if it was a floating-point (VFP) exception
353
+
354
+       If we need to start from the PSP, we need to go up exactly 6 words to find the PC.
355
+       See the ARMv7-M Architecture Reference Manual p.594 and Cortex-M7 Processor Programming Manual p.44/p.45 for details.
356
+    */
357
+    if ((ucb.vrs[15] & 0xc) == 0) {
358
+      /* Return to Handler Mode: MSP (0xffffff-1) */
359
+      stack = ucb.vrs[13];
360
+
361
+      /* The PC is always 2 words down from the MSP, if it was a non-floating-point exception */
362
+      stack -= 2*4;
363
+
364
+      /* If there was a VFP exception (0xffffffe1), the PC is located another 18 words down */
365
+      if ((ucb.vrs[15] & 0xf0) == 0xe0) {
366
+        stack -= 18*4;
367
+      }
368
+    }
369
+    else {
370
+      /* Return to Thread Mode: PSP (0xffffff-d) */
371
+      stack = read_psp();
372
+
373
+      /* The PC is always 6 words up from the PSP */
374
+      stack += 6*4;
375
+    }
376
+
377
+    /* Store the PC */
378
+    uint32_t v;
379
+    if (!cb->readW(stack,&v))
380
+      return UNWIND_DREAD_W_FAIL;
381
+    ucb.vrs[15] = v;
382
+    stack -= 4;
383
+
384
+    /* Store the LR */
385
+    if (!cb->readW(stack,&v))
386
+      return UNWIND_DREAD_W_FAIL;
387
+    ucb.vrs[14] = v;
388
+    stack -= 4;
389
+  }
390
+
391
+  /* We are done if current frame pc is equal to the virtual pc, prevent infinite loop */
392
+  if (frame->pc == ucb.vrs[15])
393
+    return UNWIND_SUCCESS;
394
+
395
+  /* Update the frame */
396
+  frame->fp = ucb.vrs[7];
397
+  frame->sp = ucb.vrs[13];
398
+  frame->lr = ucb.vrs[14];
399
+  frame->pc = ucb.vrs[15];
400
+
401
+  /* All good - Continue unwinding */
402
+  return UNWIND_MORE_AVAILABLE;
403
+}
404
+
405
+UnwResult UnwindByTableStart(UnwindFrame* frame, const UnwindCallbacks *cb, void *data) {
406
+
407
+  UnwResult err = UNWIND_SUCCESS;
408
+  UnwReport entry;
409
+
410
+  /* Use DWARF unwind information to unwind frames */
411
+  do {
412
+    if (frame->pc == 0) {
413
+      /* Reached __exidx_end. */
414
+      break;
415
+    }
416
+
417
+    if (frame->pc == 0x00000001) {
418
+      /* Reached .cantunwind instruction. */
419
+      break;
420
+    }
421
+
422
+    /* Find the unwind index of the current frame pc */
423
+    const UnwTabEntry *index = UnwTabSearchIndex(__exidx_start, __exidx_end, frame->pc);
424
+
425
+    /* Clear last bit (Thumb indicator) */
426
+    frame->pc &= 0xfffffffeU;
427
+
428
+    /* Generate the backtrace information */
429
+    entry.address = frame->pc;
430
+    entry.function = prel31_to_addr(&index->addr_offset);
431
+    entry.name = UnwTabGetFunctionName(cb, entry.function);
432
+    if (!cb->report(data,&entry))
433
+      break;
434
+
435
+    /* Unwind frame and repeat */
436
+  } while ((err = UnwTabUnwindFrame(cb, frame)) == UNWIND_MORE_AVAILABLE);
437
+
438
+  /* All done */
439
+  return err;
440
+}
441
+
442
+#endif
443
+

+ 44
- 0
Marlin/src/HAL/HAL_DUE/backtrace/unwarmbytab.h 查看文件

@@ -0,0 +1,44 @@
1
+/***************************************************************************
2
+ * ARM Stack Unwinder, Michael.McTernan.2001@cs.bris.ac.uk
3
+ * Updated, adapted and several bug fixes on 2018 by Eduardo José Tagle
4
+ *
5
+ * This program is PUBLIC DOMAIN.
6
+ * This means that there is no copyright and anyone is able to take a copy
7
+ * for free and use it as they wish, with or without modifications, and in
8
+ * any context, commerically or otherwise. The only limitation is that I
9
+ * don't guarantee that the software is fit for any purpose or accept any
10
+ * liablity for it's use or misuse - this software is without warranty.
11
+ ***************************************************************************
12
+ * File Description: Interface to the memory tracking sub-system.
13
+ **************************************************************************/
14
+
15
+#ifndef UNWARMBYTAB_H
16
+#define UNWARMBYTAB_H
17
+
18
+#include "unwarm.h"
19
+
20
+typedef struct {
21
+  uint32_t vrs[16];
22
+  uint32_t current; /* Address of current byte */
23
+  int remaining;
24
+  int byte;
25
+} UnwTabState;
26
+
27
+typedef struct {
28
+  uint32_t addr_offset;
29
+  uint32_t insn;
30
+} UnwTabEntry;
31
+
32
+#ifdef __cplusplus
33
+extern "C" {
34
+#endif
35
+
36
+UnwResult UnwindByTableStart(UnwindFrame* frame, const UnwindCallbacks *cb, void *data);
37
+
38
+#ifdef __cplusplus
39
+}
40
+#endif
41
+
42
+#endif
43
+
44
+/* END OF FILE */

+ 118
- 0
Marlin/src/HAL/HAL_DUE/backtrace/unwarmmem.c 查看文件

@@ -0,0 +1,118 @@
1
+/***************************************************************************
2
+ * ARM Stack Unwinder, Michael.McTernan.2001@cs.bris.ac.uk
3
+ * Updated, adapted and several bug fixes on 2018 by Eduardo José Tagle
4
+ *
5
+ * This program is PUBLIC DOMAIN.
6
+ * This means that there is no copyright and anyone is able to take a copy
7
+ * for free and use it as they wish, with or without modifications, and in
8
+ * any context, commerically or otherwise. The only limitation is that I
9
+ * don't guarantee that the software is fit for any purpose or accept any
10
+ * liablity for it's use or misuse - this software is without warranty.
11
+ ***************************************************************************
12
+ * File Description: Implementation of the memory tracking sub-system.
13
+ **************************************************************************/
14
+
15
+#ifdef ARDUINO_ARCH_SAM
16
+#define MODULE_NAME "UNWARMMEM"
17
+
18
+#include <stdio.h>
19
+#include "unwarmmem.h"
20
+#include "unwarm.h"
21
+
22
+
23
+#define M_IsIdxUsed(a, v) (((a)[v >> 3] & (1 << (v & 0x7))) ? true : false)
24
+#define M_SetIdxUsed(a, v) ((a)[v >> 3] |= (1 << (v & 0x7)))
25
+#define M_ClrIdxUsed(a, v) ((a)[v >> 3] &= ~(1 << (v & 0x7)))
26
+
27
+/** Search the memory hash to see if an entry is stored in the hash already.
28
+ * This will search the hash and either return the index where the item is
29
+ * stored, or -1 if the item was not found.
30
+ */
31
+static int16_t memHashIndex(MemData * const memData, const uint32_t addr) {
32
+
33
+  const uint16_t v = addr % MEM_HASH_SIZE;
34
+  uint16_t       s = v;
35
+
36
+  do {
37
+    /* Check if the element is occupied */
38
+    if(M_IsIdxUsed(memData->used, s)) {
39
+      /* Check if it is occupied with the sought data */
40
+      if(memData->a[s] == addr) {
41
+        return s;
42
+      }
43
+    }
44
+    else {
45
+      /* Item is free, this is where the item should be stored */
46
+      return s;
47
+    }
48
+
49
+    /* Search the next entry */
50
+    s++;
51
+    if(s > MEM_HASH_SIZE) {
52
+      s = 0;
53
+    }
54
+  } while(s != v);
55
+
56
+  /* Search failed, hash is full and the address not stored */
57
+  return -1;
58
+}
59
+
60
+bool UnwMemHashRead(MemData * const memData, uint32_t addr,uint32_t * const data, bool * const tracked) {
61
+
62
+  int16_t i = memHashIndex(memData, addr);
63
+
64
+  if(i >= 0 && M_IsIdxUsed(memData->used, i) && memData->a[i] == addr) {
65
+    *data    = memData->v[i];
66
+    *tracked = M_IsIdxUsed(memData->tracked, i);
67
+    return true;
68
+  }
69
+  else {
70
+    /* Address not found in the hash */
71
+    return false;
72
+  }
73
+}
74
+
75
+bool UnwMemHashWrite(MemData * const memData, uint32_t addr, uint32_t val, bool valValid) {
76
+
77
+  int16_t i = memHashIndex(memData, addr);
78
+
79
+  if(i < 0){
80
+    /* Hash full */
81
+    return false;
82
+  }
83
+  else {
84
+    /* Store the item */
85
+    memData->a[i] = addr;
86
+    M_SetIdxUsed(memData->used, i);
87
+
88
+    if(valValid)
89
+    {
90
+      memData->v[i] = val;
91
+      M_SetIdxUsed(memData->tracked, i);
92
+    }
93
+    else {
94
+#if defined(UNW_DEBUG)
95
+      memData->v[i] = 0xdeadbeef;
96
+#endif
97
+      M_ClrIdxUsed(memData->tracked, i);
98
+    }
99
+
100
+    return true;
101
+  }
102
+}
103
+
104
+void UnwMemHashGC(UnwState * const state) {
105
+
106
+  const uint32_t minValidAddr = state->regData[13].v;
107
+  MemData * const memData  = &state->memData;
108
+  uint16_t       t;
109
+
110
+  for(t = 0; t < MEM_HASH_SIZE; t++) {
111
+    if(M_IsIdxUsed(memData->used, t) && (memData->a[t] < minValidAddr)) {
112
+      UnwPrintd3("MemHashGC: Free elem %d, addr 0x%08x\n", t, memData->a[t]);
113
+
114
+      M_ClrIdxUsed(memData->used, t);
115
+    }
116
+  }
117
+}
118
+#endif

+ 33
- 0
Marlin/src/HAL/HAL_DUE/backtrace/unwarmmem.h 查看文件

@@ -0,0 +1,33 @@
1
+/***************************************************************************
2
+ * ARM Stack Unwinder, Michael.McTernan.2001@cs.bris.ac.uk
3
+ * Updated, adapted and several bug fixes on 2018 by Eduardo José Tagle
4
+ *
5
+ * This program is PUBLIC DOMAIN.
6
+ * This means that there is no copyright and anyone is able to take a copy
7
+ * for free and use it as they wish, with or without modifications, and in
8
+ * any context, commerically or otherwise. The only limitation is that I
9
+ * don't guarantee that the software is fit for any purpose or accept any
10
+ * liablity for it's use or misuse - this software is without warranty.
11
+ ***************************************************************************
12
+ * File Description: Interface to the memory tracking sub-system.
13
+ **************************************************************************/
14
+
15
+#ifndef UNWARMMEM_H
16
+#define UNWARMMEM_H
17
+
18
+#include "unwarm.h"
19
+
20
+#ifdef __cplusplus
21
+extern "C" {
22
+#endif
23
+
24
+bool UnwMemHashRead(MemData * const memData, uint32_t addr, uint32_t * const data, bool * const tracked);
25
+bool UnwMemHashWrite(MemData * const memData, uint32_t addr, uint32_t val, bool valValid);
26
+void UnwMemHashGC(UnwState * const state);
27
+
28
+#ifdef __cplusplus
29
+}
30
+#endif
31
+
32
+#endif
33
+

+ 98
- 0
Marlin/src/HAL/HAL_DUE/backtrace/unwinder.c 查看文件

@@ -0,0 +1,98 @@
1
+/***************************************************************************
2
+ * ARM Stack Unwinder, Michael.McTernan.2001@cs.bris.ac.uk
3
+ * Updated, adapted and several bug fixes on 2018 by Eduardo José Tagle
4
+ *
5
+ * This program is PUBLIC DOMAIN.
6
+ * This means that there is no copyright and anyone is able to take a copy
7
+ * for free and use it as they wish, with or without modifications, and in
8
+ * any context, commercially or otherwise. The only limitation is that I
9
+ * don't guarantee that the software is fit for any purpose or accept any
10
+ * liability for it's use or misuse - this software is without warranty.
11
+ ***************************************************************************
12
+ * File Description: Implementation of the interface into the ARM unwinder.
13
+ **************************************************************************/
14
+
15
+#ifdef ARDUINO_ARCH_SAM
16
+
17
+#define MODULE_NAME "UNWINDER"
18
+
19
+#include <stdio.h>
20
+#include <string.h>
21
+#include "unwinder.h"
22
+#include "unwarm.h"
23
+#include "unwarmbytab.h"
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
+/* These symbols point to the unwind index and should be provide by the linker script */
64
+extern const UnwTabEntry __exidx_start[];
65
+extern const UnwTabEntry __exidx_end[];
66
+
67
+// Detect if unwind information is present or not
68
+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
70
+}
71
+
72
+UnwResult UnwindStart(UnwindFrame* frame, const UnwindCallbacks *cb, void *data)
73
+{
74
+  if (HasUnwindTableInfo()) {
75
+
76
+    /* We have unwind information tables */
77
+    return UnwindByTableStart(frame, cb, data);
78
+
79
+  } else {
80
+
81
+    /* We don't have unwind information tables */
82
+    UnwState state;
83
+
84
+    /* Initialise the unwinding state */
85
+    UnwInitState(&state, cb, data, frame->pc, frame->sp);
86
+
87
+    /* Check the Thumb bit */
88
+    if(frame->pc & 0x1) {
89
+      return UnwStartThumb(&state);
90
+    }
91
+    else {
92
+      return UnwStartArm(&state);
93
+    }
94
+  }
95
+}
96
+#endif
97
+
98
+

+ 179
- 0
Marlin/src/HAL/HAL_DUE/backtrace/unwinder.h 查看文件

@@ -0,0 +1,179 @@
1
+/***************************************************************************
2
+ * ARM Stack Unwinder, Michael.McTernan.2001@cs.bris.ac.uk
3
+ * Updated, adapted and several bug fixes on 2018 by Eduardo José Tagle
4
+ *
5
+ * This program is PUBLIC DOMAIN.
6
+ * This means that there is no copyright and anyone is able to take a copy
7
+ * for free and use it as they wish, with or without modifications, and in
8
+ * any context, commerically or otherwise. The only limitation is that I
9
+ * don't guarantee that the software is fit for any purpose or accept any
10
+ * liablity for it's use or misuse - this software is without warranty.
11
+ **************************************************************************/
12
+/** \file
13
+ * Interface to the ARM stack unwinding module.
14
+ **************************************************************************/
15
+
16
+#ifndef UNWINDER_H
17
+#define UNWINDER_H
18
+
19
+#include <stdint.h>
20
+#include <stdbool.h>
21
+
22
+/** \def UNW_DEBUG
23
+ * If this define is set, additional information will be produced while
24
+ * unwinding the stack to allow debug of the unwind module itself.
25
+ */
26
+/* #define UNW_DEBUG 1 */
27
+
28
+/***************************************************************************
29
+ * Type Definitions
30
+ **************************************************************************/
31
+
32
+/** Possible results for UnwindStart to return.
33
+ */
34
+typedef enum {
35
+  /** Unwinding was successful and complete. */
36
+  UNWIND_SUCCESS = 0,
37
+
38
+  /** Not an error: More frames are available. */
39
+  UNWIND_MORE_AVAILABLE = 1,
40
+
41
+  /** Unsupported DWARF unwind personality. */
42
+  UNWIND_UNSUPPORTED_DWARF_PERSONALITY = -1,
43
+
44
+  /** Refused to perform unwind. */
45
+  UNWIND_REFUSED = -2,
46
+
47
+  /** Reached an invalid SP. */
48
+  UNWIND_INVALID_SP = -3,
49
+
50
+  /** Reached an invalid PC */
51
+  UNWIND_INVALID_PC = -4,
52
+
53
+  /** Unsupported DWARF instruction */
54
+  UNWIND_UNSUPPORTED_DWARF_INSTR = -5,
55
+
56
+  /** More than UNW_MAX_INSTR_COUNT instructions were interpreted. */
57
+  UNWIND_EXHAUSTED = -6,
58
+
59
+  /** Unwinding stopped because the reporting func returned false. */
60
+  UNWIND_TRUNCATED = -7,
61
+
62
+  /** Read data was found to be inconsistent. */
63
+  UNWIND_INCONSISTENT = -8,
64
+
65
+  /** Unsupported instruction or data found. */
66
+  UNWIND_UNSUPPORTED = -9,
67
+
68
+  /** General failure. */
69
+  UNWIND_FAILURE = -10,
70
+
71
+  /** Illegal instruction. */
72
+  UNWIND_ILLEGAL_INSTR = -11,
73
+
74
+  /** Unwinding hit the reset vector. */
75
+  UNWIND_RESET = -12,
76
+
77
+  /** Failed read for an instruction word. */
78
+  UNWIND_IREAD_W_FAIL = -13,
79
+
80
+  /** Failed read for an instruction half-word. */
81
+  UNWIND_IREAD_H_FAIL = -14,
82
+
83
+  /** Failed read for an instruction byte. */
84
+  UNWIND_IREAD_B_FAIL = -15,
85
+
86
+  /** Failed read for a data word. */
87
+  UNWIND_DREAD_W_FAIL = -16,
88
+
89
+  /** Failed read for a data half-word. */
90
+  UNWIND_DREAD_H_FAIL = -17,
91
+
92
+  /** Failed read for a data byte. */
93
+  UNWIND_DREAD_B_FAIL = -18,
94
+
95
+  /** Failed write for a data word. */
96
+  UNWIND_DWRITE_W_FAIL = -19
97
+
98
+} UnwResult;
99
+
100
+/** A backtrace report */
101
+typedef struct {
102
+  uint32_t function;  /** Starts address of function */
103
+  const char *name;   /** Function name, or null if not available */
104
+  uint32_t address;   /** PC on that function */
105
+} UnwReport;
106
+
107
+/** Type for function pointer for result callback.
108
+ * The function is passed two parameters, the first is a void * pointer,
109
+ * and the second is the return address of the function.  The bottom bit
110
+ * of the passed address indicates the execution mode; if it is set,
111
+ * the execution mode at the return address is Thumb, otherwise it is
112
+ * ARM.
113
+ *
114
+ * The return value of this function determines whether unwinding should
115
+ * continue or not.  If true is returned, unwinding will continue and the
116
+ * report function maybe called again in future.  If false is returned,
117
+ * unwinding will stop with UnwindStart() returning UNWIND_TRUNCATED.
118
+ */
119
+typedef bool (*UnwindReportFunc)(void* data, const UnwReport* bte);
120
+
121
+/** Structure that holds memory callback function pointers.
122
+ */
123
+typedef struct {
124
+
125
+  /** Report an unwind result. */
126
+  UnwindReportFunc report;
127
+
128
+  /** Read a 32 bit word from memory.
129
+   * The memory address to be read is passed as \a address, and
130
+   * \a *val is expected to be populated with the read value.
131
+   * If the address cannot or should not be read, false can be
132
+   * returned to indicate that unwinding should stop.  If true
133
+   * is returned, \a *val is assumed to be valid and unwinding
134
+   * will continue.
135
+   */
136
+  bool (*readW)(const uint32_t address, uint32_t *val);
137
+
138
+  /** Read a 16 bit half-word from memory.
139
+   * This function has the same usage as for readW, but is expected
140
+   * to read only a 16 bit value.
141
+   */
142
+  bool (*readH)(const uint32_t address, uint16_t *val);
143
+
144
+  /** Read a byte from memory.
145
+   * This function has the same usage as for readW, but is expected
146
+   * to read only an 8 bit value.
147
+   */
148
+  bool (*readB)(const uint32_t address, uint8_t  *val);
149
+
150
+#if defined(UNW_DEBUG)
151
+  /** Print a formatted line for debug. */
152
+  int (*printf)(const char *format, ...);
153
+#endif
154
+} UnwindCallbacks;
155
+
156
+/* A frame */
157
+typedef struct {
158
+  uint32_t fp;
159
+  uint32_t sp;
160
+  uint32_t lr;
161
+  uint32_t pc;
162
+} UnwindFrame;
163
+
164
+#ifdef __cplusplus
165
+extern "C" {
166
+#endif
167
+
168
+/** Start unwinding the current stack.
169
+ * This will unwind the stack starting at the PC value supplied to in the
170
+ * link register (i.e. not a normal register) and the stack pointer value
171
+ * supplied.
172
+ */
173
+UnwResult UnwindStart(UnwindFrame* frame, const UnwindCallbacks *cb, void *data);
174
+
175
+#ifdef __cplusplus
176
+}
177
+#endif
178
+
179
+#endif /* UNWINDER_H */

正在加载...
取消
保存