summaryrefslogtreecommitdiff
path: root/src/vm/i386/gmscpu.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/vm/i386/gmscpu.h')
-rw-r--r--src/vm/i386/gmscpu.h140
1 files changed, 140 insertions, 0 deletions
diff --git a/src/vm/i386/gmscpu.h b/src/vm/i386/gmscpu.h
new file mode 100644
index 0000000000..0aecefac21
--- /dev/null
+++ b/src/vm/i386/gmscpu.h
@@ -0,0 +1,140 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/**************************************************************/
+/* gmscpu.h */
+/**************************************************************/
+/* HelperFrame is defines 'GET_STATE(machState)' macro, which
+ figures out what the state of the machine will be when the
+ current method returns. It then stores the state in the
+ JIT_machState structure. */
+
+/**************************************************************/
+
+#ifndef __gmsx86_h__
+#define __gmsx86_h__
+
+#define __gmsx86_h__
+
+#ifdef _DEBUG
+class HelperMethodFrame;
+struct MachState;
+EXTERN_C MachState* STDCALL HelperMethodFrameConfirmState(HelperMethodFrame* frame, void* esiVal, void* ediVal, void* ebxVal, void* ebpVal);
+#endif
+
+ // A MachState indicates the register state of the processor at some point in time (usually
+ // just before or after a call is made). It can be made one of two ways. Either explicitly
+ // (when you for some reason know the values of all the registers), or implicitly using the
+ // GET_STATE macros.
+
+typedef DPTR(struct MachState) PTR_MachState;
+struct MachState {
+
+ MachState()
+ {
+ LIMITED_METHOD_DAC_CONTRACT;
+ INDEBUG(memset(this, 0xCC, sizeof(MachState));)
+ }
+
+ bool isValid() { LIMITED_METHOD_DAC_CONTRACT; _ASSERTE(dac_cast<TADDR>(_pRetAddr) != INVALID_POINTER_CC); return(_pRetAddr != 0); }
+ TADDR* pEdi() { LIMITED_METHOD_DAC_CONTRACT; _ASSERTE(dac_cast<TADDR>(_pEdi) != INVALID_POINTER_CC); return(_pEdi); }
+ TADDR* pEsi() { LIMITED_METHOD_DAC_CONTRACT; _ASSERTE(dac_cast<TADDR>(_pEsi) != INVALID_POINTER_CC); return(_pEsi); }
+ TADDR* pEbx() { LIMITED_METHOD_DAC_CONTRACT; _ASSERTE(dac_cast<TADDR>(_pEbx) != INVALID_POINTER_CC); return(_pEbx); }
+ TADDR* pEbp() { LIMITED_METHOD_DAC_CONTRACT; _ASSERTE(dac_cast<TADDR>(_pEbp) != INVALID_POINTER_CC); return(_pEbp); }
+ TADDR esp() { LIMITED_METHOD_DAC_CONTRACT; _ASSERTE(isValid()); return(_esp); }
+ PTR_TADDR pRetAddr() { LIMITED_METHOD_DAC_CONTRACT; _ASSERTE(isValid()); return(_pRetAddr); }
+ TADDR GetRetAddr() { LIMITED_METHOD_DAC_CONTRACT; _ASSERTE(isValid()); return *_pRetAddr; }
+#ifndef DACCESS_COMPILE
+ void SetRetAddr(TADDR* addr) { LIMITED_METHOD_CONTRACT; _ASSERTE(isValid()); _pRetAddr = addr; }
+#endif
+
+ friend class HelperMethodFrame;
+ friend class CheckAsmOffsets;
+ friend struct LazyMachState;
+#ifdef _DEBUG
+ friend MachState* STDCALL HelperMethodFrameConfirmState(HelperMethodFrame* frame, void* esiVal, void* ediVal, void* ebxVal, void* ebpVal);
+#endif
+
+
+protected:
+ // Note the fields are layed out to make generating a
+ // MachState structure from assembly code very easy
+
+ // The state of all the callee saved registers.
+ // If the register has been spill to the stack p<REG>
+ // points at this location, otherwise it points
+ // at the field <REG> field itself
+ PTR_TADDR _pEdi;
+ TADDR _edi;
+ PTR_TADDR _pEsi;
+ TADDR _esi;
+ PTR_TADDR _pEbx;
+ TADDR _ebx;
+ PTR_TADDR _pEbp;
+ TADDR _ebp;
+
+ TADDR _esp; // stack pointer after the function returns
+ PTR_TADDR _pRetAddr; // The address of the stored IP address (points into the stack)
+};
+
+/********************************************************************/
+/* This allows you to defer the computation of the Machine state
+ until later. Note that we don't reuse slots, because we want
+ this to be threadsafe without locks */
+
+struct LazyMachState;
+typedef DPTR(LazyMachState) PTR_LazyMachState;
+struct LazyMachState : public MachState {
+ // compute the machine state of the processor as it will exist just
+ // after the return after at most'funCallDepth' number of functions.
+ // if 'testFtn' is non-NULL, the return address is tested at each
+ // return instruction encountered. If this test returns non-NULL,
+ // then stack walking stops (thus you can walk up to the point that the
+ // return address matches some criteria
+
+ // Normally this is called with funCallDepth=1 and testFtn = 0 so that
+ // it returns the state of the processor after the function that called 'captureState()'
+ void setLazyStateFromUnwind(MachState* copy);
+ static void unwindLazyState(LazyMachState* baseState,
+ MachState* lazyState,
+ DWORD threadId,
+ int funCallDepth = 1,
+ HostCallPreference hostCallPreference = AllowHostCalls);
+
+ friend class HelperMethodFrame;
+ friend class CheckAsmOffsets;
+private:
+ TADDR captureEbp; // Ebp at the time of capture
+ TADDR captureEsp; // Esp at the time of capture
+ TADDR captureEip; // Eip at the time of capture
+};
+
+inline void LazyMachState::setLazyStateFromUnwind(MachState* copy)
+{
+ // _pRetAddr has to be the last thing updated when we make the copy (because its
+ // is the the _pRetAddr becoming non-zero that flips this from invalid to valid.
+ // we assert that it is the last field in the struct.
+ static_assert_no_msg(offsetof(MachState, _pRetAddr) + sizeof(_pRetAddr) == sizeof(MachState));
+
+ memcpy(this, copy, offsetof(MachState, _pRetAddr));
+
+ // this has to be last
+ VolatileStore((TADDR*)&_pRetAddr, dac_cast<TADDR>(copy->_pRetAddr));
+}
+
+// Do the initial capture of the machine state. This is meant to be
+// as light weight as possible, as we may never need the state that
+// we capture. Thus to complete the process you need to call
+// 'getMachState()', which finishes the process
+EXTERN_C int __fastcall LazyMachStateCaptureState(struct LazyMachState *pState);
+
+// CAPTURE_STATE captures just enough register state so that the state of the
+// processor can be deterined just after the the routine that has CAPTURE_STATE in
+// it returns.
+
+// Note that the return is never taken, is is there for epilog walking
+#define CAPTURE_STATE(machState, ret) \
+ if (LazyMachStateCaptureState(machState)) ret
+
+#endif