Simplify loop size when step=1
[official-gcc.git] / libgo / runtime / go-unwind.c
blobad3142cb05d86c4b237da118b7cdc3863076dc64
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;
63 hdr = (struct _Unwind_Exception *) runtime_g()->exception;
65 #ifdef __USING_SJLJ_EXCEPTIONS__
66 _Unwind_SjLj_Resume_or_Rethrow (hdr);
67 #else
68 #if defined(_LIBUNWIND_STD_ABI)
69 _Unwind_RaiseException (hdr);
70 #else
71 _Unwind_Resume_or_Rethrow (hdr);
72 #endif
73 #endif
75 /* Rethrowing the exception should not return. */
76 abort();
79 /* Return the size of the type that holds an exception header, so that
80 it can be allocated by Go code. */
82 uintptr unwindExceptionSize(void)
83 __asm__ (GOSYM_PREFIX "runtime.unwindExceptionSize");
85 uintptr
86 unwindExceptionSize ()
88 uintptr ret, align;
90 ret = sizeof (struct _Unwind_Exception);
91 /* Adjust the size fo make sure that we can get an aligned value. */
92 align = __alignof__ (struct _Unwind_Exception);
93 if (align > __alignof__ (uintptr))
94 ret += align - __alignof__ (uintptr);
95 return ret;
98 /* Throw an exception. This is called with g->exception pointing to
99 an uninitialized _Unwind_Exception instance. */
101 void throwException (void) __asm__(GOSYM_PREFIX "runtime.throwException");
103 void
104 throwException ()
106 struct _Unwind_Exception *hdr;
107 uintptr align;
109 hdr = (struct _Unwind_Exception *)runtime_g ()->exception;
111 /* Make sure the value is correctly aligned. It will be large
112 enough, because of unwindExceptionSize. */
113 align = __alignof__ (struct _Unwind_Exception);
114 hdr = ((struct _Unwind_Exception *)
115 (((uintptr) hdr + align - 1) &~ (align - 1)));
117 __builtin_memcpy (&hdr->exception_class, &__go_exception_class,
118 sizeof hdr->exception_class);
119 hdr->exception_cleanup = NULL;
121 #ifdef __USING_SJLJ_EXCEPTIONS__
122 _Unwind_SjLj_RaiseException (hdr);
123 #else
124 _Unwind_RaiseException (hdr);
125 #endif
127 /* Raising an exception should not return. */
128 abort ();
131 static inline _Unwind_Ptr
132 encoded_value_base (uint8_t encoding, struct _Unwind_Context *context)
134 if (encoding == DW_EH_PE_omit)
135 return 0;
136 switch (encoding & 0x70)
138 case DW_EH_PE_absptr:
139 case DW_EH_PE_pcrel:
140 case DW_EH_PE_aligned:
141 return 0;
142 case DW_EH_PE_textrel:
143 return _Unwind_GetTextRelBase(context);
144 case DW_EH_PE_datarel:
145 return _Unwind_GetDataRelBase(context);
146 case DW_EH_PE_funcrel:
147 return _Unwind_GetRegionStart(context);
149 abort ();
152 /* Read an unsigned leb128 value. */
154 static inline const uint8_t *
155 read_uleb128 (const uint8_t *p, _uleb128_t *val)
157 unsigned int shift = 0;
158 _uleb128_t result = 0;
159 uint8_t byte;
163 byte = *p++;
164 result |= ((_uleb128_t)byte & 0x7f) << shift;
165 shift += 7;
167 while (byte & 0x80);
169 *val = result;
170 return p;
173 /* Similar, but read a signed leb128 value. */
175 static inline const uint8_t *
176 read_sleb128 (const uint8_t *p, _sleb128_t *val)
178 unsigned int shift = 0;
179 _uleb128_t result = 0;
180 uint8_t byte;
184 byte = *p++;
185 result |= ((_uleb128_t)byte & 0x7f) << shift;
186 shift += 7;
188 while (byte & 0x80);
190 /* sign extension */
191 if (shift < (8 * sizeof(result)) && (byte & 0x40) != 0)
192 result |= (((_uleb128_t)~0) << shift);
194 *val = (_sleb128_t)result;
195 return p;
198 #define ROUND_UP_TO_PVB(x) (x + sizeof(void *) - 1) &- sizeof(void *)
200 static inline const uint8_t *
201 read_encoded_value (struct _Unwind_Context *context, uint8_t encoding,
202 const uint8_t *p, _Unwind_Ptr *val)
204 _Unwind_Ptr base = encoded_value_base (encoding, context);
205 _Unwind_Internal_Ptr decoded = 0;
206 const uint8_t *origp = p;
208 if (encoding == DW_EH_PE_aligned)
210 _Unwind_Internal_Ptr uip = (_Unwind_Internal_Ptr)p;
211 uip = ROUND_UP_TO_PVB (uip);
212 decoded = *(_Unwind_Internal_Ptr *)uip;
213 p = (const uint8_t *)(uip + sizeof(void *));
215 else
217 switch (encoding & 0x0f)
219 case DW_EH_PE_sdata2:
221 int16_t result;
222 __builtin_memcpy (&result, p, sizeof(int16_t));
223 decoded = result;
224 p += sizeof(int16_t);
225 break;
227 case DW_EH_PE_udata2:
229 uint16_t result;
230 __builtin_memcpy (&result, p, sizeof(uint16_t));
231 decoded = result;
232 p += sizeof(uint16_t);
233 break;
235 case DW_EH_PE_sdata4:
237 int32_t result;
238 __builtin_memcpy (&result, p, sizeof(int32_t));
239 decoded = result;
240 p += sizeof(int32_t);
241 break;
243 case DW_EH_PE_udata4:
245 uint32_t result;
246 __builtin_memcpy (&result, p, sizeof(uint32_t));
247 decoded = result;
248 p += sizeof(uint32_t);
249 break;
251 case DW_EH_PE_sdata8:
253 int64_t result;
254 __builtin_memcpy (&result, p, sizeof(int64_t));
255 decoded = result;
256 p += sizeof(int64_t);
257 break;
259 case DW_EH_PE_udata8:
261 uint64_t result;
262 __builtin_memcpy (&result, p, sizeof(uint64_t));
263 decoded = result;
264 p += sizeof(uint64_t);
265 break;
267 case DW_EH_PE_uleb128:
269 _uleb128_t value;
270 p = read_uleb128 (p, &value);
271 decoded = (_Unwind_Internal_Ptr)value;
272 break;
274 case DW_EH_PE_sleb128:
276 _sleb128_t value;
277 p = read_sleb128 (p, &value);
278 decoded = (_Unwind_Internal_Ptr)value;
279 break;
281 case DW_EH_PE_absptr:
282 __builtin_memcpy (&decoded, (const void *)p, sizeof(const void*));
283 p += sizeof(void *);
284 break;
285 default:
286 abort ();
289 if (decoded == 0)
291 *val = decoded;
292 return p;
295 if ((encoding & 0x70) == DW_EH_PE_pcrel)
296 decoded += ((_Unwind_Internal_Ptr)origp);
297 else
298 decoded += base;
300 if ((encoding & DW_EH_PE_indirect) != 0)
301 decoded = *(_Unwind_Internal_Ptr *)decoded;
303 *val = decoded;
304 return p;
307 static inline int
308 value_size (uint8_t encoding)
310 switch (encoding & 0x0f)
312 case DW_EH_PE_sdata2:
313 case DW_EH_PE_udata2:
314 return 2;
315 case DW_EH_PE_sdata4:
316 case DW_EH_PE_udata4:
317 return 4;
318 case DW_EH_PE_sdata8:
319 case DW_EH_PE_udata8:
320 return 8;
321 case DW_EH_PE_absptr:
322 return sizeof(uintptr);
323 default:
324 break;
326 abort ();
329 /* The rest of this code is really similar to gcc/unwind-c.c and
330 libjava/exception.cc. */
332 typedef struct
334 _Unwind_Ptr Start;
335 _Unwind_Ptr LPStart;
336 _Unwind_Ptr ttype_base;
337 const unsigned char *TType;
338 const unsigned char *action_table;
339 unsigned char ttype_encoding;
340 unsigned char call_site_encoding;
341 } lsda_header_info;
343 static const unsigned char *
344 parse_lsda_header (struct _Unwind_Context *context, const unsigned char *p,
345 lsda_header_info *info)
347 _uleb128_t tmp;
348 unsigned char lpstart_encoding;
350 info->Start = (context ? _Unwind_GetRegionStart (context) : 0);
352 /* Find @LPStart, the base to which landing pad offsets are relative. */
353 lpstart_encoding = *p++;
354 if (lpstart_encoding != DW_EH_PE_omit)
355 p = read_encoded_value (context, lpstart_encoding, p, &info->LPStart);
356 else
357 info->LPStart = info->Start;
359 /* Find @TType, the base of the handler and exception spec type data. */
360 info->ttype_encoding = *p++;
361 if (info->ttype_encoding != DW_EH_PE_omit)
363 p = read_uleb128 (p, &tmp);
364 info->TType = p + tmp;
366 else
367 info->TType = 0;
369 /* The encoding and length of the call-site table; the action table
370 immediately follows. */
371 info->call_site_encoding = *p++;
372 p = read_uleb128 (p, &tmp);
373 info->action_table = p + tmp;
375 return p;
378 /* The personality function is invoked when unwinding the stack due to
379 a panic. Its job is to find the cleanup and exception handlers to
380 run. We can't split the stack here, because we won't be able to
381 unwind from that split. */
383 #ifdef __ARM_EABI_UNWINDER__
384 /* ARM EABI personality routines must also unwind the stack. */
385 #define CONTINUE_UNWINDING \
386 do \
388 if (__gnu_unwind_frame (ue_header, context) != _URC_OK) \
389 return _URC_FAILURE; \
390 return _URC_CONTINUE_UNWIND; \
392 while (0)
393 #else
394 #define CONTINUE_UNWINDING return _URC_CONTINUE_UNWIND
395 #endif
397 #ifdef __ARM_EABI_UNWINDER__
398 #define STOP_UNWINDING _URC_FAILURE
399 #else
400 #define STOP_UNWINDING _URC_NORMAL_STOP
401 #endif
403 #ifdef __USING_SJLJ_EXCEPTIONS__
404 #define PERSONALITY_FUNCTION __gccgo_personality_sj0
405 #define __builtin_eh_return_data_regno(x) x
406 #else
407 #define PERSONALITY_FUNCTION __gccgo_personality_v0
408 #endif
410 #ifdef __ARM_EABI_UNWINDER__
411 _Unwind_Reason_Code
412 PERSONALITY_FUNCTION (_Unwind_State, struct _Unwind_Exception *,
413 struct _Unwind_Context *)
414 __attribute__ ((no_split_stack, flatten, target ("general-regs-only")));
416 _Unwind_Reason_Code
417 PERSONALITY_FUNCTION (_Unwind_State state,
418 struct _Unwind_Exception * ue_header,
419 struct _Unwind_Context * context)
420 #else
421 _Unwind_Reason_Code
422 PERSONALITY_FUNCTION (int, _Unwind_Action, _Unwind_Exception_Class,
423 struct _Unwind_Exception *, struct _Unwind_Context *)
424 __attribute__ ((no_split_stack, flatten));
426 _Unwind_Reason_Code
427 PERSONALITY_FUNCTION (int version,
428 _Unwind_Action actions,
429 _Unwind_Exception_Class exception_class,
430 struct _Unwind_Exception *ue_header,
431 struct _Unwind_Context *context)
432 #endif
434 lsda_header_info info;
435 const unsigned char *language_specific_data, *p, *action_record;
436 _Unwind_Ptr landing_pad, ip;
437 int ip_before_insn = 0;
438 _Bool is_foreign;
439 G *g;
441 #ifdef __ARM_EABI_UNWINDER__
442 _Unwind_Action actions;
444 switch (state & _US_ACTION_MASK)
446 case _US_VIRTUAL_UNWIND_FRAME:
447 if (state & _UA_FORCE_UNWIND)
448 /* We are called from _Unwind_Backtrace. No handler to run. */
449 CONTINUE_UNWINDING;
450 actions = _UA_SEARCH_PHASE;
451 break;
453 case _US_UNWIND_FRAME_STARTING:
454 actions = _UA_CLEANUP_PHASE;
455 if (!(state & _US_FORCE_UNWIND)
456 && ue_header->barrier_cache.sp == _Unwind_GetGR(context, 13))
457 actions |= _UA_HANDLER_FRAME;
458 break;
460 case _US_UNWIND_FRAME_RESUME:
461 CONTINUE_UNWINDING;
462 break;
464 default:
465 abort();
467 actions |= state & _US_FORCE_UNWIND;
469 is_foreign = 0;
471 /* The dwarf unwinder assumes the context structure holds things like the
472 function and LSDA pointers. The ARM implementation caches these in
473 the exception header (UCB). To avoid rewriting everything we make the
474 virtual IP register point at the UCB. */
475 ip = (_Unwind_Ptr) ue_header;
476 _Unwind_SetGR (context, 12, ip);
477 #else
478 if (version != 1)
479 return _URC_FATAL_PHASE1_ERROR;
481 is_foreign = exception_class != __go_exception_class;
482 #endif
484 language_specific_data = (const unsigned char *)
485 _Unwind_GetLanguageSpecificData (context);
487 /* If no LSDA, then there are no handlers or cleanups. */
488 if (! language_specific_data)
489 CONTINUE_UNWINDING;
491 /* Parse the LSDA header. */
492 p = parse_lsda_header (context, language_specific_data, &info);
493 #ifdef HAVE_GETIPINFO
494 ip = _Unwind_GetIPInfo (context, &ip_before_insn);
495 #else
496 ip = _Unwind_GetIP (context);
497 #endif
498 if (! ip_before_insn)
499 --ip;
500 landing_pad = 0;
501 action_record = NULL;
503 #ifdef __USING_SJLJ_EXCEPTIONS__
504 /* The given "IP" is an index into the call-site table, with two
505 exceptions -- -1 means no-action, and 0 means terminate. But
506 since we're using uleb128 values, we've not got random access
507 to the array. */
508 if ((int) ip <= 0)
509 return _URC_CONTINUE_UNWIND;
510 else
512 _uleb128_t cs_lp, cs_action;
515 p = read_uleb128 (p, &cs_lp);
516 p = read_uleb128 (p, &cs_action);
518 while (--ip);
520 /* Can never have null landing pad for sjlj -- that would have
521 been indicated by a -1 call site index. */
522 landing_pad = (_Unwind_Ptr)cs_lp + 1;
523 if (cs_action)
524 action_record = info.action_table + cs_action - 1;
525 goto found_something;
527 #else
528 /* Search the call-site table for the action associated with this IP. */
529 while (p < info.action_table)
531 _Unwind_Ptr cs_start, cs_len, cs_lp;
532 _uleb128_t cs_action;
534 /* Note that all call-site encodings are "absolute" displacements. */
535 p = read_encoded_value (0, info.call_site_encoding, p, &cs_start);
536 p = read_encoded_value (0, info.call_site_encoding, p, &cs_len);
537 p = read_encoded_value (0, info.call_site_encoding, p, &cs_lp);
538 p = read_uleb128 (p, &cs_action);
540 /* The table is sorted, so if we've passed the ip, stop. */
541 if (ip < info.Start + cs_start)
542 p = info.action_table;
543 else if (ip < info.Start + cs_start + cs_len)
545 if (cs_lp)
546 landing_pad = info.LPStart + cs_lp;
547 if (cs_action)
548 action_record = info.action_table + cs_action - 1;
549 goto found_something;
552 #endif
554 /* IP is not in table. No associated cleanups. */
555 CONTINUE_UNWINDING;
557 found_something:
558 if (landing_pad == 0)
560 /* IP is present, but has a null landing pad.
561 No handler to be run. */
562 CONTINUE_UNWINDING;
565 if (actions & _UA_SEARCH_PHASE)
567 if (action_record == 0)
569 /* This indicates a cleanup rather than an exception
570 handler. */
571 CONTINUE_UNWINDING;
574 return _URC_HANDLER_FOUND;
577 /* It's possible for g to be NULL here for an exception thrown by a
578 language other than Go. */
579 g = runtime_g ();
580 if (g == NULL)
582 if (!is_foreign)
583 abort ();
585 else
587 g->exception = ue_header;
588 g->isforeign = is_foreign;
591 _Unwind_SetGR (context, __builtin_eh_return_data_regno (0),
592 (_Unwind_Ptr) ue_header);
593 _Unwind_SetGR (context, __builtin_eh_return_data_regno (1), 0);
594 _Unwind_SetIP (context, landing_pad);
595 return _URC_INSTALL_CONTEXT;
598 // A dummy personality function, which doesn't capture any exception
599 // and simply passes by. This is used for functions that don't
600 // capture exceptions but need LSDA for stack maps.
601 _Unwind_Reason_Code
602 __gccgo_personality_dummy (int, _Unwind_Action, _Unwind_Exception_Class,
603 struct _Unwind_Exception *, struct _Unwind_Context *)
604 __attribute__ ((no_split_stack));
606 _Unwind_Reason_Code
607 #ifdef __ARM_EABI_UNWINDER__
608 __attribute__ ((target ("general-regs-only")))
609 #endif
610 __gccgo_personality_dummy (int version __attribute__ ((unused)),
611 _Unwind_Action actions __attribute__ ((unused)),
612 _Unwind_Exception_Class exception_class __attribute__ ((unused)),
613 struct _Unwind_Exception *ue_header __attribute__ ((unused)),
614 struct _Unwind_Context *context __attribute__ ((unused)))
616 CONTINUE_UNWINDING;
619 // A sentinel value for Go functions.
620 // A function is a Go function if it has LSDA, which has type info,
621 // and the first (dummy) landing pad's type info is a pointer to
622 // this value.
623 #define GO_FUNC_SENTINEL ((uint64)'G' | ((uint64)'O'<<8) | \
624 ((uint64)'.'<<16) | ((uint64)'.'<<24) | \
625 ((uint64)'F'<<32) | ((uint64)'U'<<40) | \
626 ((uint64)'N'<<48) | ((uint64)'C'<<56))
628 struct _stackmap {
629 uint32 len;
630 uint8 data[1]; // variabe length
633 extern void
634 runtime_scanstackblockwithmap (uintptr ip, uintptr sp, uintptr size, uint8 *ptrmask, void* gcw)
635 __asm__ (GOSYM_PREFIX "runtime.scanstackblockwithmap");
637 #define FOUND 0
638 #define NOTFOUND_OK 1
639 #define NOTFOUND_BAD 2
641 // Helper function to search for stack maps in the unwinding records of a frame.
642 // If found, populate ip, sp, and stackmap. Returns the #define'd values above.
643 static int
644 findstackmaps (struct _Unwind_Context *context, _Unwind_Ptr *ip, _Unwind_Ptr *sp, struct _stackmap **stackmap)
646 lsda_header_info info;
647 const unsigned char *language_specific_data, *p, *action_record;
648 bool first;
649 struct _stackmap *stackmap1;
650 _Unwind_Ptr ip1;
651 int ip_before_insn = 0;
652 _sleb128_t index;
653 int size;
655 #ifdef HAVE_GETIPINFO
656 ip1 = _Unwind_GetIPInfo (context, &ip_before_insn);
657 #else
658 ip1 = _Unwind_GetIP (context);
659 #endif
660 if (! ip_before_insn)
661 --ip1;
663 if (ip != NULL)
664 *ip = ip1;
665 if (sp != NULL)
666 *sp = _Unwind_GetCFA (context);
668 #ifdef __ARM_EABI_UNWINDER__
670 _Unwind_Control_Block *ucbp;
671 ucbp = (_Unwind_Control_Block *) _Unwind_GetGR (context, 12);
672 if (*ucbp->pr_cache.ehtp & (1u << 31))
673 // The "compact" model is used, with one of the predefined
674 // personality functions. It doesn't have standard LSDA.
675 return NOTFOUND_OK;
677 #endif
679 language_specific_data = (const unsigned char *)
680 _Unwind_GetLanguageSpecificData (context);
682 /* If no LSDA, then there is no stack maps. */
683 if (! language_specific_data)
684 return NOTFOUND_OK;
686 p = parse_lsda_header (context, language_specific_data, &info);
688 if (info.TType == NULL)
689 return NOTFOUND_OK;
691 size = value_size (info.ttype_encoding);
693 action_record = NULL;
694 first = true;
696 /* Search the call-site table for the action associated with this IP. */
697 while (p < info.action_table)
699 _Unwind_Ptr cs_start, cs_len, cs_lp;
700 _uleb128_t cs_action;
702 /* Note that all call-site encodings are "absolute" displacements. */
703 p = read_encoded_value (0, info.call_site_encoding, p, &cs_start);
704 p = read_encoded_value (0, info.call_site_encoding, p, &cs_len);
705 p = read_encoded_value (0, info.call_site_encoding, p, &cs_lp);
706 p = read_uleb128 (p, &cs_action);
708 if (first)
710 // For a Go function, the first entry points to the sentinel value.
711 // Check this here.
712 const unsigned char *p1, *action1;
713 uint64 *x;
715 if (!cs_action)
716 return NOTFOUND_OK;
718 action1 = info.action_table + cs_action - 1;
719 read_sleb128 (action1, &index);
720 p1 = info.TType - index*size;
721 read_encoded_value (context, info.ttype_encoding, p1, (_Unwind_Ptr*)&x);
722 if (x == NULL || *x != GO_FUNC_SENTINEL)
723 return NOTFOUND_OK;
725 first = false;
726 continue;
729 /* The table is sorted, so if we've passed the ip, stop. */
730 if (ip1 < info.Start + cs_start)
731 return NOTFOUND_BAD;
732 else if (ip1 < info.Start + cs_start + cs_len)
734 if (cs_action)
735 action_record = info.action_table + cs_action - 1;
736 break;
740 if (action_record == NULL)
741 return NOTFOUND_BAD;
743 read_sleb128 (action_record, &index);
744 p = info.TType - index*size;
745 read_encoded_value (context, info.ttype_encoding, p, (_Unwind_Ptr*)&stackmap1);
746 if (stackmap1 == NULL)
747 return NOTFOUND_BAD;
749 if (stackmap != NULL)
750 *stackmap = stackmap1;
751 return FOUND;
754 struct scanstate {
755 void* gcw; // the GC worker, passed into scanstackwithmap_callback
756 uintptr lastsp; // the last (outermost) SP of Go function seen in a traceback, set by the callback
759 // Callback function to scan a stack frame with stack maps.
760 // It skips non-Go functions.
761 static _Unwind_Reason_Code
762 scanstackwithmap_callback (struct _Unwind_Context *context, void *arg)
764 struct _stackmap *stackmap;
765 _Unwind_Ptr ip, sp;
766 G* gp;
767 struct scanstate* state = (struct scanstate*) arg;
768 void *gcw;
770 gp = runtime_g ();
771 gcw = state->gcw;
773 switch (findstackmaps (context, &ip, &sp, &stackmap))
775 case NOTFOUND_OK:
776 // Not a Go function. Skip this frame.
777 return _URC_NO_REASON;
778 case NOTFOUND_BAD:
780 // No stack map found.
781 // If we're scanning from the signal stack, the goroutine
782 // may be not stopped at a safepoint. Allow this case.
783 if (gp != gp->m->gsignal)
785 // TODO: print gp, pc, sp
786 runtime_throw ("no stack map");
788 return STOP_UNWINDING;
790 case FOUND:
791 break;
792 default:
793 abort ();
796 state->lastsp = sp;
797 runtime_scanstackblockwithmap (ip, sp, (uintptr)(stackmap->len) * sizeof(uintptr), stackmap->data, gcw);
799 return _URC_NO_REASON;
802 // Scan the stack with stack maps. Return whether the scan
803 // succeeded.
804 bool
805 scanstackwithmap (void *gcw)
807 _Unwind_Reason_Code code;
808 bool ret;
809 struct scanstate state;
810 G* gp;
811 G* curg;
813 state.gcw = gcw;
814 state.lastsp = 0;
815 gp = runtime_g ();
816 curg = gp->m->curg;
818 runtime_xadd (&__go_runtime_in_callers, 1);
819 code = _Unwind_Backtrace (scanstackwithmap_callback, (void*)&state);
820 runtime_xadd (&__go_runtime_in_callers, -1);
821 ret = (code == _URC_END_OF_STACK);
822 if (ret && gp == gp->m->gsignal)
824 // For signal-triggered scan, the unwinder may not be able to unwind
825 // the whole stack while it still reports _URC_END_OF_STACK (e.g.
826 // signal is delivered in vdso). Check that we actually reached the
827 // the end of the stack, that is, the SP on entry.
828 if (state.lastsp != curg->entrysp)
829 ret = false;
831 return ret;
834 // Returns whether stack map is enabled.
835 bool
836 usestackmaps ()
838 return runtime_usestackmaps;
841 // Callback function to probe if a stack frame has stack maps.
842 static _Unwind_Reason_Code
843 probestackmaps_callback (struct _Unwind_Context *context,
844 void *arg __attribute__ ((unused)))
846 switch (findstackmaps (context, NULL, NULL, NULL))
848 case NOTFOUND_OK:
849 case NOTFOUND_BAD:
850 return _URC_NO_REASON;
851 case FOUND:
852 break;
853 default:
854 abort ();
857 // Found a stack map. No need to keep unwinding.
858 runtime_usestackmaps = true;
859 return STOP_UNWINDING;
862 // Try to find a stack map, store the result in global variable runtime_usestackmaps.
863 // Called in start-up time from Go code, so there is a Go frame on the stack.
864 bool
865 probestackmaps ()
867 runtime_usestackmaps = false;
868 _Unwind_Backtrace (probestackmaps_callback, NULL);
869 return runtime_usestackmaps;