summaryrefslogtreecommitdiff
path: root/src/inc/dbggcinfodecoder.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/inc/dbggcinfodecoder.h')
-rw-r--r--src/inc/dbggcinfodecoder.h344
1 files changed, 344 insertions, 0 deletions
diff --git a/src/inc/dbggcinfodecoder.h b/src/inc/dbggcinfodecoder.h
new file mode 100644
index 0000000000..f618ca336f
--- /dev/null
+++ b/src/inc/dbggcinfodecoder.h
@@ -0,0 +1,344 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+/*****************************************************************
+ *
+ * GC Information Decoding API
+ *
+ * This is an older well-tested implementation
+ * now used to verify the real encoding
+ * Define VERIFY_GCINFO to enable the verification
+ *
+ *****************************************************************/
+
+#ifdef VERIFY_GCINFO
+
+#ifndef _DBG_GC_INFO_DECODER_
+#define _DBG_GC_INFO_DECODER_
+
+#include "daccess.h"
+
+#ifndef GCINFODECODER_NO_EE
+
+#include "eetwain.h"
+
+#else // GCINFODECODER_NO_EE
+
+#if !defined(_NTAMD64_)
+#include "clrnt.h"
+#endif
+
+// Misc. VM types:
+
+class Object;
+typedef Object *OBJECTREF;
+typedef SIZE_T TADDR;
+
+// Stuff from gc.h:
+
+#ifndef __GC_H
+
+#define GC_CALL_INTERIOR 0x1
+#define GC_CALL_PINNED 0x2
+
+#endif // !__GC_H
+
+
+// Stuff from check.h:
+
+#ifndef UNREACHABLE
+#define UNREACHABLE() __assume(0)
+#endif
+
+// Stuff from eetwain.h:
+
+#ifndef _EETWAIN_H
+
+typedef void (*GCEnumCallback)(
+ LPVOID hCallback, // callback data
+ OBJECTREF* pObject, // address of obect-reference we are reporting
+ DWORD flags // is this a pinned and/or interior pointer
+);
+
+
+#if defined(_WIN64) || defined(_TARGET_ARM_)
+#define USE_GC_INFO_DECODER
+#endif
+
+#include "regdisp.h"
+
+#endif // !_EETWAIN_H
+
+#endif // GCINFODECODER_NO_EE
+
+#include "gcinfotypes.h"
+
+
+namespace DbgGcInfo {
+
+struct GcSlotDesc
+{
+ union
+ {
+ UINT32 RegisterNumber;
+ GcStackSlot Stack;
+ } Slot;
+ GcSlotFlags Flags;
+};
+
+class BitStreamReader
+{
+public:
+ BitStreamReader( const BYTE* pBuffer )
+ {
+ _ASSERTE( pBuffer != NULL );
+ m_pBuffer = (PTR_BYTE)(TADDR)pBuffer;
+ m_BitsRead = 0;
+ }
+
+ //
+ // bit 0 is the least significative bit
+ // count can be negative so that bits are written in most-significative to least-significative order
+ //
+ size_t Read( int numBits )
+ {
+ size_t result = 0;
+ int curBitsRead = 0;
+
+ while( curBitsRead < numBits )
+ {
+ int currByte = m_BitsRead /8;
+ int currBitInCurrentByte = m_BitsRead % 8;
+ int bitsLeftInCurrentByte = 8 - currBitInCurrentByte;
+ _ASSERTE( bitsLeftInCurrentByte > 0 );
+
+ int bitsToReadInCurrentByte = min( numBits - curBitsRead, bitsLeftInCurrentByte );
+
+ size_t data = m_pBuffer[ currByte ];
+ data >>= currBitInCurrentByte;
+ data &= (1<<bitsToReadInCurrentByte) -1;
+
+ data <<= curBitsRead;
+ result |= data;
+
+ curBitsRead += bitsToReadInCurrentByte;
+ m_BitsRead += bitsToReadInCurrentByte;
+ }
+
+ return result;
+ }
+
+ // Returns the number of bits read so far
+ size_t GetCurrentPos()
+ {
+ return m_BitsRead;
+ }
+
+ void SetCurrentPos( size_t pos )
+ {
+ m_BitsRead = pos;
+ }
+
+ // Can use negative values
+ void Skip( SSIZE_T numBitsToSkip )
+ {
+ m_BitsRead += numBitsToSkip;
+ _ASSERTE( m_BitsRead >= 0 );
+ }
+
+ //--------------------------------------------------------------------------
+ // Decode variable length numbers
+ // See the corresponding methods on BitStreamWriter for more information on the format
+ //--------------------------------------------------------------------------
+
+ inline size_t DecodeVarLengthUnsigned( int base )
+ {
+ _ASSERTE((base > 0) && (base < (int)sizeof(size_t)*8));
+ size_t numEncodings = 1 << base;
+ size_t result = 0;
+ for(int shift=0; ; shift+=base)
+ {
+ _ASSERTE(shift+base <= (int)sizeof(size_t)*8);
+
+ size_t currentChunk = Read(base+1);
+ result |= (currentChunk & (numEncodings-1)) << shift;
+ if(!(currentChunk & numEncodings))
+ {
+ // Extension bit is not set, we're done.
+ return result;
+ }
+ }
+ }
+
+ inline SSIZE_T DecodeVarLengthSigned( int base )
+ {
+ _ASSERTE((base > 0) && (base < (int)sizeof(SSIZE_T)*8));
+ size_t numEncodings = 1 << base;
+ SSIZE_T result = 0;
+ for(int shift=0; ; shift+=base)
+ {
+ _ASSERTE(shift+base <= (int)sizeof(SSIZE_T)*8);
+
+ size_t currentChunk = Read(base+1);
+ result |= (currentChunk & (numEncodings-1)) << shift;
+ if(!(currentChunk & numEncodings))
+ {
+ // Extension bit is not set, sign-extend and we're done.
+ int sbits = sizeof(SSIZE_T)*8 - (shift+base);
+ result <<= sbits;
+ result >>= sbits; // This provides the sign extension
+ return result;
+ }
+ }
+ }
+
+private:
+ PTR_BYTE m_pBuffer;
+ size_t m_BitsRead;
+};
+
+
+class GcInfoDecoder
+{
+public:
+
+ // If you are not insterested in interruptibility or gc lifetime information, pass 0 as instructionOffset
+ GcInfoDecoder(
+ const BYTE* gcInfoAddr,
+ GcInfoDecoderFlags flags,
+ UINT32 instructionOffset = 0
+ );
+
+
+ //------------------------------------------------------------------------
+ // Interruptibility
+ //------------------------------------------------------------------------
+
+ bool IsInterruptible();
+
+ // Returns true to stop enumerating.
+ typedef bool EnumerateInterruptibleRangesCallback (UINT32 startOffset, UINT32 stopOffset, LPVOID hCallback);
+
+ void EnumerateInterruptibleRanges (
+ EnumerateInterruptibleRangesCallback *pCallback,
+ LPVOID hCallback);
+
+ //------------------------------------------------------------------------
+ // GC lifetime information
+ //------------------------------------------------------------------------
+
+ bool EnumerateLiveSlots(
+ PREGDISPLAY pRD,
+ bool reportScratchSlots,
+ unsigned flags,
+ GCEnumCallback pCallBack,
+ LPVOID hCallBack
+ );
+
+ void VerifyLiveRegister(
+ UINT32 regNum,
+ GcSlotFlags flags
+ );
+
+
+ void VerifyLiveStackSlot(
+ int spOffset,
+ GcStackSlotBase spBase,
+ GcSlotFlags flags
+ );
+
+ void DoFinalVerification();
+
+ //------------------------------------------------------------------------
+ // Miscellaneous method information
+ //------------------------------------------------------------------------
+
+ INT32 GetSecurityObjectStackSlot();
+ INT32 GetPSPSymStackSlot();
+ INT32 GetGenericsInstContextStackSlot();
+ bool GetIsVarArg();
+ UINT32 GetCodeLength();
+ UINT32 GetStackBaseRegister();
+ UINT32 GetSizeOfEditAndContinuePreservedArea();
+
+#ifdef FIXED_STACK_PARAMETER_SCRATCH_AREA
+ UINT32 GetSizeOfStackParameterArea();
+#endif // FIXED_STACK_PARAMETER_SCRATCH_AREA
+
+private:
+ BitStreamReader m_Reader;
+ UINT32 m_InstructionOffset;
+
+ // Pre-decoded information
+ bool m_IsInterruptible;
+ bool m_IsVarArg;
+ INT32 m_SecurityObjectStackSlot;
+ INT32 m_PSPSymStackSlot;
+ INT32 m_GenericsInstContextStackSlot;
+ UINT32 m_CodeLength;
+ UINT32 m_StackBaseRegister;
+ UINT32 m_SizeOfEditAndContinuePreservedArea;
+ UINT32 m_NumInterruptibleRanges;
+
+#ifdef FIXED_STACK_PARAMETER_SCRATCH_AREA
+ UINT32 m_SizeOfStackOutgoingAndScratchArea;
+#endif // FIXED_STACK_PARAMETER_SCRATCH_AREA
+
+#ifdef _DEBUG
+ GcInfoDecoderFlags m_Flags;
+#endif
+
+ GcSlotDesc* m_pLiveRegisters;
+ GcSlotDesc* m_pLiveStackSlots;
+ int m_NumLiveRegisters;
+ int m_NumLiveStackSlots;
+
+ CQuickBytes qbSlots1;
+ CQuickBytes qbSlots2;
+
+ static bool SetIsInterruptibleCB (UINT32 startOffset, UINT32 stopOffset, LPVOID hCallback);
+
+ OBJECTREF* GetRegisterSlot(
+ int regNum,
+ PREGDISPLAY pRD
+ );
+
+ OBJECTREF* GetStackSlot(
+ INT32 spOffset,
+ GcStackSlotBase spBase,
+ PREGDISPLAY pRD
+ );
+
+ bool IsScratchRegister(int regNum, PREGDISPLAY pRD);
+ bool IsScratchStackSlot(INT32 spOffset, GcStackSlotBase spBase, PREGDISPLAY pRD);
+
+ void ReportRegisterToGC(
+ int regNum,
+ BOOL isInterior,
+ BOOL isPinned,
+ PREGDISPLAY pRD,
+ unsigned flags,
+ GCEnumCallback pCallBack,
+ LPVOID hCallBack
+ );
+
+ void ReportStackSlotToGC(
+ INT32 spOffset,
+ GcStackSlotBase spBase,
+ BOOL isInterior,
+ BOOL isPinned,
+ PREGDISPLAY pRD,
+ unsigned flags,
+ GCEnumCallback pCallBack,
+ LPVOID hCallBack
+ );
+
+
+};
+
+}
+
+#endif // _DBG_GC_INFO_DECODER_
+#endif // VERIFY_GCINFO
+