stack.c 5.1 KB

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