(root)/
gcc-13.2.0/
libgo/
runtime/
stack.c
       1  // Copyright 2009 The Go Authors. All rights reserved.
       2  // Use of this source code is governed by a BSD-style
       3  // license that can be found in the LICENSE file.
       4  
       5  // Stack scanning code for the garbage collector.
       6  
       7  #include "runtime.h"
       8  
       9  #ifdef USING_SPLIT_STACK
      10  
      11  extern void * __splitstack_find (void *, void *, size_t *, void **, void **,
      12  				 void **);
      13  
      14  extern void * __splitstack_find_context (void *context[10], size_t *, void **,
      15  					 void **, void **);
      16  
      17  #endif
      18  
      19  bool runtime_usestackmaps;
      20  
      21  // Calling unwind_init in doscanstack only works if it does not do a
      22  // tail call to doscanstack1.
      23  #pragma GCC optimize ("-fno-optimize-sibling-calls")
      24  
      25  extern void scanstackblock(uintptr addr, uintptr size, void *gcw)
      26    __asm__(GOSYM_PREFIX "runtime.scanstackblock");
      27  
      28  static bool doscanstack1(G*, void*)
      29    __attribute__ ((noinline));
      30  
      31  // Scan gp's stack, passing stack chunks to scanstackblock.
      32  bool doscanstack(G *gp, void* gcw) {
      33  	// Save registers on the stack, so that if we are scanning our
      34  	// own stack we will see them.
      35  	if (!runtime_usestackmaps) {
      36  		__builtin_unwind_init();
      37  		flush_registers_to_secondary_stack();
      38  	}
      39  
      40  	return doscanstack1(gp, gcw);
      41  }
      42  
      43  // Scan gp's stack after saving registers.
      44  static bool doscanstack1(G *gp, void *gcw) {
      45  #ifdef USING_SPLIT_STACK
      46  	void* sp;
      47  	size_t spsize;
      48  	void* next_segment;
      49  	void* next_sp;
      50  	void* initial_sp;
      51  	G* _g_;
      52  
      53  	_g_ = runtime_g();
      54  	if (runtime_usestackmaps) {
      55  		// If stack map is enabled, we get here only when we can unwind
      56  		// the stack being scanned. That is, either we are scanning our
      57  		// own stack, or we are scanning through a signal handler.
      58  		__go_assert((_g_ == gp) || ((_g_ == gp->m->gsignal) && (gp == gp->m->curg)));
      59  		return scanstackwithmap(gcw);
      60  	}
      61  	if (_g_ == gp) {
      62  		// Scanning our own stack.
      63  		// If we are on a signal stack, it can unwind through the signal
      64  		// handler and see the g stack, so just scan our own stack.
      65  		sp = __splitstack_find(nil, nil, &spsize, &next_segment,
      66  				       &next_sp, &initial_sp);
      67  	} else {
      68  		// Scanning another goroutine's stack.
      69  		// The goroutine is usually asleep (the world is stopped).
      70  
      71  		// The exception is that if the goroutine is about to enter or might
      72  		// have just exited a system call, it may be executing code such
      73  		// as schedlock and may have needed to start a new stack segment.
      74  		// Use the stack segment and stack pointer at the time of
      75  		// the system call instead, since that won't change underfoot.
      76  		if(gp->gcstack != 0) {
      77  			sp = (void*)(gp->gcstack);
      78  			spsize = gp->gcstacksize;
      79  			next_segment = (void*)(gp->gcnextsegment);
      80  			next_sp = (void*)(gp->gcnextsp);
      81  			initial_sp = (void*)(gp->gcinitialsp);
      82  		} else {
      83  			sp = __splitstack_find_context((void**)(&gp->stackcontext[0]),
      84  						       &spsize, &next_segment,
      85  						       &next_sp, &initial_sp);
      86  		}
      87  	}
      88  	if(sp != nil) {
      89  		scanstackblock((uintptr)(sp), (uintptr)(spsize), gcw);
      90  		while((sp = __splitstack_find(next_segment, next_sp,
      91  					      &spsize, &next_segment,
      92  					      &next_sp, &initial_sp)) != nil)
      93  			scanstackblock((uintptr)(sp), (uintptr)(spsize), gcw);
      94  	}
      95  #else
      96  	byte* bottom;
      97  	byte* top;
      98  	byte* nextsp2;
      99  	byte* initialsp2;
     100  
     101  	if(gp == runtime_g()) {
     102  		// Scanning our own stack.
     103  		bottom = (byte*)&gp;
     104  		nextsp2 = secondary_stack_pointer();
     105  	} else {
     106  		// Scanning another goroutine's stack.
     107  		// The goroutine is usually asleep (the world is stopped).
     108  		bottom = (void*)gp->gcnextsp;
     109  		if(bottom == nil)
     110  			return true;
     111  		nextsp2 = (void*)gp->gcnextsp2;
     112  	}
     113  	top = (byte*)(void*)(gp->gcinitialsp) + gp->gcstacksize;
     114  	if(top > bottom)
     115  		scanstackblock((uintptr)(bottom), (uintptr)(top - bottom), gcw);
     116  	else
     117  		scanstackblock((uintptr)(top), (uintptr)(bottom - top), gcw);
     118  	if (nextsp2 != nil) {
     119  		initialsp2 = (byte*)(void*)(gp->gcinitialsp2);
     120  		if(initialsp2 > nextsp2)
     121  			scanstackblock((uintptr)(nextsp2), (uintptr)(initialsp2 - nextsp2), gcw);
     122  		else
     123  			scanstackblock((uintptr)(initialsp2), (uintptr)(nextsp2 - initialsp2), gcw);
     124  	}
     125  #endif
     126  	return true;
     127  }
     128  
     129  extern bool onCurrentStack(uintptr p)
     130    __asm__(GOSYM_PREFIX "runtime.onCurrentStack");
     131  
     132  bool onCurrentStack(uintptr p)
     133  {
     134  #ifdef USING_SPLIT_STACK
     135  
     136  	void* sp;
     137  	size_t spsize;
     138  	void* next_segment;
     139  	void* next_sp;
     140  	void* initial_sp;
     141  
     142  	sp = __splitstack_find(nil, nil, &spsize, &next_segment, &next_sp,
     143  			       &initial_sp);
     144  	while (sp != nil) {
     145  		if (p >= (uintptr)(sp) && p < (uintptr)(sp) + spsize) {
     146  			return true;
     147  		}
     148  		sp = __splitstack_find(next_segment, next_sp, &spsize,
     149  				       &next_segment, &next_sp, &initial_sp);
     150  	}
     151  	return false;
     152  
     153  #else
     154  
     155  	G* gp;
     156  	byte* bottom;
     157  	byte* top;
     158  	byte* temp;
     159  	byte* nextsp2;
     160  	byte* initialsp2;
     161  
     162  	gp = runtime_g();
     163  	bottom = (byte*)(&p);
     164  	top = (byte*)(void*)(gp->gcinitialsp) + gp->gcstacksize;
     165  	if ((uintptr)(top) < (uintptr)(bottom)) {
     166  		temp = top;
     167  		top = bottom;
     168  		bottom = temp;
     169  	}
     170  	if (p >= (uintptr)(bottom) && p < (uintptr)(top)) {
     171  		return true;
     172  	}
     173  
     174  	nextsp2 = secondary_stack_pointer();
     175  	if (nextsp2 != nil) {
     176  		initialsp2 = (byte*)(void*)(gp->gcinitialsp2);
     177  		if ((uintptr)(initialsp2) < (uintptr)(nextsp2)) {
     178  			temp = initialsp2;
     179  			initialsp2 = nextsp2;
     180  			nextsp2 = temp;
     181  		}
     182  		if (p >= (uintptr)(nextsp2) && p < (uintptr)(initialsp2)) {
     183  			return true;
     184  		}
     185  	}
     186  
     187  	return false;
     188  
     189  #endif
     190  }