1 /* C6X ABI compliant unwinding routines
2    Copyright (C) 2011-2016 Free Software Foundation, Inc.
3 
4    This file is free software; you can redistribute it and/or modify it
5    under the terms of the GNU General Public License as published by the
6    Free Software Foundation; either version 3, or (at your option) any
7    later version.
8 
9    This file is distributed in the hope that it will be useful, but
10    WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12    General Public License for more details.
13 
14    Under Section 7 of GPL version 3, you are granted additional
15    permissions described in the GCC Runtime Library Exception, version
16    3.1, as published by the Free Software Foundation.
17 
18    You should have received a copy of the GNU General Public License and
19    a copy of the GCC Runtime Library Exception along with this program;
20    see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
21    <http://www.gnu.org/licenses/>.  */
22 
23 #include "unwind.h"
24 
25 /* We add a prototype for abort here to avoid creating a dependency on
26    target headers.  */
27 extern void abort (void);
28 
29 typedef struct _ZSt9type_info type_info; /* This names C++ type_info type */
30 
31 /* Misc constants.  */
32 #define R_A0 0
33 #define R_A1 1
34 #define R_A2 2
35 #define R_A3 3
36 #define R_A4 4
37 #define R_A5 5
38 #define R_A6 6
39 #define R_A7 7
40 #define R_A8 8
41 #define R_A9 9
42 #define R_A10 10
43 #define R_A11 11
44 #define R_A12 12
45 #define R_A13 13
46 #define R_A14 14
47 #define R_A15 15
48 #define R_B0 16
49 #define R_B1 17
50 #define R_B2 18
51 #define R_B3 19
52 #define R_B4 20
53 #define R_B5 21
54 #define R_B6 22
55 #define R_B7 23
56 #define R_B8 24
57 #define R_B9 25
58 #define R_B10 26
59 #define R_B11 27
60 #define R_B12 28
61 #define R_B13 29
62 #define R_B14 30
63 #define R_B15 31
64 
65 #define R_SP R_B15
66 #define R_PC 33
67 
68 #define uint32_highbit (((_uw) 1) << 31)
69 
70 void __attribute__((weak)) __cxa_call_unexpected(_Unwind_Control_Block *ucbp);
71 
72 /* Unwind descriptors.  */
73 
74 typedef struct
75 {
76   _uw16 length;
77   _uw16 offset;
78 } EHT16;
79 
80 typedef struct
81 {
82   _uw length;
83   _uw offset;
84 } EHT32;
85 
86 /* Calculate the address encoded by a 31-bit self-relative offset at address
87    P.  Copy of routine in unwind-arm.c.  */
88 
89 static inline _uw
selfrel_offset31(const _uw * p)90 selfrel_offset31 (const _uw *p)
91 {
92   _uw offset;
93 
94   offset = *p;
95   /* Sign extend to 32 bits.  */
96   if (offset & (1 << 30))
97     offset |= 1u << 31;
98 
99   return offset + (_uw) p;
100 }
101 
102 
103 /* Personality routine helper functions.  */
104 
105 #define CODE_FINISH (0xe7)
106 
107 /* Return the next byte of unwinding information, or CODE_FINISH if there is
108    no data remaining.  */
109 static inline _uw8
next_unwind_byte(__gnu_unwind_state * uws)110 next_unwind_byte (__gnu_unwind_state * uws)
111 {
112   _uw8 b;
113 
114   if (uws->bytes_left == 0)
115     {
116       /* Load another word */
117       if (uws->words_left == 0)
118 	return CODE_FINISH; /* Nothing left.  */
119       uws->words_left--;
120       uws->data = *(uws->next++);
121       uws->bytes_left = 3;
122     }
123   else
124     uws->bytes_left--;
125 
126   /* Extract the most significant byte.  */
127   b = (uws->data >> 24) & 0xff;
128   uws->data <<= 8;
129   return b;
130 }
131 
132 static void
unwind_restore_pair(_Unwind_Context * context,int reg,_uw * ptr)133 unwind_restore_pair (_Unwind_Context * context, int reg, _uw *ptr)
134 {
135 #ifdef _BIG_ENDIAN
136   _Unwind_VRS_Set (context, _UVRSC_CORE, reg, _UVRSD_UINT32, ptr + 1);
137   _Unwind_VRS_Set (context, _UVRSC_CORE, reg + 1, _UVRSD_UINT32, ptr);
138 #else
139   _Unwind_VRS_Set (context, _UVRSC_CORE, reg, _UVRSD_UINT32, ptr);
140   _Unwind_VRS_Set (context, _UVRSC_CORE, reg + 1, _UVRSD_UINT32, ptr + 1);
141 #endif
142 }
143 
144 static const int
145 unwind_frame_regs[13] =
146 {
147   R_A15, R_B15, R_B14, R_B13, R_B12, R_B11, R_B10, R_B3,
148   R_A14, R_A13, R_A12, R_A11, R_A10
149 };
150 
151 static void
pop_compact_frame(_Unwind_Context * context,_uw mask,_uw * ptr,int inc_sp)152 pop_compact_frame (_Unwind_Context * context, _uw mask, _uw *ptr, int inc_sp)
153 {
154   int size;
155   _uw test;
156   int i, regno, nregs;
157 
158   size = 0;
159   nregs = __builtin_popcount (mask);
160   for (i = 0; i < 13; i++)
161     {
162       test = 1 << i;
163       if ((mask & test) == 0)
164 	continue;
165 
166       regno = unwind_frame_regs[12 - i];
167 
168       if (i < 12 && nregs > 2
169 	  && (mask & (test << 1)) != 0
170 	  && unwind_frame_regs[11 - i] == regno + 1
171 	  && (regno & 1) == 0)
172 	{
173 	  i++;
174 	  nregs--;
175 	}
176 
177       nregs--;
178       size += 2;
179     }
180 
181   if (!inc_sp)
182     ptr -= size;
183 
184   /* SP points just past the end of the stack.  */
185   ptr += 2;
186   nregs = __builtin_popcount (mask);
187   for (i = 0; i < 13; i++)
188     {
189       test = 1 << i;
190       if ((mask & test) == 0)
191 	continue;
192 
193       regno = unwind_frame_regs[12 - i];
194 
195       if (i < 12 && nregs > 2
196 	  && (mask & (test << 1)) != 0
197 	  && unwind_frame_regs[11 - i] == regno + 1
198 	  && (regno & 1) == 0)
199 	{
200 	  /* Register pair.  */
201 	  unwind_restore_pair (context, regno, ptr);
202 	  i++;
203 	  nregs--;
204 	}
205       else
206 	{
207 	  /* Single register with padding.  */
208 	  _Unwind_VRS_Set (context, _UVRSC_CORE, regno, _UVRSD_UINT32, ptr);
209 	}
210 
211       nregs--;
212       ptr += 2;
213     }
214 
215   ptr -= 2;
216   if ((mask & (1 << 11)) == 0)
217     _Unwind_VRS_Set (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, &ptr);
218 }
219 
220 static void
pop_frame(_Unwind_Context * context,_uw mask,_uw * ptr,int inc_sp)221 pop_frame (_Unwind_Context * context, _uw mask, _uw *ptr, int inc_sp)
222 {
223   int i;
224   int regno;
225   int nregs;
226 
227   nregs = __builtin_popcount (mask);
228 
229   if (!inc_sp)
230     ptr -= nregs;
231   else if (nregs & 1)
232     ptr++;
233 
234   ptr++;
235   for (i = 0; i < 13; i++)
236     {
237       if ((mask & (1 << i)) == 0)
238 	continue;
239       regno = unwind_frame_regs[12 - i];
240       if (i < 12 && unwind_frame_regs[11 - i] == (regno + 1)
241 	  && (mask & (1 << (i + 1))) != 0
242 	  && (((_uw)ptr) & 4) == 0
243 	  && (regno & 1) == 0)
244 	{
245 	  unwind_restore_pair (context, regno, ptr);
246 	  i++;
247 	  ptr += 2;
248 	}
249       else
250 	{
251 	  _Unwind_VRS_Set (context, _UVRSC_CORE, regno, _UVRSD_UINT32,
252 			   ptr);
253 	  ptr++;
254 	}
255     }
256 
257   ptr--;
258   if ((mask & (1 << 11)) == 0)
259     _Unwind_VRS_Set (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, &ptr);
260 }
261 
262 /* Unwind a 24-bit encoded frame.  */
263 _Unwind_Reason_Code
__gnu_unwind_24bit(_Unwind_Context * context,_uw data,int compact)264 __gnu_unwind_24bit (_Unwind_Context * context, _uw data, int compact)
265 {
266   _uw offset;
267   _uw mask;
268   _uw *ptr;
269   _uw tmp;
270   int ret_reg = unwind_frame_regs[data & 0xf];
271 
272   if (ret_reg != R_B3)
273     {
274       _Unwind_VRS_Get (context, _UVRSC_CORE, unwind_frame_regs[data & 0xf],
275 		       _UVRSD_UINT32, &tmp);
276       _Unwind_VRS_Set (context, _UVRSC_CORE, R_B3, _UVRSD_UINT32, &tmp);
277     }
278 
279   mask = (data >> 4) & 0x1fff;
280 
281   offset = (data >> 17) & 0x7f;
282   if (offset == 0x7f)
283     _Unwind_VRS_Get (context, _UVRSC_CORE, R_A15, _UVRSD_UINT32, &ptr);
284   else
285     {
286       _Unwind_VRS_Get (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, &ptr);
287       ptr += offset * 2;
288     }
289 
290 
291   if (compact)
292     pop_compact_frame (context, mask, ptr, offset != 0x7f);
293   else
294     pop_frame (context, mask, ptr, offset != 0x7f);
295 
296   _Unwind_VRS_Get (context, _UVRSC_CORE, R_B3, _UVRSD_UINT32, &tmp);
297   _Unwind_VRS_Set (context, _UVRSC_CORE, R_PC, _UVRSD_UINT32, &tmp);
298 
299   return _URC_OK;
300 }
301 
302 static void
unwind_pop_rts(_Unwind_Context * context)303 unwind_pop_rts (_Unwind_Context * context)
304 {
305   _uw *ptr;
306 
307   _Unwind_VRS_Get (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, &ptr);
308 #ifdef _BIG_ENDIAN
309   _Unwind_VRS_Set (context, _UVRSC_CORE, R_B3, _UVRSD_UINT32, ptr + 1);
310 #else
311   _Unwind_VRS_Set (context, _UVRSC_CORE, R_B3, _UVRSD_UINT32, ptr + 2);
312 #endif
313   ptr += 3;
314   unwind_restore_pair (context, R_A10, ptr);
315   ptr += 2;
316   unwind_restore_pair (context, R_B10, ptr);
317   ptr += 2;
318   unwind_restore_pair (context, R_A12, ptr);
319   ptr += 2;
320   unwind_restore_pair (context, R_B12, ptr);
321   ptr += 2;
322   unwind_restore_pair (context, R_A14, ptr);
323   ptr += 2;
324   _Unwind_VRS_Set (context, _UVRSC_CORE, R_B14, _UVRSD_UINT32, ptr);
325   _Unwind_VRS_Set (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, &ptr);
326   /* PC will be set by implicit RETURN opcode.  */
327 }
328 
329 /* Execute the unwinding instructions described by UWS.  */
330 _Unwind_Reason_Code
__gnu_unwind_execute(_Unwind_Context * context,__gnu_unwind_state * uws)331 __gnu_unwind_execute (_Unwind_Context * context, __gnu_unwind_state * uws)
332 {
333   _uw op;
334   int inc_sp;
335   _uw reg;
336   _uw *ptr;
337 
338   inc_sp = 1;
339   for (;;)
340     {
341       op = next_unwind_byte (uws);
342       if (op == CODE_FINISH)
343 	{
344 	  /* Drop out of the loop.  */
345 	  break;
346 	}
347       if ((op & 0xc0) == 0)
348 	{
349 	  /* sp += (imm6 << 3) + 8.  */
350 	  _uw offset;
351 
352 	  offset = ((op & 0x3f) << 3) + 8;
353 	  _Unwind_VRS_Get (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, &reg);
354 	  reg += offset;
355 	  _Unwind_VRS_Set (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, &reg);
356 	  continue;
357 	}
358 
359       if (op == 0xd2)
360 	{
361 	  /* vsp = vsp + 0x204 + (uleb128 << 2).  */
362 	  int shift;
363 
364 	  _Unwind_VRS_Get (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, &reg);
365 	  op = next_unwind_byte (uws);
366 	  shift = 3;
367 	  while (op & 0x80)
368 	    {
369 	      reg += ((op & 0x7f) << shift);
370 	      shift += 7;
371 	      op = next_unwind_byte (uws);
372 	    }
373 	  reg += ((op & 0x7f) << shift) + 0x408;
374 	  _Unwind_VRS_Set (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, &reg);
375 	  continue;
376 	}
377 
378       if ((op & 0xe0) == 0x80)
379 	{
380 	  /* POP bitmask */
381 	  _uw mask = ((op & 0x1f) << 8) | next_unwind_byte (uws);
382 
383 	  if (mask == 0)
384 	    {
385 	      /* CANTUNWIND */
386 	      return _URC_FAILURE;
387 	    }
388 
389 	  _Unwind_VRS_Get (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, &ptr);
390 	  pop_frame (context, mask, ptr, inc_sp);
391 	  continue;
392 	}
393 
394       if ((op & 0xe0) == 0xa0)
395 	{
396 	  /* POP bitmask (compact) */
397 	  _uw mask = ((op & 0x1f) << 8) | next_unwind_byte (uws);
398 
399 	  _Unwind_VRS_Get (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, &ptr);
400 	  pop_compact_frame (context, mask, ptr, inc_sp);
401 	  continue;
402 	}
403 
404       if ((op & 0xf0) == 0xc0)
405 	{
406 	  /* POP registers */
407 	  int nregs = op & 0xf;
408 
409 	  _Unwind_VRS_Get (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, &ptr);
410 	  while (nregs > 0)
411 	    {
412 	      op = next_unwind_byte (uws);
413 	      if ((op >> 4) != 0xf)
414 		{
415 		  reg = unwind_frame_regs[op >> 4];
416 		  _Unwind_VRS_Set (context, _UVRSC_CORE, reg, _UVRSD_UINT32,
417 				   ptr);
418 		  nregs--;
419 		}
420 	      ptr--;
421 	      if ((op & 0xf) != 0xf)
422 		{
423 		  reg = unwind_frame_regs[op & 0xf];
424 		  _Unwind_VRS_Set (context, _UVRSC_CORE, reg, _UVRSD_UINT32,
425 				   ptr);
426 		  nregs--;
427 		}
428 	      ptr--;
429 	    }
430 
431 	  continue;
432 	}
433 
434       if (op == 0xd0)
435 	{
436 	  /* MV FP, SP */
437 	  inc_sp = 0;
438 	  _Unwind_VRS_Get (context, _UVRSC_CORE, R_A15, _UVRSD_UINT32, &reg);
439 	  _Unwind_VRS_Set (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, &reg);
440 	  continue;
441 	}
442 
443       if (op == 0xd1)
444 	{
445 	  /* __cx6abi_pop_rts */
446 	  unwind_pop_rts (context);
447 	  break;
448 	}
449 
450       if ((op & 0xf0) == 0xe0)
451 	{
452 	  /* B3 = reg.  RETURN case alreadh handled above.  */
453 	  int regno = unwind_frame_regs[op & 0xf];
454 
455 	  _Unwind_VRS_Get (context, _UVRSC_CORE, regno, _UVRSD_UINT32, &reg);
456 	  _Unwind_VRS_Set (context, _UVRSC_CORE, R_B3, _UVRSD_UINT32, &reg);
457 	  continue;
458 	}
459 
460       /* Reserved.  */
461       return _URC_FAILURE;
462     }
463 
464   /* Implicit RETURN.  */
465   _Unwind_VRS_Get (context, _UVRSC_CORE, R_B3, _UVRSD_UINT32, &reg);
466   _Unwind_VRS_Set (context, _UVRSC_CORE, R_PC, _UVRSD_UINT32, &reg);
467   return _URC_OK;
468 }
469 
470 
471 /* Execute the unwinding instructions associated with a frame.  UCBP and
472    CONTEXT are the current exception object and virtual CPU state
473    respectively.  */
474 
475 _Unwind_Reason_Code
__gnu_unwind_frame(_Unwind_Control_Block * ucbp,_Unwind_Context * context)476 __gnu_unwind_frame (_Unwind_Control_Block * ucbp, _Unwind_Context * context)
477 {
478   _uw *ptr;
479   __gnu_unwind_state uws;
480 
481   ptr = (_uw *) ucbp->pr_cache.ehtp;
482   /* Skip over the personality routine address.  */
483   ptr++;
484   /* Setup the unwinder state.  */
485   uws.data = (*ptr) << 8;
486   uws.next = ptr + 1;
487   uws.bytes_left = 3;
488   uws.words_left = ((*ptr) >> 24) & 0xff;
489 
490   return __gnu_unwind_execute (context, &uws);
491 }
492 
493 /* Data segment base pointer corresponding to the function catching
494    the exception.  */
495 
496 _Unwind_Ptr
_Unwind_GetDataRelBase(_Unwind_Context * context)497 _Unwind_GetDataRelBase (_Unwind_Context *context)
498 {
499   return _Unwind_GetGR (context, R_B14);
500 }
501 
502 /* This should never be used.  */
503 
504 _Unwind_Ptr
_Unwind_GetTextRelBase(_Unwind_Context * context)505 _Unwind_GetTextRelBase (_Unwind_Context *context __attribute__ ((unused)))
506 {
507   abort ();
508 }
509 
510 /* Only used by gcc personality routines, so can rely on a value they hid
511    there earlier.  */
512 _Unwind_Ptr
_Unwind_GetRegionStart(_Unwind_Context * context)513 _Unwind_GetRegionStart (_Unwind_Context *context)
514 {
515   _Unwind_Control_Block *ucbp;
516 
517   ucbp = (_Unwind_Control_Block *) _Unwind_GetGR (context, UNWIND_POINTER_REG);
518   return (_Unwind_Ptr) ucbp->pr_cache.fnstart;
519 }
520 
521 void *
_Unwind_GetLanguageSpecificData(_Unwind_Context * context)522 _Unwind_GetLanguageSpecificData (_Unwind_Context *context)
523 {
524   _Unwind_Control_Block *ucbp;
525   _uw *ptr;
526 
527   ucbp = (_Unwind_Control_Block *) _Unwind_GetGR (context, UNWIND_POINTER_REG);
528   ptr = (_uw *) ucbp->pr_cache.ehtp;
529   /* Skip the personality routine address.  */
530   ptr++;
531   /* Skip the unwind opcodes.  */
532   ptr += (((*ptr) >> 24) & 0xff) + 1;
533 
534   return ptr;
535 }
536