///////////////////////////////////////////////////////////////////////////////// private static UIntPtr GetNativeRegister( IntPtr thread, uint flags, int offset, int size ) { // // NOTE: Are we able to query the thread context (i.e. we know // what platform we are on and the appropriate constants // have been setup)? // if (!CanQueryThread) { if (Interlocked.Increment(ref CannotQueryThread) == 1) { TraceOps.DebugTrace( "GetNativeRegister: cannot query thread", typeof(NativeStack).Name, TracePriority.NativeError); } return(UIntPtr.Zero); } // // NOTE: We do not allow anybody to attempt to read outside what // we think the bounds of the CONTEXT structure are. // if ((offset < 0) || (offset > (CONTEXT_SIZE - IntPtr.Size))) { return(UIntPtr.Zero); } try { lock (syncRoot) /* TRANSACTIONAL */ { // // NOTE: Perform one-time allocation of the fixed-size // thread context buffer, on demand and schedule // to have it freed prior to process exit. // if (ThreadContextBuffer == UIntPtr.Zero) { // // NOTE: Schedule the fixed-size thread context // buffer to be freed either upon the // AppDomain being unloaded (if we are not // in the default AppDomain) or when the // process exits. This should gracefully // handle both embedding and stand-alone // scenarios. // AppDomain appDomain = AppDomainOps.GetCurrent(); if (appDomain != null) { if (!AppDomainOps.IsDefault(appDomain)) { appDomain.DomainUnload += NativeStack_Exited; } else { appDomain.ProcessExit += NativeStack_Exited; } } // // NOTE: Now that we are sure that we have // succeeded in scheduling the cleanup for // this buffer, allocate it. // // NOTE: For safety, we now allocate at least a // whole page for this buffer. // // ThreadContextBuffer = ConversionOps.ToUIntPtr( // Marshal.AllocCoTaskMem((int)CONTEXT_SIZE)); // ThreadContextBuffer = ConversionOps.ToUIntPtr( Marshal.AllocCoTaskMem((int)Math.Max( CONTEXT_SIZE, PlatformOps.GetPageSize()))); } // // NOTE: Make sure we were able to allocate the // thread context buffer. // if (ThreadContextBuffer == UIntPtr.Zero) { return(UIntPtr.Zero); } // // NOTE: Internally convert our buffer UIntPtr to // IntPtr, as required by Marshal class. // This is absolutely required because // otherwise we end up calling the generic // version of the WriteInt32 and ReadInt32 // methods (that take an object instead of // an IntPtr) and getting the wrong results. // IntPtr threadContext = ConversionOps.ToIntPtr( ThreadContextBuffer); // // NOTE: Write flags that tell GetThreadContext // which fields of the thread context buffer // we would like it to populate. For now, // we mainly want to support the control // registers (primarily for ESP and EBP). // Marshal.WriteInt32( threadContext, (int)CONTEXT_FLAGS_OFFSET, (int)flags); // // NOTE: Query the Win32 API to obtain the // requested thread context. In theory, // this could fail or throw an exception // at this point. In that case, we would // return zero from this function and the // stack checking code would assume that // native stack checking is unavailable // and should not be relied upon. // if (UnsafeNativeMethods.GetThreadContext( thread, threadContext)) { if (size == IntPtr.Size) { return(ConversionOps.ToUIntPtr( Marshal.ReadIntPtr(threadContext, offset))); } else { switch (size) { case sizeof(long): { return(ConversionOps.ToUIntPtr( Marshal.ReadInt64(threadContext, offset))); } case sizeof(int): { return(ConversionOps.ToUIntPtr( Marshal.ReadInt32(threadContext, offset))); } case sizeof(short): { return(ConversionOps.ToUIntPtr( Marshal.ReadInt16(threadContext, offset))); } case sizeof(byte): { return(ConversionOps.ToUIntPtr( Marshal.ReadByte(threadContext, offset))); } } } } } } catch (Exception e) { if (Interlocked.Increment(ref ContextException) == 1) { TraceOps.DebugTrace( e, typeof(NativeStack).Name, TracePriority.NativeError); } } return(UIntPtr.Zero); }
///////////////////////////////////////////////////////////////////////////////// public static UIntPtr GetNativeStackMargin() { return(new UIntPtr( (ulong)PlatformOps.GetPageSize() * (ulong)StackMarginPages)); }