Skip gnat.dg/prot7.adb on hppa.
[official-gcc.git] / libgo / runtime / go-unwind.c
blob16e05252ec997ae15e6871c246282f86c2753247
1 /* go-unwind.c -- unwind the stack for panic/recover.
3 Copyright 2010 The Go Authors. All rights reserved.
4 Use of this source code is governed by a BSD-style
5 license that can be found in the LICENSE file. */
7 #include "config.h"
9 #include <stdlib.h>
10 #include <unistd.h>
12 #include "unwind.h"
14 #include "runtime.h"
16 /* These constants are documented here:
17 https://refspecs.linuxfoundation.org/LSB_3.0.0/LSB-PDA/LSB-PDA/dwarfext.html
20 #define DW_EH_PE_omit 0xff
21 #define DW_EH_PE_absptr 0x00
22 #define DW_EH_PE_uleb128 0x01
23 #define DW_EH_PE_udata2 0x02
24 #define DW_EH_PE_udata4 0x03
25 #define DW_EH_PE_udata8 0x04
26 #define DW_EH_PE_sleb128 0x09
27 #define DW_EH_PE_sdata2 0x0A
28 #define DW_EH_PE_sdata4 0x0B
29 #define DW_EH_PE_sdata8 0x0C
30 #define DW_EH_PE_pcrel 0x10
31 #define DW_EH_PE_textrel 0x20
32 #define DW_EH_PE_datarel 0x30
33 #define DW_EH_PE_funcrel 0x40
34 #define DW_EH_PE_aligned 0x50
35 #define DW_EH_PE_indirect 0x80
37 /* The code for a Go exception. */
39 #ifdef __ARM_EABI_UNWINDER__
40 static const _Unwind_Exception_Class __go_exception_class =
41 { 'G', 'N', 'U', 'C', 'G', 'O', '\0', '\0' };
42 #else
43 static const _Unwind_Exception_Class __go_exception_class =
44 ((((((((_Unwind_Exception_Class) 'G'
45 << 8 | (_Unwind_Exception_Class) 'N')
46 << 8 | (_Unwind_Exception_Class) 'U')
47 << 8 | (_Unwind_Exception_Class) 'C')
48 << 8 | (_Unwind_Exception_Class) 'G')
49 << 8 | (_Unwind_Exception_Class) 'O')
50 << 8 | (_Unwind_Exception_Class) '\0')
51 << 8 | (_Unwind_Exception_Class) '\0');
52 #endif
54 /* Rethrow an exception. */
56 void rethrowException (void) __asm__(GOSYM_PREFIX "runtime.rethrowException");
58 void
59 rethrowException ()
61 struct _Unwind_Exception *hdr;
62 _Unwind_Reason_Code reason;
64 hdr = (struct _Unwind_Exception *) runtime_g()->exception;
66 #ifdef __USING_SJLJ_EXCEPTIONS__
67 reason = _Unwind_SjLj_Resume_or_Rethrow (hdr);
68 #else
69 #if defined(_LIBUNWIND_STD_ABI)
70 reason = _Unwind_RaiseException (hdr);
71 #else
72 reason = _Unwind_Resume_or_Rethrow (hdr);
73 #endif
74 #endif
76 /* Rethrowing the exception should not return. */
77 runtime_printf ("failed to rethrow unwind exception (reason=%d)\n", reason);
78 abort();
81 /* Return the size of the type that holds an exception header, so that
82 it can be allocated by Go code. */
84 uintptr unwindExceptionSize(void)
85 __asm__ (GOSYM_PREFIX "runtime.unwindExceptionSize");
87 uintptr
88 unwindExceptionSize ()
90 uintptr ret, align;
92 ret = sizeof (struct _Unwind_Exception);
93 /* Adjust the size fo make sure that we can get an aligned value. */
94 align = __alignof__ (struct _Unwind_Exception);
95 if (align > __alignof__ (uintptr))
96 ret += align - __alignof__ (uintptr);
97 return ret;
100 /* Throw an exception. This is called with g->exception pointing to
101 an uninitialized _Unwind_Exception instance. */
103 void throwException (void) __asm__(GOSYM_PREFIX "runtime.throwException");
105 void
106 throwException ()
108 struct _Unwind_Exception *hdr;
109 uintptr align;
110 _Unwind_Reason_Code reason;
112 hdr = (struct _Unwind_Exception *)runtime_g ()->exception;
114 /* Make sure the value is correctly aligned. It will be large
115 enough, because of unwindExceptionSize. */
116 align = __alignof__ (struct _Unwind_Exception);
117 hdr = ((struct _Unwind_Exception *)
118 (((uintptr) hdr + align - 1) &~ (align - 1)));
120 __builtin_memcpy (&hdr->exception_class, &__go_exception_class,
121 sizeof hdr->exception_class);
122 hdr->exception_cleanup = NULL;
124 #ifdef __USING_SJLJ_EXCEPTIONS__
125 reason = _Unwind_SjLj_RaiseException (hdr);
126 #else
127 reason = _Unwind_RaiseException (hdr);
128 #endif
130 /* Raising an exception should not return. */
131 runtime_printf ("failed to throw unwind exception (reason=%d)\n", reason);
132 abort ();
135 static inline _Unwind_Ptr
136 encoded_value_base (uint8_t encoding, struct _Unwind_Context *context)
138 if (encoding == DW_EH_PE_omit)
139 return 0;
140 switch (encoding & 0x70)
142 case DW_EH_PE_absptr:
143 case DW_EH_PE_pcrel:
144 case DW_EH_PE_aligned:
145 return 0;
146 case DW_EH_PE_textrel:
147 return _Unwind_GetTextRelBase(context);
148 case DW_EH_PE_datarel:
149 return _Unwind_GetDataRelBase(context);
150 case DW_EH_PE_funcrel:
151 return _Unwind_GetRegionStart(context);
153 abort ();
156 /* Read an unsigned leb128 value. */
158 static inline const uint8_t *
159 read_uleb128 (const uint8_t *p, _uleb128_t *val)
161 unsigned int shift = 0;
162 _uleb128_t result = 0;
163 uint8_t byte;
167 byte = *p++;
168 result |= ((_uleb128_t)byte & 0x7f) << shift;
169 shift += 7;
171 while (byte & 0x80);
173 *val = result;
174 return p;
177 /* Similar, but read a signed leb128 value. */
179 static inline const uint8_t *
180 read_sleb128 (const uint8_t *p, _sleb128_t *val)
182 unsigned int shift = 0;
183 _uleb128_t result = 0;
184 uint8_t byte;
188 byte = *p++;
189 result |= ((_uleb128_t)byte & 0x7f) << shift;
190 shift += 7;
192 while (byte & 0x80);
194 /* sign extension */
195 if (shift < (8 * sizeof(result)) && (byte & 0x40) != 0)
196 result |= (((_uleb128_t)~0) << shift);
198 *val = (_sleb128_t)result;
199 return p;
202 #define ROUND_UP_TO_PVB(x) (x + sizeof(void *) - 1) &- sizeof(void *)
204 static inline const uint8_t *
205 read_encoded_value (struct _Unwind_Context *context, uint8_t encoding,
206 const uint8_t *p, _Unwind_Ptr *val)
208 _Unwind_Ptr base = encoded_value_base (encoding, context);
209 _Unwind_Internal_Ptr decoded = 0;
210 const uint8_t *origp = p;
212 if (encoding == DW_EH_PE_aligned)
214 _Unwind_Internal_Ptr uip = (_Unwind_Internal_Ptr)p;
215 uip = ROUND_UP_TO_PVB (uip);
216 decoded = *(_Unwind_Internal_Ptr *)uip;
217 p = (const uint8_t *)(uip + sizeof(void *));
219 else
221 switch (encoding & 0x0f)
223 case DW_EH_PE_sdata2:
225 int16_t result;
226 __builtin_memcpy (&result, p, sizeof(int16_t));
227 decoded = result;
228 p += sizeof(int16_t);
229 break;
231 case DW_EH_PE_udata2:
233 uint16_t result;
234 __builtin_memcpy (&result, p, sizeof(uint16_t));
235 decoded = result;
236 p += sizeof(uint16_t);
237 break;
239 case DW_EH_PE_sdata4:
241 int32_t result;
242 __builtin_memcpy (&result, p, sizeof(int32_t));
243 decoded = result;
244 p += sizeof(int32_t);
245 break;
247 case DW_EH_PE_udata4:
249 uint32_t result;
250 __builtin_memcpy (&result, p, sizeof(uint32_t));
251 decoded = result;
252 p += sizeof(uint32_t);
253 break;
255 case DW_EH_PE_sdata8:
257 int64_t result;
258 __builtin_memcpy (&result, p, sizeof(int64_t));
259 decoded = result;
260 p += sizeof(int64_t);
261 break;
263 case DW_EH_PE_udata8:
265 uint64_t result;
266 __builtin_memcpy (&result, p, sizeof(uint64_t));
267 decoded = result;
268 p += sizeof(uint64_t);
269 break;
271 case DW_EH_PE_uleb128:
273 _uleb128_t value;
274 p = read_uleb128 (p, &value);
275 decoded = (_Unwind_Internal_Ptr)value;
276 break;
278 case DW_EH_PE_sleb128:
280 _sleb128_t value;
281 p = read_sleb128 (p, &value);
282 decoded = (_Unwind_Internal_Ptr)value;
283 break;
285 case DW_EH_PE_absptr:
286 __builtin_memcpy (&decoded, (const void *)p, sizeof(const void*));
287 p += sizeof(void *);
288 break;
289 default:
290 abort ();
293 if (decoded == 0)
295 *val = decoded;
296 return p;
299 if ((encoding & 0x70) == DW_EH_PE_pcrel)
300 decoded += ((_Unwind_Internal_Ptr)origp);
301 else
302 decoded += base;
304 if ((encoding & DW_EH_PE_indirect) != 0)
305 decoded = *(_Unwind_Internal_Ptr *)decoded;
307 *val = decoded;
308 return p;
311 static inline int
312 value_size (uint8_t encoding)
314 switch (encoding & 0x0f)
316 case DW_EH_PE_sdata2:
317 case DW_EH_PE_udata2:
318 return 2;
319 case DW_EH_PE_sdata4:
320 case DW_EH_PE_udata4:
321 return 4;
322 case DW_EH_PE_sdata8:
323 case DW_EH_PE_udata8:
324 return 8;
325 case DW_EH_PE_absptr:
326 return sizeof(uintptr);
327 default:
328 break;
330 abort ();
333 /* The rest of this code is really similar to gcc/unwind-c.c and
334 libjava/exception.cc. */
336 typedef struct
338 _Unwind_Ptr Start;
339 _Unwind_Ptr LPStart;
340 _Unwind_Ptr ttype_base;
341 const unsigned char *TType;
342 const unsigned char *action_table;
343 unsigned char ttype_encoding;
344 unsigned char call_site_encoding;
345 } lsda_header_info;
347 static const unsigned char *
348 parse_lsda_header (struct _Unwind_Context *context, const unsigned char *p,
349 lsda_header_info *info)
351 _uleb128_t tmp;
352 unsigned char lpstart_encoding;
354 info->Start = (context ? _Unwind_GetRegionStart (context) : 0);
356 /* Find @LPStart, the base to which landing pad offsets are relative. */
357 lpstart_encoding = *p++;
358 if (lpstart_encoding != DW_EH_PE_omit)
359 p = read_encoded_value (context, lpstart_encoding, p, &info->LPStart);
360 else
361 info->LPStart = info->Start;
363 /* Find @TType, the base of the handler and exception spec type data. */
364 info->ttype_encoding = *p++;
365 if (info->ttype_encoding != DW_EH_PE_omit)
367 p = read_uleb128 (p, &tmp);
368 info->TType = p + tmp;
370 else
371 info->TType = 0;
373 /* The encoding and length of the call-site table; the action table
374 immediately follows. */
375 info->call_site_encoding = *p++;
376 p = read_uleb128 (p, &tmp);
377 info->action_table = p + tmp;
379 return p;
382 /* The personality function is invoked when unwinding the stack due to
383 a panic. Its job is to find the cleanup and exception handlers to
384 run. We can't split the stack here, because we won't be able to
385 unwind from that split. */
387 #ifdef __ARM_EABI_UNWINDER__
388 /* ARM EABI personality routines must also unwind the stack. */
389 #define CONTINUE_UNWINDING \
390 do \
392 if (__gnu_unwind_frame (ue_header, context) != _URC_OK) \
393 return _URC_FAILURE; \
394 return _URC_CONTINUE_UNWIND; \
396 while (0)
397 #else
398 #define CONTINUE_UNWINDING return _URC_CONTINUE_UNWIND
399 #endif
401 #ifdef __ARM_EABI_UNWINDER__
402 #define STOP_UNWINDING _URC_FAILURE
403 #else
404 #define STOP_UNWINDING _URC_NORMAL_STOP
405 #endif
407 #ifdef __USING_SJLJ_EXCEPTIONS__
408 #define PERSONALITY_FUNCTION __gccgo_personality_sj0
409 #define __builtin_eh_return_data_regno(x) x
410 #else
411 #define PERSONALITY_FUNCTION __gccgo_personality_v0
412 #endif
414 #ifdef __ARM_EABI_UNWINDER__
415 _Unwind_Reason_Code
416 PERSONALITY_FUNCTION (_Unwind_State, struct _Unwind_Exception *,
417 struct _Unwind_Context *)
418 __attribute__ ((no_split_stack, flatten, target ("general-regs-only")));
420 _Unwind_Reason_Code
421 PERSONALITY_FUNCTION (_Unwind_State state,
422 struct _Unwind_Exception * ue_header,
423 struct _Unwind_Context * context)
424 #else
425 _Unwind_Reason_Code
426 PERSONALITY_FUNCTION (int, _Unwind_Action, _Unwind_Exception_Class,
427 struct _Unwind_Exception *, struct _Unwind_Context *)
428 __attribute__ ((no_split_stack, flatten));
430 _Unwind_Reason_Code
431 PERSONALITY_FUNCTION (int version,
432 _Unwind_Action actions,
433 _Unwind_Exception_Class exception_class,
434 struct _Unwind_Exception *ue_header,
435 struct _Unwind_Context *context)
436 #endif
438 lsda_header_info info;
439 const unsigned char *language_specific_data, *p, *action_record;
440 _Unwind_Ptr landing_pad, ip;
441 int ip_before_insn = 0;
442 _Bool is_foreign;
443 G *g;
445 #ifdef __ARM_EABI_UNWINDER__
446 _Unwind_Action actions;
448 switch (state & _US_ACTION_MASK)
450 case _US_VIRTUAL_UNWIND_FRAME:
451 if (state & _UA_FORCE_UNWIND)
452 /* We are called from _Unwind_Backtrace. No handler to run. */
453 CONTINUE_UNWINDING;
454 actions = _UA_SEARCH_PHASE;
455 break;
457 case _US_UNWIND_FRAME_STARTING:
458 actions = _UA_CLEANUP_PHASE;
459 if (!(state & _US_FORCE_UNWIND)
460 && ue_header->barrier_cache.sp == _Unwind_GetGR(context, 13))
461 actions |= _UA_HANDLER_FRAME;
462 break;
464 case _US_UNWIND_FRAME_RESUME:
465 CONTINUE_UNWINDING;
466 break;
468 default:
469 abort();
471 actions |= state & _US_FORCE_UNWIND;
473 is_foreign = 0;
475 /* The dwarf unwinder assumes the context structure holds things like the
476 function and LSDA pointers. The ARM implementation caches these in
477 the exception header (UCB). To avoid rewriting everything we make the
478 virtual IP register point at the UCB. */
479 ip = (_Unwind_Ptr) ue_header;
480 _Unwind_SetGR (context, 12, ip);
481 #else
482 if (version != 1)
483 return _URC_FATAL_PHASE1_ERROR;
485 is_foreign = exception_class != __go_exception_class;
486 #endif
488 language_specific_data = (const unsigned char *)
489 _Unwind_GetLanguageSpecificData (context);
491 /* If no LSDA, then there are no handlers or cleanups. */
492 if (! language_specific_data)
493 CONTINUE_UNWINDING;
495 /* Parse the LSDA header. */
496 p = parse_lsda_header (context, language_specific_data, &info);
497 #ifdef HAVE_GETIPINFO
498 ip = _Unwind_GetIPInfo (context, &ip_before_insn);
499 #else
500 ip = _Unwind_GetIP (context);
501 #endif
502 if (! ip_before_insn)
503 --ip;
504 landing_pad = 0;
505 action_record = NULL;
507 #ifdef __USING_SJLJ_EXCEPTIONS__
508 /* The given "IP" is an index into the call-site table, with two
509 exceptions -- -1 means no-action, and 0 means terminate. But
510 since we're using uleb128 values, we've not got random access
511 to the array. */
512 if ((int) ip <= 0)
513 return _URC_CONTINUE_UNWIND;
514 else
516 _uleb128_t cs_lp, cs_action;
519 p = read_uleb128 (p, &cs_lp);
520 p = read_uleb128 (p, &cs_action);
522 while (--ip);
524 /* Can never have null landing pad for sjlj -- that would have
525 been indicated by a -1 call site index. */
526 landing_pad = (_Unwind_Ptr)cs_lp + 1;
527 if (cs_action)
528 action_record = info.action_table + cs_action - 1;
529 goto found_something;
531 #else
532 /* Search the call-site table for the action associated with this IP. */
533 while (p < info.action_table)
535 _Unwind_Ptr cs_start, cs_len, cs_lp;
536 _uleb128_t cs_action;
538 /* Note that all call-site encodings are "absolute" displacements. */
539 p = read_encoded_value (0, info.call_site_encoding, p, &cs_start);
540 p = read_encoded_value (0, info.call_site_encoding, p, &cs_len);
541 p = read_encoded_value (0, info.call_site_encoding, p, &cs_lp);
542 p = read_uleb128 (p, &cs_action);
544 /* The table is sorted, so if we've passed the ip, stop. */
545 if (ip < info.Start + cs_start)
546 p = info.action_table;
547 else if (ip < info.Start + cs_start + cs_len)
549 if (cs_lp)
550 landing_pad = info.LPStart + cs_lp;
551 if (cs_action)
552 action_record = info.action_table + cs_action - 1;
553 goto found_something;
556 #endif
558 /* IP is not in table. No associated cleanups. */
559 CONTINUE_UNWINDING;
561 found_something:
562 if (landing_pad == 0)
564 /* IP is present, but has a null landing pad.
565 No handler to be run. */
566 CONTINUE_UNWINDING;
569 if (actions & _UA_SEARCH_PHASE)
571 if (action_record == 0)
573 /* This indicates a cleanup rather than an exception
574 handler. */
575 CONTINUE_UNWINDING;
578 return _URC_HANDLER_FOUND;
581 /* It's possible for g to be NULL here for an exception thrown by a
582 language other than Go. */
583 g = runtime_g ();
584 if (g == NULL)
586 if (!is_foreign)
587 abort ();
589 else
591 g->exception = ue_header;
592 g->isforeign = is_foreign;
595 _Unwind_SetGR (context, __builtin_eh_return_data_regno (0),
596 (_Unwind_Ptr) ue_header);
597 _Unwind_SetGR (context, __builtin_eh_return_data_regno (1), 0);
598 _Unwind_SetIP (context, landing_pad);
599 return _URC_INSTALL_CONTEXT;
602 // A dummy personality function, which doesn't capture any exception
603 // and simply passes by. This is used for functions that don't
604 // capture exceptions but need LSDA for stack maps.
605 _Unwind_Reason_Code
606 __gccgo_personality_dummy (int, _Unwind_Action, _Unwind_Exception_Class,
607 struct _Unwind_Exception *, struct _Unwind_Context *)
608 __attribute__ ((no_split_stack));
610 _Unwind_Reason_Code
611 #ifdef __ARM_EABI_UNWINDER__
612 __attribute__ ((target ("general-regs-only")))
613 #endif
614 __gccgo_personality_dummy (int version __attribute__ ((unused)),
615 _Unwind_Action actions __attribute__ ((unused)),
616 _Unwind_Exception_Class exception_class __attribute__ ((unused)),
617 struct _Unwind_Exception *ue_header __attribute__ ((unused)),
618 struct _Unwind_Context *context __attribute__ ((unused)))
620 CONTINUE_UNWINDING;
623 // A sentinel value for Go functions.
624 // A function is a Go function if it has LSDA, which has type info,
625 // and the first (dummy) landing pad's type info is a pointer to
626 // this value.
627 #define GO_FUNC_SENTINEL ((uint64)'G' | ((uint64)'O'<<8) | \
628 ((uint64)'.'<<16) | ((uint64)'.'<<24) | \
629 ((uint64)'F'<<32) | ((uint64)'U'<<40) | \
630 ((uint64)'N'<<48) | ((uint64)'C'<<56))
632 struct _stackmap {
633 uint32 len;
634 uint8 data[1]; // variabe length
637 extern void
638 runtime_scanstackblockwithmap (uintptr ip, uintptr sp, uintptr size, uint8 *ptrmask, void* gcw)
639 __asm__ (GOSYM_PREFIX "runtime.scanstackblockwithmap");
641 #define FOUND 0
642 #define NOTFOUND_OK 1
643 #define NOTFOUND_BAD 2
645 // Helper function to search for stack maps in the unwinding records of a frame.
646 // If found, populate ip, sp, and stackmap. Returns the #define'd values above.
647 static int
648 findstackmaps (struct _Unwind_Context *context, _Unwind_Ptr *ip, _Unwind_Ptr *sp, struct _stackmap **stackmap)
650 lsda_header_info info;
651 const unsigned char *language_specific_data, *p, *action_record;
652 bool first;
653 struct _stackmap *stackmap1;
654 _Unwind_Ptr ip1;
655 int ip_before_insn = 0;
656 _sleb128_t index;
657 int size;
659 #ifdef HAVE_GETIPINFO
660 ip1 = _Unwind_GetIPInfo (context, &ip_before_insn);
661 #else
662 ip1 = _Unwind_GetIP (context);
663 #endif
664 if (! ip_before_insn)
665 --ip1;
667 if (ip != NULL)
668 *ip = ip1;
669 if (sp != NULL)
670 *sp = _Unwind_GetCFA (context);
672 #ifdef __ARM_EABI_UNWINDER__
674 _Unwind_Control_Block *ucbp;
675 ucbp = (_Unwind_Control_Block *) _Unwind_GetGR (context, 12);
676 if (*ucbp->pr_cache.ehtp & (1u << 31))
677 // The "compact" model is used, with one of the predefined
678 // personality functions. It doesn't have standard LSDA.
679 return NOTFOUND_OK;
681 #endif
683 language_specific_data = (const unsigned char *)
684 _Unwind_GetLanguageSpecificData (context);
686 /* If no LSDA, then there is no stack maps. */
687 if (! language_specific_data)
688 return NOTFOUND_OK;
690 p = parse_lsda_header (context, language_specific_data, &info);
692 if (info.TType == NULL)
693 return NOTFOUND_OK;
695 size = value_size (info.ttype_encoding);
697 action_record = NULL;
698 first = true;
700 /* Search the call-site table for the action associated with this IP. */
701 while (p < info.action_table)
703 _Unwind_Ptr cs_start, cs_len, cs_lp;
704 _uleb128_t cs_action;
706 /* Note that all call-site encodings are "absolute" displacements. */
707 p = read_encoded_value (0, info.call_site_encoding, p, &cs_start);
708 p = read_encoded_value (0, info.call_site_encoding, p, &cs_len);
709 p = read_encoded_value (0, info.call_site_encoding, p, &cs_lp);
710 p = read_uleb128 (p, &cs_action);
712 if (first)
714 // For a Go function, the first entry points to the sentinel value.
715 // Check this here.
716 const unsigned char *p1, *action1;
717 uint64 *x;
719 if (!cs_action)
720 return NOTFOUND_OK;
722 action1 = info.action_table + cs_action - 1;
723 read_sleb128 (action1, &index);
724 p1 = info.TType - index*size;
725 read_encoded_value (context, info.ttype_encoding, p1, (_Unwind_Ptr*)&x);
726 if (x == NULL || *x != GO_FUNC_SENTINEL)
727 return NOTFOUND_OK;
729 first = false;
730 continue;
733 /* The table is sorted, so if we've passed the ip, stop. */
734 if (ip1 < info.Start + cs_start)
735 return NOTFOUND_BAD;
736 else if (ip1 < info.Start + cs_start + cs_len)
738 if (cs_action)
739 action_record = info.action_table + cs_action - 1;
740 break;
744 if (action_record == NULL)
745 return NOTFOUND_BAD;
747 read_sleb128 (action_record, &index);
748 p = info.TType - index*size;
749 read_encoded_value (context, info.ttype_encoding, p, (_Unwind_Ptr*)&stackmap1);
750 if (stackmap1 == NULL)
751 return NOTFOUND_BAD;
753 if (stackmap != NULL)
754 *stackmap = stackmap1;
755 return FOUND;
758 struct scanstate {
759 void* gcw; // the GC worker, passed into scanstackwithmap_callback
760 uintptr lastsp; // the last (outermost) SP of Go function seen in a traceback, set by the callback
763 // Callback function to scan a stack frame with stack maps.
764 // It skips non-Go functions.
765 static _Unwind_Reason_Code
766 scanstackwithmap_callback (struct _Unwind_Context *context, void *arg)
768 struct _stackmap *stackmap;
769 _Unwind_Ptr ip, sp;
770 G* gp;
771 struct scanstate* state = (struct scanstate*) arg;
772 void *gcw;
774 gp = runtime_g ();
775 gcw = state->gcw;
777 switch (findstackmaps (context, &ip, &sp, &stackmap))
779 case NOTFOUND_OK:
780 // Not a Go function. Skip this frame.
781 return _URC_NO_REASON;
782 case NOTFOUND_BAD:
784 // No stack map found.
785 // If we're scanning from the signal stack, the goroutine
786 // may be not stopped at a safepoint. Allow this case.
787 if (gp != gp->m->gsignal)
789 // TODO: print gp, pc, sp
790 runtime_throw ("no stack map");
792 return STOP_UNWINDING;
794 case FOUND:
795 break;
796 default:
797 abort ();
800 state->lastsp = sp;
801 runtime_scanstackblockwithmap (ip, sp, (uintptr)(stackmap->len) * sizeof(uintptr), stackmap->data, gcw);
803 return _URC_NO_REASON;
806 // Scan the stack with stack maps. Return whether the scan
807 // succeeded.
808 bool
809 scanstackwithmap (void *gcw)
811 _Unwind_Reason_Code code;
812 bool ret;
813 struct scanstate state;
814 G* gp;
815 G* curg;
817 state.gcw = gcw;
818 state.lastsp = 0;
819 gp = runtime_g ();
820 curg = gp->m->curg;
822 runtime_xadd (&__go_runtime_in_callers, 1);
823 code = _Unwind_Backtrace (scanstackwithmap_callback, (void*)&state);
824 runtime_xadd (&__go_runtime_in_callers, -1);
825 ret = (code == _URC_END_OF_STACK);
826 if (ret && gp == gp->m->gsignal)
828 // For signal-triggered scan, the unwinder may not be able to unwind
829 // the whole stack while it still reports _URC_END_OF_STACK (e.g.
830 // signal is delivered in vdso). Check that we actually reached the
831 // the end of the stack, that is, the SP on entry.
832 if (state.lastsp != curg->entrysp)
833 ret = false;
835 return ret;
838 // Returns whether stack map is enabled.
839 bool
840 usestackmaps ()
842 return runtime_usestackmaps;
845 // Callback function to probe if a stack frame has stack maps.
846 static _Unwind_Reason_Code
847 probestackmaps_callback (struct _Unwind_Context *context,
848 void *arg __attribute__ ((unused)))
850 switch (findstackmaps (context, NULL, NULL, NULL))
852 case NOTFOUND_OK:
853 case NOTFOUND_BAD:
854 return _URC_NO_REASON;
855 case FOUND:
856 break;
857 default:
858 abort ();
861 // Found a stack map. No need to keep unwinding.
862 runtime_usestackmaps = true;
863 return STOP_UNWINDING;
866 // Try to find a stack map, store the result in global variable runtime_usestackmaps.
867 // Called in start-up time from Go code, so there is a Go frame on the stack.
868 bool
869 probestackmaps ()
871 runtime_usestackmaps = false;
872 _Unwind_Backtrace (probestackmaps_callback, NULL);
873 return runtime_usestackmaps;