void printExInfo(ExInfo exInfo) { Log.deIndent(); foreach (var ex in exInfo.tryStarts) { Log.log(logLevel, "// try start: {0}", getExceptionString(ex)); } foreach (var ex in exInfo.tryEnds) { Log.log(logLevel, "// try end: {0}", getExceptionString(ex)); } foreach (var ex in exInfo.filterStarts) { Log.log(logLevel, "// filter start: {0}", getExceptionString(ex)); } foreach (var ex in exInfo.handlerStarts) { Log.log(logLevel, "// handler start: {0}", getExceptionString(ex)); } foreach (var ex in exInfo.handlerEnds) { Log.log(logLevel, "// handler end: {0}", getExceptionString(ex)); } Log.indent(); }
void PrintExInfo(ExInfo exInfo) { Logger.Instance.DeIndent(); foreach (var ex in exInfo.tryStarts) { Logger.Log(loggerEvent, "// try start: {0}", GetExceptionString(ex)); } foreach (var ex in exInfo.tryEnds) { Logger.Log(loggerEvent, "// try end: {0}", GetExceptionString(ex)); } foreach (var ex in exInfo.filterStarts) { Logger.Log(loggerEvent, "// filter start: {0}", GetExceptionString(ex)); } foreach (var ex in exInfo.handlerStarts) { Logger.Log(loggerEvent, "// handler start: {0}", GetExceptionString(ex)); } foreach (var ex in exInfo.handlerEnds) { Logger.Log(loggerEvent, "// handler end: {0}", GetExceptionString(ex)); } Logger.Instance.Indent(); }
public static void RhThrowHwEx(uint exceptionCode, ref ExInfo exInfo) { // trigger a GC (only if gcstress) to ensure we can stackwalk at this point GCStress.TriggerGC(); InternalCalls.RhpValidateExInfoStack(); IntPtr faultingCodeAddress = exInfo._pExContext->IP; bool instructionFault = true; ExceptionIDs exceptionId; switch (exceptionCode) { case (uint)HwExceptionCode.STATUS_REDHAWK_NULL_REFERENCE: exceptionId = ExceptionIDs.NullReference; break; case (uint)HwExceptionCode.STATUS_REDHAWK_WRITE_BARRIER_NULL_REFERENCE: // The write barrier where the actual fault happened has been unwound already. // The IP of this fault needs to be treated as return address, not as IP of // faulting instruction. instructionFault = false; exceptionId = ExceptionIDs.NullReference; break; case (uint)HwExceptionCode.STATUS_DATATYPE_MISALIGNMENT: exceptionId = ExceptionIDs.DataMisaligned; break; // N.B. -- AVs that have a read/write address lower than 64k are already transformed to // HwExceptionCode.REDHAWK_NULL_REFERENCE prior to calling this routine. case (uint)HwExceptionCode.STATUS_ACCESS_VIOLATION: exceptionId = ExceptionIDs.AccessViolation; break; case (uint)HwExceptionCode.STATUS_INTEGER_DIVIDE_BY_ZERO: exceptionId = ExceptionIDs.DivideByZero; break; case (uint)HwExceptionCode.STATUS_INTEGER_OVERFLOW: exceptionId = ExceptionIDs.Overflow; break; default: // We don't wrap SEH exceptions from foreign code like CLR does, so we believe that we // know the complete set of HW faults generated by managed code and do not need to handle // this case. FailFastViaClasslib(RhFailFastReason.InternalError, null, faultingCodeAddress); exceptionId = ExceptionIDs.NullReference; break; } Exception exceptionToThrow = GetClasslibException(exceptionId, faultingCodeAddress); exInfo.Init(exceptionToThrow, instructionFault); DispatchEx(ref exInfo._frameIter, ref exInfo, MaxTryRegionIdx); FallbackFailFast(RhFailFastReason.InternalError, null); }
ExInfo GetExInfo(Instruction instruction) { if (instruction == null) { return(lastExInfo); } if (!exInfos.TryGetValue(instruction, out var exInfo)) { exInfos[instruction] = exInfo = new ExInfo(); } return(exInfo); }
internal void Init(object exceptionObj, ref ExInfo rethrownExInfo) { // _pPrevExInfo -- set by asm helper // _pExContext -- set by asm helper // _passNumber -- set by asm helper // _idxCurClause -- set by asm helper // _frameIter -- initialized explicitly during dispatch _exception = exceptionObj; _kind = rethrownExInfo._kind | ExKind.RethrowFlag; _notifyDebuggerSP = UIntPtr.Zero; }
public static void RhRethrow(ref ExInfo activeExInfo, ref ExInfo exInfo) { // trigger a GC (only if gcstress) to ensure we can stackwalk at this point GCStress.TriggerGC(); InternalCalls.RhpValidateExInfoStack(); // We need to copy the Exception object to this stack location because collided unwinds will cause // the original stack location to go dead. Exception rethrownException = activeExInfo.ThrownException; exInfo.Init(rethrownException, ref activeExInfo); DispatchEx(ref exInfo._frameIter, ref exInfo, activeExInfo._idxCurClause); BinderIntrinsics.DebugBreak(); }
public static void RhRethrow(ref ExInfo activeExInfo, ref ExInfo exInfo) { // trigger a GC (only if gcstress) to ensure we can stackwalk at this point GCStress.TriggerGC(); InternalCalls.RhpValidateExInfoStack(); // We need to copy the exception object to this stack location because collided unwinds // will cause the original stack location to go dead. object rethrownException = activeExInfo.ThrownException; exInfo.Init(rethrownException, ref activeExInfo); DispatchEx(ref exInfo._frameIter, ref exInfo, activeExInfo._idxCurClause); FallbackFailFast(RhFailFastReason.InternalError, null); }
public void Print(LoggerEvent loggerEvent, IList<Instruction> allInstructions, IList<ExceptionHandler> allExceptionHandlers) { try { this.loggerEvent = loggerEvent; this.allInstructions = allInstructions; this.allExceptionHandlers = allExceptionHandlers; lastExInfo = new ExInfo(); Print(); } finally { this.allInstructions = null; this.allExceptionHandlers = null; targets.Clear(); labels.Clear(); exInfos.Clear(); lastExInfo = null; } }
public static void RhThrowHwEx(uint exceptionCode, ref ExInfo exInfo) { // trigger a GC (only if gcstress) to ensure we can stackwalk at this point GCStress.TriggerGC(); InternalCalls.RhpValidateExInfoStack(); IntPtr faultingCodeAddress = exInfo._pExContext->IP; ExceptionIDs exceptionId; switch (exceptionCode) { case (uint)HwExceptionCode.STATUS_REDHAWK_NULL_REFERENCE: exceptionId = ExceptionIDs.NullReference; break; case (uint)HwExceptionCode.STATUS_DATATYPE_MISALIGNMENT: exceptionId = ExceptionIDs.DataMisaligned; break; // N.B. -- AVs that have a read/write address lower than 64k are already transformed to // HwExceptionCode.REDHAWK_NULL_REFERENCE prior to calling this routine. case (uint)HwExceptionCode.STATUS_ACCESS_VIOLATION: exceptionId = ExceptionIDs.AccessViolation; break; case (uint)HwExceptionCode.STATUS_INTEGER_DIVIDE_BY_ZERO: exceptionId = ExceptionIDs.DivideByZero; break; default: // We don't wrap SEH exceptions from foreign code like CLR does, so we believe that we // know the complete set of HW faults generated by managed code and do not need to handle // this case. FailFastViaClasslib(RhFailFastReason.InternalError, null, faultingCodeAddress); exceptionId = ExceptionIDs.NullReference; break; } Exception exceptionToThrow = GetClasslibException(exceptionId, faultingCodeAddress); exInfo.Init(exceptionToThrow); DispatchEx(ref exInfo._frameIter, ref exInfo, MaxTryRegionIdx); BinderIntrinsics.DebugBreak(); }
public void Print(LoggerEvent loggerEvent, IList <Instruction> allInstructions, IList <ExceptionHandler> allExceptionHandlers) { try { this.loggerEvent = loggerEvent; this.allInstructions = allInstructions; this.allExceptionHandlers = allExceptionHandlers; lastExInfo = new ExInfo(); Print(); } finally { this.allInstructions = null; this.allExceptionHandlers = null; targets.Clear(); labels.Clear(); exInfos.Clear(); lastExInfo = null; } }
public static void RhThrowEx(Exception exceptionObj, ref ExInfo exInfo) { // trigger a GC (only if gcstress) to ensure we can stackwalk at this point Debug.TriggerGCForGCStress(); InternalCalls.RhpValidateExInfoStack(); // Transform attempted throws of null to a throw of NullReferenceException. if (exceptionObj == null) { IntPtr faultingCodeAddress = exInfo._pExContext->IP; exceptionObj = GetClasslibException(ExceptionIDs.NullReference, faultingCodeAddress); } exInfo.Init(exceptionObj); DispatchEx(ref exInfo._frameIter, ref exInfo, MaxTryRegionIdx); BinderIntrinsics.DebugBreak(); }
public void print(Log.LogLevel logLevel, IList<Instruction> allInstructions, IList<ExceptionHandler> allExceptionHandlers) { try { this.logLevel = logLevel; this.allInstructions = allInstructions; this.allExceptionHandlers = allExceptionHandlers; lastExInfo = new ExInfo(); print(); } finally { this.allInstructions = null; this.allExceptionHandlers = null; targets.Clear(); labels.Clear(); exInfos.Clear(); lastExInfo = null; } }
public void print(Log.LogLevel logLevel, IList <Instruction> allInstructions, IList <ExceptionHandler> allExceptionHandlers) { try { this.logLevel = logLevel; this.allInstructions = allInstructions; this.allExceptionHandlers = allExceptionHandlers; lastExInfo = new ExInfo(); print(); } finally { this.allInstructions = null; this.allExceptionHandlers = null; targets.Clear(); labels.Clear(); exInfos.Clear(); lastExInfo = null; } }
public static void RhThrowEx(object exceptionObj, ref ExInfo exInfo) { // trigger a GC (only if gcstress) to ensure we can stackwalk at this point GCStress.TriggerGC(); InternalCalls.RhpValidateExInfoStack(); // Transform attempted throws of null to a throw of NullReferenceException. if (exceptionObj == null) { IntPtr faultingCodeAddress = exInfo._pExContext->IP; exceptionObj = GetClasslibException(ExceptionIDs.NullReference, faultingCodeAddress); } exInfo.Init(exceptionObj); DispatchEx(ref exInfo._frameIter, ref exInfo, MaxTryRegionIdx); FallbackFailFast(RhFailFastReason.InternalError, null); }
private static void UpdateStackTrace(object exceptionObj, ref ExInfo exInfo, ref bool isFirstRethrowFrame, ref UIntPtr prevFramePtr, ref bool isFirstFrame) { // We use the fact that all funclet stack frames belonging to the same logical method activation // will have the same FramePointer value. Additionally, the stackwalker will return a sequence of // callbacks for all the funclet stack frames, one right after the other. The classlib doesn't // want to know about funclets, so we strip them out by only reporting the first frame of a // sequence of funclets. This is correct because the leafmost funclet is first in the sequence // and corresponds to the current 'IP state' of the method. UIntPtr curFramePtr = exInfo._frameIter.FramePointer; if ((prevFramePtr == UIntPtr.Zero) || (curFramePtr != prevFramePtr)) { AppendExceptionStackFrameViaClasslib(exceptionObj, (IntPtr)exInfo._frameIter.ControlPC, ref isFirstRethrowFrame, ref isFirstFrame); } prevFramePtr = curFramePtr; }
internal unsafe static void UnhandledExceptionFailFastViaClasslib( RhFailFastReason reason, Exception unhandledException, ref ExInfo exInfo) { IntPtr pFailFastFunction = (IntPtr)InternalCalls.RhpGetClasslibFunction(exInfo._pExContext->IP, ClassLibFunctionId.FailFast); if (pFailFastFunction == IntPtr.Zero) { FailFastViaClasslib( reason, unhandledException, exInfo._pExContext->IP); } // 16-byte align the context. This is overkill on x86 and ARM, but simplifies things slightly. const int contextAlignment = 16; byte * pbBuffer = stackalloc byte[sizeof(OSCONTEXT) + contextAlignment]; void * pContext = PointerAlign(pbBuffer, contextAlignment); // We 'normalized' the faulting IP of hardware faults to behave like return addresses. Undo this // normalization here so that we report the correct thing in the exception context record. if ((exInfo._kind & ExKind.KindMask) == ExKind.HardwareFault) { exInfo._pExContext->IP = (IntPtr)(((byte *)exInfo._pExContext->IP) - c_IPAdjustForHardwareFault); } InternalCalls.RhpCopyContextFromExInfo(pContext, sizeof(OSCONTEXT), exInfo._pExContext); try { CalliIntrinsics.CallVoid(pFailFastFunction, reason, unhandledException, (IntPtr)pContext); } catch { // Unfortunately, this catch turns into "catch (System.Object)", which will not catch // exceptions thrown from the class library because their objects do not derive from our // System.Object. // // @TODO: Use a filtered catch whose filter always returns 'true'. } // The classlib's funciton should never return and should not throw. If it does, then we fail our way... FailFast(reason, unhandledException); }
internal unsafe static void UnhandledExceptionFailFastViaClasslib( RhFailFastReason reason, Exception unhandledException, ref ExInfo exInfo) { IntPtr pFailFastFunction = (IntPtr)InternalCalls.RhpGetClasslibFunction(exInfo._pExContext->IP, ClassLibFunctionId.FailFast); if (pFailFastFunction == IntPtr.Zero) { FailFastViaClasslib( reason, unhandledException, exInfo._pExContext->IP); } // 16-byte align the context. This is overkill on x86 and ARM, but simplifies things slightly. const int contextAlignment = 16; byte * pbBuffer = stackalloc byte[sizeof(OSCONTEXT) + contextAlignment]; void * pContext = PointerAlign(pbBuffer, contextAlignment); // We 'normalized' the faulting IP of hardware faults to behave like return addresses. Undo this // normalization here so that we report the correct thing in the exception context record. if ((exInfo._kind & ExKind.KindMask) == ExKind.HardwareFault) { exInfo._pExContext->IP = (IntPtr)(((byte *)exInfo._pExContext->IP) - c_IPAdjustForHardwareFault); } InternalCalls.RhpCopyContextFromExInfo(pContext, sizeof(OSCONTEXT), exInfo._pExContext); try { CalliIntrinsics.CallVoid(pFailFastFunction, reason, unhandledException, (IntPtr)pContext); } catch { // disallow all exceptions leaking out of callbacks } // The classlib's funciton should never return and should not throw. If it does, then we fail our way... FallbackFailFast(reason, unhandledException); }
private static void DispatchEx(ref StackFrameIterator frameIter, ref ExInfo exInfo, uint startIdx) { Debug.Assert(exInfo._passNumber == 1, "expected asm throw routine to set the pass"); object exceptionObj = exInfo.ThrownException; // ------------------------------------------------ // // First pass // // ------------------------------------------------ UIntPtr handlingFrameSP = MaxSP; byte * pCatchHandler = null; uint catchingTryRegionIdx = MaxTryRegionIdx; bool isFirstRethrowFrame = (startIdx != MaxTryRegionIdx); bool isFirstFrame = true; byte * prevControlPC = null; UIntPtr prevFramePtr = UIntPtr.Zero; bool unwoundReversePInvoke = false; bool isValid = frameIter.Init(exInfo._pExContext); Debug.Assert(isValid, "RhThrowEx called with an unexpected context"); DebuggerNotify.BeginFirstPass(exceptionObj, frameIter.ControlPC, frameIter.SP); for (; isValid; isValid = frameIter.Next(out startIdx, out unwoundReversePInvoke)) { // For GC stackwalking, we'll happily walk across native code blocks, but for EH dispatch, we // disallow dispatching exceptions across native code. if (unwoundReversePInvoke) { break; } prevControlPC = frameIter.ControlPC; DebugScanCallFrame(exInfo._passNumber, frameIter.ControlPC, frameIter.SP); // A debugger can subscribe to get callbacks at a specific frame of exception dispatch // exInfo._notifyDebuggerSP can be populated by the debugger from out of process // at any time. if (exInfo._notifyDebuggerSP == frameIter.SP) { DebuggerNotify.FirstPassFrameEntered(exceptionObj, frameIter.ControlPC, frameIter.SP); } UpdateStackTrace(exceptionObj, ref exInfo, ref isFirstRethrowFrame, ref prevFramePtr, ref isFirstFrame); byte *pHandler; if (FindFirstPassHandler(exceptionObj, startIdx, ref frameIter, out catchingTryRegionIdx, out pHandler)) { handlingFrameSP = frameIter.SP; pCatchHandler = pHandler; DebugVerifyHandlingFrame(handlingFrameSP); break; } } DebuggerNotify.EndFirstPass(exceptionObj, pCatchHandler, handlingFrameSP); if (pCatchHandler == null) { UnhandledExceptionFailFastViaClasslib( RhFailFastReason.PN_UnhandledException, exceptionObj, (IntPtr)prevControlPC, // IP of the last frame that did not handle the exception ref exInfo); } // We FailFast above if the exception goes unhandled. Therefore, we cannot run the second pass // without a catch handler. Debug.Assert(pCatchHandler != null, "We should have a handler if we're starting the second pass"); DebuggerNotify.BeginSecondPass(); // ------------------------------------------------ // // Second pass // // ------------------------------------------------ // Due to the stackwalker logic, we cannot tolerate triggering a GC from the dispatch code once we // are in the 2nd pass. This is because the stackwalker applies a particular unwind semantic to // 'collapse' funclets which gets confused when we walk out of the dispatch code and encounter the // 'main body' without first encountering the funclet. The thunks used to invoke 2nd-pass // funclets will always toggle this mode off before invoking them. InternalCalls.RhpSetThreadDoNotTriggerGC(); exInfo._passNumber = 2; startIdx = MaxTryRegionIdx; isValid = frameIter.Init(exInfo._pExContext); for (; isValid && ((byte *)frameIter.SP <= (byte *)handlingFrameSP); isValid = frameIter.Next(out startIdx)) { Debug.Assert(isValid, "second-pass EH unwind failed unexpectedly"); DebugScanCallFrame(exInfo._passNumber, frameIter.ControlPC, frameIter.SP); if (frameIter.SP == handlingFrameSP) { // invoke only a partial second-pass here... InvokeSecondPass(ref exInfo, startIdx, catchingTryRegionIdx); break; } InvokeSecondPass(ref exInfo, startIdx); } // ------------------------------------------------ // // Call the handler and resume execution // // ------------------------------------------------ exInfo._idxCurClause = catchingTryRegionIdx; InternalCalls.RhpCallCatchFunclet( exceptionObj, pCatchHandler, frameIter.RegisterSet, ref exInfo); // currently, RhpCallCatchFunclet will resume after the catch Debug.Assert(false, "unreachable"); FallbackFailFast(RhFailFastReason.InternalError, null); }
protected void Page_Load(object sender, EventArgs e) { url = Request.Url.AbsoluteUri.Split('/').Last(); AuthHelper.LoginCheck(Session, Request, Response, Server); AuthHelper.TeacherOnlyPage(Session, Request, Response, Server); if (Request.QueryString["pt"] == null || Request.QueryString["id"] == null) { Response.Redirect("~/Default.aspx"); } PageType = Request.QueryString["pt"]; int id = int.Parse(Request.QueryString["id"]); if (PageType == "ex") { var courseExperiment = (CourseExperiment) new ExperimentServiceImpl().GetCourseExperimentById(id); var recoders = new CourseSelectionServiceImpl().GetRecordStudentByCourseId(courseExperiment.CourseId); ExInfo.Add("name", courseExperiment.Name); ExInfo.Add("deadline", courseExperiment.Deadline.ToString()); ExInfo.Add("purpose", courseExperiment.Purpose); ExInfo.Add("steps", courseExperiment.Steps); ExInfo.Add("references", courseExperiment.References); foreach (var i in recoders) { using (var context = new HaermsEntities()) { var queryans = context.Experiment.Where(ex => ex.CourseExperimentId == courseExperiment.CourseExperimentId && i.StudentId == ex.StudentId); var newnode = new Exnode(); if (queryans.FirstOrDefault() != null) { newnode.filename = queryans.FirstOrDefault()?.Name; newnode.exid = queryans.FirstOrDefault()?.ExperimentId.ToString(); newnode.mark = queryans.FirstOrDefault()?.Mark == null ? "0" : queryans.FirstOrDefault()?.Mark.ToString(); newnode.path = queryans.FirstOrDefault()?.Path; } else { newnode.filename = null; newnode.exid = null; } newnode.stuname = context.Student.Find(i.StudentId)?.Name; newnode.stunum = context.Student.Find(i.StudentId)?.StudentNumber; exlist.Add(newnode); } } } else if (PageType == "ho") { var courseHomework = new HomeworkServiceImpl().GetCourseHomeworkByCourseId(id); var recoders = new CourseSelectionServiceImpl().GetRecordStudentByCourseId(courseHomework.CourseId); HoInfo.Add("name", courseHomework.Name); HoInfo.Add("deadline", courseHomework.Deadline.ToString(CultureInfo.InvariantCulture)); HoInfo.Add("purpose", courseHomework.Content); foreach (var i in recoders) { using (var context = new HaermsEntities()) { var queryans = context.Homework.Where(ho => ho.CourseHomeworkId == id && ho.StudentId == i.StudentId); Honode newnode = new Honode(); if (queryans.FirstOrDefault() != null) { newnode.filename = queryans.FirstOrDefault()?.Name; newnode.hoid = queryans.FirstOrDefault()?.HomeworkId.ToString(); newnode.mark = queryans.FirstOrDefault()?.Mark == null ? "0" : queryans.FirstOrDefault()?.Mark.ToString(); newnode.path = queryans.FirstOrDefault()?.Path; } else { newnode.filename = null; newnode.hoid = null; } newnode.stuname = context.Student.Find(i.StudentId)?.Name; newnode.stunum = context.Student.Find(i.StudentId)?.StudentNumber; holist.Add(newnode); } } } }
void PrintExInfo(ExInfo exInfo) { Logger.Instance.DeIndent(); foreach (var ex in exInfo.tryStarts) Logger.Log(loggerEvent, "// try start: {0}", GetExceptionString(ex)); foreach (var ex in exInfo.tryEnds) Logger.Log(loggerEvent, "// try end: {0}", GetExceptionString(ex)); foreach (var ex in exInfo.filterStarts) Logger.Log(loggerEvent, "// filter start: {0}", GetExceptionString(ex)); foreach (var ex in exInfo.handlerStarts) Logger.Log(loggerEvent, "// handler start: {0}", GetExceptionString(ex)); foreach (var ex in exInfo.handlerEnds) Logger.Log(loggerEvent, "// handler end: {0}", GetExceptionString(ex)); Logger.Instance.Indent(); }
ExInfo GetExInfo(Instruction instruction) { if (instruction == null) return lastExInfo; ExInfo exInfo; if (!exInfos.TryGetValue(instruction, out exInfo)) exInfos[instruction] = exInfo = new ExInfo(); return exInfo; }
private static void InvokeSecondPass(ref ExInfo exInfo, uint idxStart, uint idxLimit) { EHEnum ehEnum; byte* pbMethodStartAddress; if (!InternalCalls.RhpEHEnumInitFromStackFrameIterator(ref exInfo._frameIter, &pbMethodStartAddress, &ehEnum)) return; byte* pbControlPC = exInfo._frameIter.ControlPC; uint codeOffset = (uint)(pbControlPC - pbMethodStartAddress); uint lastTryStart = 0, lastTryEnd = 0; // Search the clauses for one that contains the current offset. RhEHClause ehClause; for (uint curIdx = 0; InternalCalls.RhpEHEnumNext(&ehEnum, &ehClause) && curIdx < idxLimit; curIdx++) { // // Skip to the starting try region. This is used by collided unwinds and rethrows to pickup where // the previous dispatch left off. // if (idxStart != MaxTryRegionIdx) { if (curIdx <= idxStart) { lastTryStart = ehClause._tryStartOffset; lastTryEnd = ehClause._tryEndOffset; continue; } // Now, we continue skipping while the try region is identical to the one that invoked the // previous dispatch. if ((ehClause._tryStartOffset == lastTryStart) && (ehClause._tryEndOffset == lastTryEnd)) continue; // We are done skipping. This is required to handle empty finally block markers that are used // to separate runs of different try blocks with same native code offsets. idxStart = MaxTryRegionIdx; } RhEHClauseKind clauseKind = ehClause._clauseKind; if ((clauseKind != RhEHClauseKind.RH_EH_CLAUSE_FAULT) || !ehClause.ContainsCodeOffset(codeOffset)) { continue; } // Found a containing clause. Because of the order of the clauses, we know this is the // most containing. // N.B. -- We need to suppress GC "in-between" calls to finallys in this loop because we do // not have the correct next-execution point live on the stack and, therefore, may cause a GC // hole if we allow a GC between invocation of finally funclets (i.e. after one has returned // here to the dispatcher, but before the next one is invoked). Once they are running, it's // fine for them to trigger a GC, obviously. // // As a result, RhpCallFinallyFunclet will set this state in the runtime upon return from the // funclet, and we need to reset it if/when we fall out of the loop and we know that the // method will no longer get any more GC callbacks. byte* pFinallyHandler = ehClause._handlerAddress; exInfo._idxCurClause = curIdx; InternalCalls.RhpCallFinallyFunclet(pFinallyHandler, exInfo._frameIter.RegisterSet); exInfo._idxCurClause = MaxTryRegionIdx; } }
internal static unsafe void UnhandledExceptionFailFastViaClasslib( RhFailFastReason reason, object unhandledException, IntPtr classlibAddress, ref ExInfo exInfo) { IntPtr pFailFastFunction = (IntPtr)InternalCalls.RhpGetClasslibFunctionFromCodeAddress(classlibAddress, ClassLibFunctionId.FailFast); if (pFailFastFunction == IntPtr.Zero) { FailFastViaClasslib( reason, unhandledException, classlibAddress); } // 16-byte align the context. This is overkill on x86 and ARM, but simplifies things slightly. const int contextAlignment = 16; byte * pbBuffer = stackalloc byte[sizeof(OSCONTEXT) + contextAlignment]; void * pContext = PointerAlign(pbBuffer, contextAlignment); InternalCalls.RhpCopyContextFromExInfo(pContext, sizeof(OSCONTEXT), exInfo._pExContext); try { ((delegate * < RhFailFastReason, object, IntPtr, void *, void >)pFailFastFunction) (reason, unhandledException, exInfo._pExContext->IP, pContext); } catch when(true) { // disallow all exceptions leaking out of callbacks } // The classlib's function should never return and should not throw. If it does, then we fail our way... FallbackFailFast(reason, unhandledException); }
internal unsafe static void UnhandledExceptionFailFastViaClasslib( RhFailFastReason reason, Exception unhandledException, ref ExInfo exInfo) { IntPtr pFailFastFunction = (IntPtr)InternalCalls.RhpGetClasslibFunction(exInfo._pExContext->IP, ClassLibFunctionId.FailFast); if (pFailFastFunction == IntPtr.Zero) { FailFastViaClasslib( reason, unhandledException, exInfo._pExContext->IP); } // 16-byte align the context. This is overkill on x86 and ARM, but simplifies things slightly. const int contextAlignment = 16; byte* pbBuffer = stackalloc byte[sizeof(OSCONTEXT) + contextAlignment]; void* pContext = PointerAlign(pbBuffer, contextAlignment); // We 'normalized' the faulting IP of hardware faults to behave like return addresses. Undo this // normalization here so that we report the correct thing in the exception context record. if ((exInfo._kind & ExKind.KindMask) == ExKind.HardwareFault) { exInfo._pExContext->IP = (IntPtr)(((byte*)exInfo._pExContext->IP) - c_IPAdjustForHardwareFault); } InternalCalls.RhpCopyContextFromExInfo(pContext, sizeof(OSCONTEXT), exInfo._pExContext); try { CalliIntrinsics.CallVoid(pFailFastFunction, reason, unhandledException, (IntPtr)pContext); } catch { // Unfortunately, this catch turns into "catch (System.Object)", which will not catch // exceptions thrown from the class library because their objects do not derive from our // System.Object. // // @TODO: Use a filtered catch whose filter always returns 'true'. } // The classlib's funciton should never return and should not throw. If it does, then we fail our way... FailFast(reason, unhandledException); }
private static void InvokeSecondPass(ref ExInfo exInfo, uint idxStart) { InvokeSecondPass(ref exInfo, idxStart, MaxTryRegionIdx); }
public static void RhThrowHwEx(uint exceptionCode, ref ExInfo exInfo) { // trigger a GC (only if gcstress) to ensure we can stackwalk at this point GCStress.TriggerGC(); InternalCalls.RhpValidateExInfoStack(); IntPtr faultingCodeAddress = exInfo._pExContext->IP; ExceptionIDs exceptionId; switch (exceptionCode) { case (uint)HwExceptionCode.STATUS_REDHAWK_NULL_REFERENCE: exceptionId = ExceptionIDs.NullReference; break; case (uint)HwExceptionCode.STATUS_DATATYPE_MISALIGNMENT: exceptionId = ExceptionIDs.DataMisaligned; break; // N.B. -- AVs that have a read/write address lower than 64k are already transformed to // HwExceptionCode.REDHAWK_NULL_REFERENCE prior to calling this routine. case (uint)HwExceptionCode.STATUS_ACCESS_VIOLATION: exceptionId = ExceptionIDs.AccessViolation; break; case (uint)HwExceptionCode.STATUS_INTEGER_DIVIDE_BY_ZERO: exceptionId = ExceptionIDs.DivideByZero; break; case (uint)HwExceptionCode.STATUS_INTEGER_OVERFLOW: exceptionId = ExceptionIDs.Overflow; break; default: // We don't wrap SEH exceptions from foreign code like CLR does, so we believe that we // know the complete set of HW faults generated by managed code and do not need to handle // this case. FailFastViaClasslib(RhFailFastReason.InternalError, null, faultingCodeAddress); exceptionId = ExceptionIDs.NullReference; break; } Exception exceptionToThrow = GetClasslibException(exceptionId, faultingCodeAddress); exInfo.Init(exceptionToThrow); DispatchEx(ref exInfo._frameIter, ref exInfo, MaxTryRegionIdx); FallbackFailFast(RhFailFastReason.InternalError, null); }
internal static unsafe void UnhandledExceptionFailFastViaClasslib( RhFailFastReason reason, object unhandledException, IntPtr classlibAddress, ref ExInfo exInfo) { IntPtr pFailFastFunction = (IntPtr)InternalCalls.RhpGetClasslibFunction(classlibAddress, ClassLibFunctionId.FailFast); if (pFailFastFunction == IntPtr.Zero) { FailFastViaClasslib( reason, unhandledException, classlibAddress); } // 16-byte align the context. This is overkill on x86 and ARM, but simplifies things slightly. const int contextAlignment = 16; byte* pbBuffer = stackalloc byte[sizeof(OSCONTEXT) + contextAlignment]; void* pContext = PointerAlign(pbBuffer, contextAlignment); // We 'normalized' the faulting IP of hardware faults to behave like return addresses. Undo this // normalization here so that we report the correct thing in the exception context record. if ((exInfo._kind & ExKind.KindMask) == ExKind.HardwareFault) { exInfo._pExContext->IP = (IntPtr)(((byte*)exInfo._pExContext->IP) - c_IPAdjustForHardwareFault); } InternalCalls.RhpCopyContextFromExInfo(pContext, sizeof(OSCONTEXT), exInfo._pExContext); try { CalliIntrinsics.CallVoid(pFailFastFunction, reason, unhandledException, exInfo._pExContext->IP, (IntPtr)pContext); } catch { // disallow all exceptions leaking out of callbacks } // The classlib's funciton should never return and should not throw. If it does, then we fail our way... FallbackFailFast(reason, unhandledException); }
public void CaptureTable(MapEntry entry, IWin32Window owner) { var FirmwareManager = onlineManager.FirmwareManager; this.owner = owner; switch ((MapEntryType)entry.Type) { case MapEntryType.Entry2D: var entry2D = entry.Entry2D; exInfo = entry2D.Convert.ExInfo; table.Address = (int)entry2D.Addr; table.AxisX = FirmwareManager.GetAxis(entry2D); table.AxisY = null; var converter = Source2Value(entry2D); FillMinMax(table, entry2D.Const_type); table.Units = entry2D.Units; table.xStart = entry2D.xStart; table.xPoints = entry2D.xPoints; table.xEnd = entry2D.xEnd; table.xUnits = entry2D.xUnits; table.Init(entry2D.xPoints, 1, converter, Value2Source(entry2D.Convert, table.RawMin, table.RawMax), FirmwareManager.Buffer); table.FirstInit(); table.FillValues(); OpenOltHelper.FillMinMax(table, entry2D); break; case MapEntryType.Entry3D: var entry3D = entry.Entry3D; exInfo = entry3D.Convert.ExInfo; table.Address = (int)entry3D.Addr; table.AxisX = FirmwareManager.GetAxisX(entry3D); table.AxisY = FirmwareManager.GetAxisY(entry3D); var converter3D = Source2Value(entry3D); FillMinMax(table, entry3D.Const_type); table.Init(entry3D.xPoints, entry3D.zPoints, converter3D, Value2Source(entry3D.Convert, table.RawMin, table.RawMax), FirmwareManager.Buffer); table.FirstInit(); table.FillValues(); OpenOltHelper.FillMinMax(table, entry3D); break; default: throw new NotSupportedException(); } table.Name = entry.Name; table.Tag = entry; CapturedTable = table; rawBuffer = table.GetRawBuffer(); using (var progress = ProgressForm.ShowProgress(owner)) { onlineManager.OltProtocol.StopCapture(); onlineManager.OltProtocol.WriteRam(captureAddress, rawBuffer, progress); onlineManager.OltProtocol.StartCapture(exInfo.CaptureRamId); progress.Close(); } onlineManager.EnabledRamOnlineCorrection = CapturedTable.Address == FirmwareHelper.GbcAddr || CapturedTable.Address == FirmwareHelper.KGbcAddr || CapturedTable.Address == FirmwareHelper.KGbcJ7esDadAddr; DoCaptureTable(EventArgs.Empty); }
private static void InvokeSecondPass(ref ExInfo exInfo, uint idxStart, uint idxLimit) { EHEnum ehEnum; byte * pbMethodStartAddress; if (!InternalCalls.RhpEHEnumInitFromStackFrameIterator(ref exInfo._frameIter, &pbMethodStartAddress, &ehEnum)) { return; } byte *pbControlPC = exInfo._frameIter.ControlPC; uint codeOffset = (uint)(pbControlPC - pbMethodStartAddress); uint lastTryStart = 0, lastTryEnd = 0; // Search the clauses for one that contains the current offset. RhEHClause ehClause; for (uint curIdx = 0; InternalCalls.RhpEHEnumNext(&ehEnum, &ehClause) && curIdx < idxLimit; curIdx++) { // // Skip to the starting try region. This is used by collided unwinds and rethrows to pickup where // the previous dispatch left off. // if (idxStart != MaxTryRegionIdx) { if (curIdx <= idxStart) { lastTryStart = ehClause._tryStartOffset; lastTryEnd = ehClause._tryEndOffset; continue; } // Now, we continue skipping while the try region is identical to the one that invoked the // previous dispatch. if ((ehClause._tryStartOffset == lastTryStart) && (ehClause._tryEndOffset == lastTryEnd)) { continue; } } RhEHClauseKind clauseKind = ehClause._clauseKind; if ((clauseKind != RhEHClauseKind.RH_EH_CLAUSE_FAULT) || !ehClause.ContainsCodeOffset(codeOffset)) { continue; } // Found a containing clause. Because of the order of the clauses, we know this is the // most containing. // N.B. -- We need to suppress GC "in-between" calls to finallys in this loop because we do // not have the correct next-execution point live on the stack and, therefore, may cause a GC // hole if we allow a GC between invocation of finally funclets (i.e. after one has returned // here to the dispatcher, but before the next one is invoked). Once they are running, it's // fine for them to trigger a GC, obviously. // // As a result, RhpCallFinallyFunclet will set this state in the runtime upon return from the // funclet, and we need to reset it if/when we fall out of the loop and we know that the // method will no longer get any more GC callbacks. byte *pFinallyHandler = ehClause._handlerAddress; exInfo._idxCurClause = curIdx; InternalCalls.RhpCallFinallyFunclet(pFinallyHandler, exInfo._frameIter.RegisterSet); exInfo._idxCurClause = MaxTryRegionIdx; } }
private static void DispatchEx(ref StackFrameIterator frameIter, ref ExInfo exInfo, uint startIdx) { Debug.Assert(exInfo._passNumber == 1, "expected asm throw routine to set the pass"); object exceptionObj = exInfo.ThrownException; // ------------------------------------------------ // // First pass // // ------------------------------------------------ UIntPtr handlingFrameSP = MaxSP; byte* pCatchHandler = null; uint catchingTryRegionIdx = MaxTryRegionIdx; bool isFirstRethrowFrame = (startIdx != MaxTryRegionIdx); bool isFirstFrame = true; byte* prevControlPC = null; UIntPtr prevFramePtr = UIntPtr.Zero; bool unwoundReversePInvoke = false; bool isValid = frameIter.Init(exInfo._pExContext); Debug.Assert(isValid, "RhThrowEx called with an unexpected context"); DebuggerNotify.BeginFirstPass(exceptionObj, frameIter.ControlPC, frameIter.SP); for (; isValid; isValid = frameIter.Next(out startIdx, out unwoundReversePInvoke)) { // For GC stackwalking, we'll happily walk across native code blocks, but for EH dispatch, we // disallow dispatching exceptions across native code. if (unwoundReversePInvoke) break; prevControlPC = frameIter.ControlPC; DebugScanCallFrame(exInfo._passNumber, frameIter.ControlPC, frameIter.SP); // A debugger can subscribe to get callbacks at a specific frame of exception dispatch // exInfo._notifyDebuggerSP can be populated by the debugger from out of process // at any time. if (exInfo._notifyDebuggerSP == frameIter.SP) DebuggerNotify.FirstPassFrameEntered(exceptionObj, frameIter.ControlPC, frameIter.SP); UpdateStackTrace(exceptionObj, ref exInfo, ref isFirstRethrowFrame, ref prevFramePtr, ref isFirstFrame); byte* pHandler; if (FindFirstPassHandler(exceptionObj, startIdx, ref frameIter, out catchingTryRegionIdx, out pHandler)) { handlingFrameSP = frameIter.SP; pCatchHandler = pHandler; DebugVerifyHandlingFrame(handlingFrameSP); break; } } DebuggerNotify.EndFirstPass(exceptionObj, pCatchHandler, handlingFrameSP); if (pCatchHandler == null) { UnhandledExceptionFailFastViaClasslib( RhFailFastReason.PN_UnhandledException, exceptionObj, (IntPtr)prevControlPC, // IP of the last frame that did not handle the exception ref exInfo); } // We FailFast above if the exception goes unhandled. Therefore, we cannot run the second pass // without a catch handler. Debug.Assert(pCatchHandler != null, "We should have a handler if we're starting the second pass"); DebuggerNotify.BeginSecondPass(); // ------------------------------------------------ // // Second pass // // ------------------------------------------------ // Due to the stackwalker logic, we cannot tolerate triggering a GC from the dispatch code once we // are in the 2nd pass. This is because the stackwalker applies a particular unwind semantic to // 'collapse' funclets which gets confused when we walk out of the dispatch code and encounter the // 'main body' without first encountering the funclet. The thunks used to invoke 2nd-pass // funclets will always toggle this mode off before invoking them. InternalCalls.RhpSetThreadDoNotTriggerGC(); exInfo._passNumber = 2; startIdx = MaxTryRegionIdx; isValid = frameIter.Init(exInfo._pExContext); for (; isValid && ((byte*)frameIter.SP <= (byte*)handlingFrameSP); isValid = frameIter.Next(out startIdx)) { Debug.Assert(isValid, "second-pass EH unwind failed unexpectedly"); DebugScanCallFrame(exInfo._passNumber, frameIter.ControlPC, frameIter.SP); if (frameIter.SP == handlingFrameSP) { // invoke only a partial second-pass here... InvokeSecondPass(ref exInfo, startIdx, catchingTryRegionIdx); break; } InvokeSecondPass(ref exInfo, startIdx); } // ------------------------------------------------ // // Call the handler and resume execution // // ------------------------------------------------ exInfo._idxCurClause = catchingTryRegionIdx; InternalCalls.RhpCallCatchFunclet( exceptionObj, pCatchHandler, frameIter.RegisterSet, ref exInfo); // currently, RhpCallCatchFunclet will resume after the catch Debug.Assert(false, "unreachable"); FallbackFailFast(RhFailFastReason.InternalError, null); }
void printExInfo(ExInfo exInfo) { Log.deIndent(); foreach (var ex in exInfo.tryStarts) Log.log(logLevel, "// try start: {0}", getExceptionString(ex)); foreach (var ex in exInfo.tryEnds) Log.log(logLevel, "// try end: {0}", getExceptionString(ex)); foreach (var ex in exInfo.filterStarts) Log.log(logLevel, "// filter start: {0}", getExceptionString(ex)); foreach (var ex in exInfo.handlerStarts) Log.log(logLevel, "// handler start: {0}", getExceptionString(ex)); foreach (var ex in exInfo.handlerEnds) Log.log(logLevel, "// handler end: {0}", getExceptionString(ex)); Log.indent(); }