summaryrefslogtreecommitdiff
path: root/arm-riscos-gnueabi/recipes/patches/gccsdk/unixlib-unwind.p
blob: 07290e6e2e6423f36b75b4243698798a62b9421c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
Index: libunixlib/signal/post.c
===================================================================
--- libunixlib/signal/post.c	(revision 7698)
+++ libunixlib/signal/post.c	(working copy)
@@ -267,9 +267,86 @@
 #define FP_OFFSET (-3)
 #endif
 
+#ifdef __ARM_EABI__
+/**
+ * AAPCS does not require the compiler to construct a backtrace structure
+ * in the stack (unlike APCS, which does). This results in FP rarely pointing
+ * at any form of valid stack frame (and, to complicate matters, at the time
+ * of writing, some frames end up with APCS-format frame records, anyway)
+ * which makes it nigh-on impossible to reliably unwind the stack without
+ * additional information). FP is thus often treated as an additional
+ * callee-saved register (i.e. v8) in AAPCS-conformant code.
+ *
+ * Additionally, where frame records are generated, AAPCS has them contain
+ * two entries: previous-FP and LR on entry. There is therefore (unlike APCS)
+ * no way of finding the function entry point from the frame record at all,
+ * even if it did exist.
+ *
+ * So, we cannot trust that FP ever points at a valid stack frame record and
+ * we cannot find function entry points to extract poked function names from.
+ * We can, however, make stack unwinding work if we have some means of
+ * identifying the function in which an arbitrary instruction lies.
+ *
+ * -funwind-tables will result in clang/GCC generating such a data structure,
+ * (an array between __exidx_start and __exidx_end) which will be consulted
+ * by _Unwind_Backtrace() when unwinding the stack.
+ */
+
+#include <unwind.h>
+
+static _Unwind_Reason_Code
+__write_backtrace_cb (_Unwind_Context *ctx, void *pw)
+{
+  _Unwind_Control_Block *ucbp = NULL;
+  const unsigned int *fn;
+
+  ucbp = (_Unwind_Control_Block *) _Unwind_GetGR(ctx, UNWIND_POINTER_REG);
+  fn = (const unsigned int *) ucbp->pr_cache.fnstart;
+
+  fprintf (stderr, "  (%8x) fn: %8x pc: %8x sp: %8x ",
+	   _Unwind_GetGR (ctx, 11), (unsigned int)fn, _Unwind_GetIP (ctx),
+	   _Unwind_GetGR (ctx, 13));
+
+#if PIC
+  /* FIXME: extend this with source location when available.  */
+  const char *lib = NULL;
+  unsigned offset;
+  _swix(SOM_Location,
+	_IN(0) | _OUTR(0,1), _Unwind_GetIP (ctx), &lib, &offset);
+  if (lib)
+    fprintf(stderr, " : %8X : %s\n", offset, lib);
+  else
+#endif
+    {
+      int cplusplus_name;
+      const char *name = extract_name (fn, &cplusplus_name);
+      fprintf (stderr, (cplusplus_name) ? " %s\n" : " %s()\n", name);
+    }
+
+  /* TODO: __ul_callback_fp stuff (might need to save/match lr, instead) */
+
+  return _URC_NO_REASON;
+}
+
 static void
 __write_backtrace_thread (const unsigned int *fp)
 {
+  if (fp != NULL)
+    {
+      /* TODO: thread stack traces */
+      fprintf (stderr, "Thread stack traces not supported\n");
+    }
+  else
+    {
+      _Unwind_Backtrace(__write_backtrace_cb, NULL);
+    }
+
+  fputc ('\n', stderr);
+}
+#else
+static void
+__write_backtrace_thread (const unsigned int *fp)
+{
   /* Running as USR26 or USR32 ?  */
   unsigned int is32bit;
   __asm__ volatile ("SUBS	%[is32bit], r0, r0\n\t" /* Set at least one status flag. */
@@ -306,22 +383,6 @@
 	  break;
 	}
 
-#ifdef __ARM_EABI__
-      const unsigned int * const lr = (unsigned int *)fp[LR_OFFSET];
-      fprintf (stderr, "  (%8x) lr: %8x",
-	       (unsigned int)fp, (unsigned int)lr);
-#if PIC
-      /* FIXME: extend this with source location when available.  */
-      const char *lib = NULL;
-      unsigned offset;
-      _swix(SOM_Location,
-	    _IN(0) | _OUTR(0,1), lr, &lib, &offset);
-      if (lib)
-	fprintf(stderr, " : %8X : %s\n", offset, lib);
-      else
-#endif
-	fputc('\n', stderr);
-#else
       /* Retrieve PC counter.
 	 PC counter has been saved using STMxx ..., { ..., PC } so it can be
 	 8 or 12 bytes away from the STMxx instruction depending on the ARM
@@ -347,10 +408,9 @@
       int cplusplus_name;
       const char *name = extract_name (pc, &cplusplus_name);
       fprintf (stderr, (cplusplus_name) ? " %s\n" : " %s()\n", name);
-#endif
+
       oldfp = fp;
       fp = (const unsigned int *)fp[FP_OFFSET];
-#ifndef __ARM_EABI__
       if (__ul_callbackfp != NULL && fp == __ul_callbackfp)
 	{
 	  /* At &oldfp[1] = cpsr, a1-a4, v1-v6, sl, fp, ip, sp, lr, pc */
@@ -424,18 +484,17 @@
 
 	  fputs ("\n\n", stderr);
 	}
-#endif
     }
 
   fputc ('\n', stderr);
 }
+#endif
 
-
 void
 __write_backtrace (int signo)
 {
 #ifdef __ARM_EABI__
-  register const unsigned int *fp = __builtin_frame_address(0);
+  register const unsigned int *fp = NULL;
 #else
   register const unsigned int *fp __asm ("fp");
 #endif