uint ScanStack(Thread thread, NonNullReferenceVisitor VisitThreadReference, NonNullReferenceVisitor VisitPinnedReference) { Trace.Log(Trace.Area.Stack, "Scanning stack for thread {0:x}", __arglist(thread.threadIndex)); uint numStackFrames = 0; threadBeingProcessed = thread; CalleeSaveLocations calleeSaves = new CalleeSaveLocations(); #if SINGULARITY_KERNEL TransitionRecord *marker = (TransitionRecord *)thread.context.stackMarkers; #elif SINGULARITY_PROCESS TransitionRecord *marker = null; if (thread.context != null) { marker = (TransitionRecord *)thread.context->stackMarkers; } #else TransitionRecord *marker = (TransitionRecord *) MixinThread(thread).asmStackMarker; #endif while (marker != null) { Trace.Log(Trace.Area.Stack, "Transition record: old={0:x}, callAddr={1:x}, stackBottom={2:x}", __arglist(marker->oldTransitionRecord, marker->callAddr, marker->stackBottom)); marker->calleeSaveRegisters.DebugTrace(); TransitionRecord *stopMarker = marker->oldTransitionRecord; UIntPtr returnAddr = marker->callAddr; UIntPtr * fp = (UIntPtr *) marker->calleeSaveRegisters.GetFramePointer(); UIntPtr *sp = (UIntPtr *)marker->stackBottom; calleeSaves.SetCalleeSaves(&marker->calleeSaveRegisters); numStackFrames += ScanStackSegment(ref calleeSaves, returnAddr, fp, sp, stopMarker, VisitThreadReference, VisitPinnedReference, thread); marker = marker->oldTransitionRecord; } threadBeingProcessed = null; return(numStackFrames); }
uint ScanStackSegment(ref CalleeSaveLocations calleeSaves, UIntPtr returnAddr, UIntPtr *fp, UIntPtr *sp, TransitionRecord *stopMarker, NonNullReferenceVisitor VisitThreadReference, NonNullReferenceVisitor VisitPinnedReference, Thread thread) // BUGBUG: Remove thread argument when ThreadContext is on stack! { uint numStackFrames = 0; while (true) { #if SINGULARITY if (returnAddr >= LinkStackFunctionsBegin && returnAddr <= LinkStackFunctionsLimit) { if (returnAddr >= LinkStackBegin && returnAddr <= LinkStackLimit) { returnAddr = SkipLinkStackFrame(ref fp, ref sp); } else if (returnAddr >= UnlinkStackBegin && returnAddr <= UnlinkStackLimit) { returnAddr = SkipUnlinkStackFrame(ref fp, ref sp); } else if (returnAddr >= LinkStackStubsBegin && returnAddr <= LinkStackStubsLimit) { returnAddr = SkipLinkStackStubFrame(ref fp, ref sp); } else { VTable.NotReached("Unexpected link stack function"); } } #endif // Exit loop if we have reached the of the stack segment if (fp >= stopMarker && sp < stopMarker) { break; } int tableIndex = CallSiteTableNumber(returnAddr); if (tableIndex < 0) { break; } int callSiteSet = CallSiteSetNumber(returnAddr, tableIndex); if (callSiteSet < 0) { break; } ushort *callSiteToIndexTable = callSetSiteNumberToIndex[tableIndex]; int activationIndex = (int)callSiteToIndexTable[callSiteSet]; VTable.Assert(activationIndex >= 0); CompressedFrameDescriptor *descriptorTable = activationDescriptorTable[tableIndex]; CompressedFrameDescriptor frameDescriptor = descriptorTable[activationIndex]; bool done = WalkStackFrame(ref fp, ref sp, ref calleeSaves, ref returnAddr, VisitThreadReference, VisitPinnedReference, frameDescriptor, stopMarker, thread); if (done) { break; } numStackFrames++; } calleeSaves.ClearCalleeSaves(); return(numStackFrames); }
bool WalkStackFrame(ref UIntPtr *framePointer, ref UIntPtr *stackPointer, ref CalleeSaveLocations calleeSaves, ref UIntPtr returnAddr, NonNullReferenceVisitor threadReferenceVisitor, NonNullReferenceVisitor pinnedReferenceVisitor, CompressedFrameDescriptor smallFrameDescriptor, TransitionRecord *stopMarker, Thread thread) // BUGBUG: Remove thread argument when ThreadContext is on stack! { FrameDescriptor frameDescriptor = new FrameDescriptor(smallFrameDescriptor); if (frameDescriptor.isFramePointerOmitted) { framePointer = stackPointer + frameDescriptor.frameSize; } if (FrameContainsTransitionRecord(framePointer, stackPointer, stopMarker)) { return(true); // true: done } switch (frameDescriptor.argumentTag) { case FrameDescriptor.ESCAPE32_TAG: { int *table = (int *)frameDescriptor.argumentMaskOrTable; int count = table[0]; int pinnedCount = table[1]; int *offsets = &table[2]; if (threadReferenceVisitor != null) { for (int i = 0; i < count; i++) { UIntPtr *loc = framePointer + offsets[i]; if (*loc != UIntPtr.Zero) { // BUGBUG: threadReferenceVisitor.Visit(loc); VisitIfNotContext(thread, threadReferenceVisitor, loc); } } } if (frameDescriptor.hasPinnedVariables && pinnedReferenceVisitor != null) { offsets = &offsets[count]; for (int i = 0; i < pinnedCount; i++) { UIntPtr *loc = framePointer + offsets[i]; if (*loc != UIntPtr.Zero) { pinnedReferenceVisitor.Visit(loc); } } } break; } case FrameDescriptor.ESCAPE16_TAG: { short *table = (short *)frameDescriptor.argumentMaskOrTable; int count = table[0]; int pinnedCount = table[1]; short *offsets = &table[2]; if (threadReferenceVisitor != null) { for (int i = 0; i < count; i++) { UIntPtr *loc = framePointer + offsets[i]; if (*loc != UIntPtr.Zero) { // BUGBUG: threadReferenceVisitor.Visit(loc); VisitIfNotContext(thread, threadReferenceVisitor, loc); } } } if (frameDescriptor.hasPinnedVariables && pinnedReferenceVisitor != null) { offsets = &offsets[count]; for (int i = 0; i < pinnedCount; i++) { UIntPtr *loc = framePointer + offsets[i]; if (*loc != UIntPtr.Zero) { pinnedReferenceVisitor.Visit(loc); } } } break; } case FrameDescriptor.ESCAPE8_TAG: { sbyte *table = (sbyte *)frameDescriptor.argumentMaskOrTable; int count = table[0]; int pinnedCount = table[1]; sbyte *offsets = &table[2]; if (threadReferenceVisitor != null) { for (int i = 0; i < count; i++) { UIntPtr *loc = framePointer + offsets[i]; if (*loc != UIntPtr.Zero) { // BUGBUG: threadReferenceVisitor.Visit(loc); VisitIfNotContext(thread, threadReferenceVisitor, loc); } } } if (frameDescriptor.hasPinnedVariables && pinnedReferenceVisitor != null) { offsets = &offsets[count]; for (int i = 0; i < pinnedCount; i++) { UIntPtr *loc = framePointer + offsets[i]; if (*loc != UIntPtr.Zero) { pinnedReferenceVisitor.Visit(loc); } } } break; } case FrameDescriptor.COMPRESSED_MASK_TAG: { // Process the arguments int inBetweenSlotsAbove = frameDescriptor.inBetweenSlotsAbove; uint stackArgSize = frameDescriptor.argumentCount; UIntPtr mask = frameDescriptor.argumentMaskOrTable; if (threadReferenceVisitor != null && stackArgSize > 0) { UIntPtr *argumentPointer = framePointer + stackArgSize - 1 + inBetweenSlotsAbove; for (int i = 0; mask != 0 && i < stackArgSize; i++) { if ((mask & 0x1) != 0 && *argumentPointer != UIntPtr.Zero) { // BUGBUG: threadReferenceVisitor.Visit(p); VisitIfNotContext(thread, threadReferenceVisitor, argumentPointer); } mask >>= 1; argumentPointer--; } } else { for (int i = 0; mask != 0 && i < stackArgSize; i++) { mask >>= 1; } } // Process the local variables if (threadReferenceVisitor != null) { int transitionRecordSize = frameDescriptor.hasTransitionRecord ? sizeof(TransitionRecord) / sizeof(UIntPtr) : 0; int registerCount = CountBits(frameDescriptor.calleeSaveMask); int inBetweenSlotsBelow = frameDescriptor.inBetweenSlotsBelow; UIntPtr *variablePtr = framePointer - inBetweenSlotsBelow - registerCount - transitionRecordSize - 1; // -1 because FP is pointing in "above" region. while (mask != UIntPtr.Zero) { if ((mask & 0x1) != 0 && *variablePtr != UIntPtr.Zero) { // BUGBUG: threadReferenceVisitor.Visit(p); VisitIfNotContext(thread, threadReferenceVisitor, variablePtr); } mask >>= 1; variablePtr--; } } break; } default: { VTable.NotReached("FrameDescriptor mask switch failed"); break; } } if (frameDescriptor.calleeSaveValueMask != 0 && threadReferenceVisitor != null) { calleeSaves.ScanLiveRegs(frameDescriptor.calleeSaveValueMask, threadReferenceVisitor); } #if X86 || AMD64 || ISA_IX86 || ISA_IX64 UIntPtr nextReturnAddr; if (frameDescriptor.isFramePointerOmitted) { nextReturnAddr = *framePointer; stackPointer = framePointer + 1; } else { nextReturnAddr = *(framePointer + 1); stackPointer = framePointer + 2; } #elif ARM || ISA_ARM // CompressedFrameDescriptor is the target specific portion. // This will be refactored to FrameDescriptor via partial classes. UIntPtr nextReturnAddr = CompressedFrameDescriptor.NextCallSite(frameDescriptor.isFramePointerOmitted, framePointer, out stackPointer); #else #error Unknown Architecture #endif // In Singularity, the final return address of a thread is zero if (nextReturnAddr != UIntPtr.Zero) { calleeSaves.PopFrame(framePointer, frameDescriptor.calleeSaveMask, frameDescriptor.isFramePointerOmitted, frameDescriptor.hasTransitionRecord); } else { calleeSaves.ClearFrame(frameDescriptor.calleeSaveMask, frameDescriptor.isFramePointerOmitted); } UIntPtr *calcedfp = (UIntPtr *)calleeSaves.GetFramePointer(); if (calcedfp != null) { framePointer = calcedfp; } returnAddr = nextReturnAddr; return(false); // false: not done scanning: proceed to next frame }