#include "private/pthread_support.h" /* This probably needs more porting work to ppc64. */ # if defined(GC_DARWIN_THREADS) /* From "Inside Mac OS X - Mach-O Runtime Architecture" published by Apple Page 49: "The space beneath the stack pointer, where a new stack frame would normally be allocated, is called the red zone. This area as shown in Figure 3-2 may be used for any purpose as long as a new stack frame does not need to be added to the stack." Page 50: "If a leaf procedure's red zone usage would exceed 224 bytes, then it must set up a stack frame just like routines that call other routines." */ #if defined(__ppc__) # define PPC_RED_ZONE_SIZE 224 #elif defined(__ppc64__) # define PPC_RED_ZONE_SIZE 320 #endif typedef struct StackFrame { unsigned long savedSP; unsigned long savedCR; unsigned long savedLR; unsigned long reserved[2]; unsigned long savedRTOC; } StackFrame; unsigned long FindTopOfStack(unsigned long stack_start) { StackFrame *frame; if (stack_start == 0) { # ifdef POWERPC # if CPP_WORDSZ == 32 __asm__ volatile("lwz %0,0(r1)" : "=r" (frame)); # else __asm__ volatile("ld %0,0(r1)" : "=r" (frame)); # endif # endif } else { frame = (StackFrame *)stack_start; } # ifdef DEBUG_THREADS /* GC_printf1("FindTopOfStack start at sp = %p\n", frame); */ # endif do { if (frame->savedSP == 0) break; /* if there are no more stack frames, stop */ frame = (StackFrame*)frame->savedSP; /* we do these next two checks after going to the next frame because the LR for the first stack frame in the loop is not set up on purpose, so we shouldn't check it. */ if ((frame->savedLR & ~3) == 0) break; /* if the next LR is bogus, stop */ if ((~(frame->savedLR) & ~3) == 0) break; /* ditto */ } while (1); # ifdef DEBUG_THREADS /* GC_printf1("FindTopOfStack finish at sp = %p\n", frame); */ # endif return (unsigned long)frame; } #ifdef DARWIN_DONT_PARSE_STACK void GC_push_all_stacks() { int i; kern_return_t r; GC_thread p; pthread_t me; ptr_t lo, hi; GC_THREAD_STATE_T state; mach_msg_type_number_t thread_state_count = GC_MACH_THREAD_STATE_COUNT; me = pthread_self(); if (!GC_thr_initialized) GC_thr_init(); for(i=0;inext) { if(p -> flags & FINISHED) continue; if(pthread_equal(p->id,me)) { lo = GC_approx_sp(); } else { /* Get the thread state (registers, etc) */ r = thread_get_state(p->stop_info.mach_thread, GC_MACH_THREAD_STATE, (natural_t*)&state, &thread_state_count); if(r != KERN_SUCCESS) ABORT("thread_get_state failed"); #if defined(I386) lo = (void*)state . THREAD_FLD (esp); GC_push_one(state . THREAD_FLD (eax)); GC_push_one(state . THREAD_FLD (ebx)); GC_push_one(state . THREAD_FLD (ecx)); GC_push_one(state . THREAD_FLD (edx)); GC_push_one(state . THREAD_FLD (edi)); GC_push_one(state . THREAD_FLD (esi)); GC_push_one(state . THREAD_FLD (ebp)); #elif defined(X86_64) lo = (void*)state . THREAD_FLD (rsp); GC_push_one(state . THREAD_FLD (rax)); GC_push_one(state . THREAD_FLD (rbx)); GC_push_one(state . THREAD_FLD (rcx)); GC_push_one(state . THREAD_FLD (rdx)); GC_push_one(state . THREAD_FLD (rdi)); GC_push_one(state . THREAD_FLD (rsi)); GC_push_one(state . THREAD_FLD (rbp)); GC_push_one(state . THREAD_FLD (rsp)); GC_push_one(state . THREAD_FLD (r8)); GC_push_one(state . THREAD_FLD (r9)); GC_push_one(state . THREAD_FLD (r10)); GC_push_one(state . THREAD_FLD (r11)); GC_push_one(state . THREAD_FLD (r12)); GC_push_one(state . THREAD_FLD (r13)); GC_push_one(state . THREAD_FLD (r14)); GC_push_one(state . THREAD_FLD (r15)); GC_push_one(state . THREAD_FLD (rip)); GC_push_one(state . THREAD_FLD (rflags)); GC_push_one(state . THREAD_FLD (cs)); GC_push_one(state . THREAD_FLD (fs)); GC_push_one(state . THREAD_FLD (gs)); #elif defined(POWERPC) lo = (void*)(state . THREAD_FLD (r1) - PPC_RED_ZONE_SIZE); GC_push_one(state . THREAD_FLD (r0)); GC_push_one(state . THREAD_FLD (r2)); GC_push_one(state . THREAD_FLD (r3)); GC_push_one(state . THREAD_FLD (r4)); GC_push_one(state . THREAD_FLD (r5)); GC_push_one(state . THREAD_FLD (r6)); GC_push_one(state . THREAD_FLD (r7)); GC_push_one(state . THREAD_FLD (r8)); GC_push_one(state . THREAD_FLD (r9)); GC_push_one(state . THREAD_FLD (r10)); GC_push_one(state . THREAD_FLD (r11)); GC_push_one(state . THREAD_FLD (r12)); GC_push_one(state . THREAD_FLD (r13)); GC_push_one(state . THREAD_FLD (r14)); GC_push_one(state . THREAD_FLD (r15)); GC_push_one(state . THREAD_FLD (r16)); GC_push_one(state . THREAD_FLD (r17)); GC_push_one(state . THREAD_FLD (r18)); GC_push_one(state . THREAD_FLD (r19)); GC_push_one(state . THREAD_FLD (r20)); GC_push_one(state . THREAD_FLD (r21)); GC_push_one(state . THREAD_FLD (r22)); GC_push_one(state . THREAD_FLD (r23)); GC_push_one(state . THREAD_FLD (r24)); GC_push_one(state . THREAD_FLD (r25)); GC_push_one(state . THREAD_FLD (r26)); GC_push_one(state . THREAD_FLD (r27)); GC_push_one(state . THREAD_FLD (r28)); GC_push_one(state . THREAD_FLD (r29)); GC_push_one(state . THREAD_FLD (r30)); GC_push_one(state . THREAD_FLD (r31)); #else # error FIXME for non-x86 || ppc architectures #endif } /* p != me */ if(p->flags & MAIN_THREAD) hi = GC_stackbottom; else hi = p->stack_end; #if DEBUG_THREADS GC_printf3("Darwin: Stack for thread 0x%lx = [%lx,%lx)\n", (unsigned long) p -> id, (unsigned long) lo, (unsigned long) hi ); #endif GC_push_all_stack(lo,hi); } /* for(p=GC_threads[i]...) */ } /* for(i=0;i