Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions src/coreclr/gcdump/gcdumpnonx86.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,7 @@ size_t GCDump::DumpGCTable(PTR_CBYTE gcInfoBlock,
| DECODE_GENERICS_INST_CONTEXT
| DECODE_GC_LIFETIMES
| DECODE_PROLOG_LENGTH
| DECODE_RETURN_KIND
#if defined(TARGET_ARM) || defined(TARGET_ARM64) || defined(TARGET_RISCV64) || defined(TARGET_LOONGARCH64)
| DECODE_HAS_TAILCALLS
#endif
Expand Down Expand Up @@ -501,6 +502,12 @@ size_t GCDump::DumpGCTable(PTR_CBYTE gcInfoBlock,
gcPrintf("Size of parameter area: %x\n", hdrdecoder.GetSizeOfStackParameterArea());
#endif

if (hdrdecoder.Version() < 4)
{
ReturnKind returnKind = hdrdecoder.GetReturnKind();
gcPrintf("Return Kind: %s\n", ReturnKindToString(returnKind));
}

UINT32 cbEncodedMethodSize = hdrdecoder.GetCodeLength();
gcPrintf("Code size: %x\n", cbEncodedMethodSize);

Expand Down
16 changes: 16 additions & 0 deletions src/coreclr/inc/gcinfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
// ******************************************************************************
// WARNING!!!: These values are used by SOS in the diagnostics repo. Values should
// added or removed in a backwards and forwards compatible way.
// There are scenarios in diagnostics that support parsing of old GC Info formats.
// See: https://github.com/dotnet/diagnostics/blob/main/src/shared/inc/gcinfo.h
// ******************************************************************************

Expand Down Expand Up @@ -38,6 +39,17 @@ const unsigned this_OFFSET_FLAG = 0x2; // the offset is "this"

#define GCINFO_VERSION 4

#ifdef SOS_INCLUDE
extern bool IsRuntimeVersionAtLeast(DWORD major);
inline int GCInfoVersion()
{
// In SOS we only care about ability to parse/dump the GC Info.
// Since v2 and v3 had the same file format and v1 is no longer supported,
// we can assume that everything before net10.0 uses GCInfo v3.
return IsRuntimeVersionAtLeast(10) ? 4 : 3;
}
#endif

//-----------------------------------------------------------------------------
// GCInfoToken: A wrapper that contains the GcInfo data and version number.
//
Expand Down Expand Up @@ -67,7 +79,11 @@ struct GCInfoToken

static uint32_t ReadyToRunVersionToGcInfoVersion(uint32_t readyToRunMajorVersion, uint32_t readyToRunMinorVersion)
{
#ifdef SOS_INCLUDE
return GCInfoVersion();
#else
return GCINFO_VERSION;
#endif
}
};

Expand Down
31 changes: 30 additions & 1 deletion src/coreclr/inc/gcinfodecoder.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@
#ifndef _GC_INFO_DECODER_
#define _GC_INFO_DECODER_

#ifdef SOS_INCLUDE
#define DECODE_OLD_FORMATS
#endif

#define _max(a, b) (((a) > (b)) ? (a) : (b))
#define _min(a, b) (((a) < (b)) ? (a) : (b))

Expand Down Expand Up @@ -222,6 +226,7 @@ enum GcInfoDecoderFlags
DECODE_PROLOG_LENGTH = 0x400, // length of the prolog (used to avoid reporting generics context)
DECODE_EDIT_AND_CONTINUE = 0x800,
DECODE_REVERSE_PINVOKE_VAR = 0x1000,
DECODE_RETURN_KIND = 0x2000, // Unused starting with v4 format
#if defined(TARGET_ARM) || defined(TARGET_ARM64) || defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64)
DECODE_HAS_TAILCALLS = 0x4000,
#endif // TARGET_ARM || TARGET_ARM64 || TARGET_LOONGARCH64
Expand All @@ -247,7 +252,6 @@ enum GcInfoHeaderFlags
GC_INFO_HAS_EDIT_AND_CONTINUE_INFO = 0x100,
GC_INFO_REVERSE_PINVOKE_FRAME = 0x200,

GC_INFO_FLAGS_BIT_SIZE_VERSION_1 = 9,
GC_INFO_FLAGS_BIT_SIZE = 10,
};

Expand Down Expand Up @@ -584,6 +588,7 @@ class TGcInfoDecoder
#if defined(TARGET_ARM) || defined(TARGET_ARM64) || defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64)
bool HasTailCalls();
#endif // TARGET_ARM || TARGET_ARM64 || TARGET_LOONGARCH64 || defined(TARGET_RISCV64)
ReturnKind GetReturnKind();
UINT32 GetCodeLength();
UINT32 GetStackBaseRegister();
UINT32 GetSizeOfEditAndContinuePreservedArea();
Expand All @@ -596,6 +601,10 @@ class TGcInfoDecoder
UINT32 GetSizeOfStackParameterArea();
#endif // FIXED_STACK_PARAMETER_SCRATCH_AREA

inline UINT32 Version()
{
return m_Version;
}

private:
BitStreamReader m_Reader;
Expand All @@ -616,6 +625,8 @@ class TGcInfoDecoder
#ifdef TARGET_ARM64
UINT32 m_SizeOfEditAndContinueFixedStackFrame;
#endif
// Unused starting with v4 format
ReturnKind m_ReturnKind;
#ifdef PARTIALLY_INTERRUPTIBLE_GC_SUPPORTED
UINT32 m_NumSafePoints;
UINT32 m_SafePointIndex;
Expand All @@ -634,6 +645,24 @@ class TGcInfoDecoder
#endif
UINT32 m_Version;

inline UINT32 NormalizeCodeOffset(UINT32 offset)
{
#ifdef DECODE_OLD_FORMATS
if (Version() < 4)
return offset;
#endif
return GcInfoEncoding::NORMALIZE_CODE_OFFSET(offset);
}

inline UINT32 DenormalizeCodeOffset(UINT32 offset)
{
#ifdef DECODE_OLD_FORMATS
if (Version() < 4)
return offset;
#endif
return GcInfoEncoding::DENORMALIZE_CODE_OFFSET(offset);
}

bool PredecodeFatHeader(int remainingFlags);

static bool SetIsInterruptibleCB (UINT32 startOffset, UINT32 stopOffset, void * hCallback);
Expand Down
14 changes: 13 additions & 1 deletion src/coreclr/inc/gcinfotypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
#define __GCINFOTYPES_H__

// HACK: debugreturn.h breaks constexpr
#ifdef debug_instrumented_return
#if defined(debug_instrumented_return) || defined(_DEBUGRETURN_H_)
#undef return
#endif // debug_instrumented_return

Expand Down Expand Up @@ -643,6 +643,8 @@ struct AMD64GcInfoEncoding {
static const int SECURITY_OBJECT_STACK_SLOT_ENCBASE = 6;
static const int GS_COOKIE_STACK_SLOT_ENCBASE = 6;
static const int CODE_LENGTH_ENCBASE = 8;
static const int SIZE_OF_RETURN_KIND_IN_SLIM_HEADER = 2;
static const int SIZE_OF_RETURN_KIND_IN_FAT_HEADER = 4;
static const int STACK_BASE_REGISTER_ENCBASE = 3;
static const int SIZE_OF_STACK_AREA_ENCBASE = 3;
static const int SIZE_OF_EDIT_AND_CONTINUE_PRESERVED_AREA_ENCBASE = 4;
Expand Down Expand Up @@ -698,6 +700,8 @@ struct ARM32GcInfoEncoding {
static const int SECURITY_OBJECT_STACK_SLOT_ENCBASE = 5;
static const int GS_COOKIE_STACK_SLOT_ENCBASE = 5;
static const int CODE_LENGTH_ENCBASE = 7;
static const int SIZE_OF_RETURN_KIND_IN_SLIM_HEADER = 2;
static const int SIZE_OF_RETURN_KIND_IN_FAT_HEADER = 2;
static const int STACK_BASE_REGISTER_ENCBASE = 1;
static const int SIZE_OF_STACK_AREA_ENCBASE = 3;
static const int SIZE_OF_EDIT_AND_CONTINUE_PRESERVED_AREA_ENCBASE = 3;
Expand Down Expand Up @@ -754,6 +758,8 @@ struct ARM64GcInfoEncoding {
static const int SECURITY_OBJECT_STACK_SLOT_ENCBASE = 6;
static const int GS_COOKIE_STACK_SLOT_ENCBASE = 6;
static const int CODE_LENGTH_ENCBASE = 8;
static const int SIZE_OF_RETURN_KIND_IN_SLIM_HEADER = 2;
static const int SIZE_OF_RETURN_KIND_IN_FAT_HEADER = 4;
// FP encoded as 0, SP as 2.
static const int STACK_BASE_REGISTER_ENCBASE = 2;
static const int SIZE_OF_STACK_AREA_ENCBASE = 3;
Expand Down Expand Up @@ -811,6 +817,8 @@ struct LoongArch64GcInfoEncoding {
static const int SECURITY_OBJECT_STACK_SLOT_ENCBASE = 6;
static const int GS_COOKIE_STACK_SLOT_ENCBASE = 6;
static const int CODE_LENGTH_ENCBASE = 8;
static const int SIZE_OF_RETURN_KIND_IN_SLIM_HEADER = 2;
static const int SIZE_OF_RETURN_KIND_IN_FAT_HEADER = 4;
// FP/SP encoded as 0 or 1.
static const int STACK_BASE_REGISTER_ENCBASE = 2;
static const int SIZE_OF_STACK_AREA_ENCBASE = 3;
Expand Down Expand Up @@ -867,6 +875,8 @@ struct RISCV64GcInfoEncoding {
static const int SECURITY_OBJECT_STACK_SLOT_ENCBASE = 6;
static const int GS_COOKIE_STACK_SLOT_ENCBASE = 6;
static const int CODE_LENGTH_ENCBASE = 8;
static const int SIZE_OF_RETURN_KIND_IN_SLIM_HEADER = 2;
static const int SIZE_OF_RETURN_KIND_IN_FAT_HEADER = 4;
static const int STACK_BASE_REGISTER_ENCBASE = 2;
// FP encoded as 0, SP as 1
static const int SIZE_OF_STACK_AREA_ENCBASE = 3;
Expand Down Expand Up @@ -927,6 +937,8 @@ struct X86GcInfoEncoding {
static const int SECURITY_OBJECT_STACK_SLOT_ENCBASE = 6;
static const int GS_COOKIE_STACK_SLOT_ENCBASE = 6;
static const int CODE_LENGTH_ENCBASE = 6;
static const int SIZE_OF_RETURN_KIND_IN_SLIM_HEADER = 2;
static const int SIZE_OF_RETURN_KIND_IN_FAT_HEADER = 2;
static const int STACK_BASE_REGISTER_ENCBASE = 3;
static const int SIZE_OF_STACK_AREA_ENCBASE = 6;
static const int SIZE_OF_EDIT_AND_CONTINUE_PRESERVED_AREA_ENCBASE = 3;
Expand Down
81 changes: 64 additions & 17 deletions src/coreclr/vm/gcinfodecoder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -88,10 +88,15 @@ template <typename GcInfoEncoding> bool TGcInfoDecoder<GcInfoEncoding>::SetIsInt
// returns true if we decoded all that was asked;
template <typename GcInfoEncoding> bool TGcInfoDecoder<GcInfoEncoding>::PredecodeFatHeader(int remainingFlags)
{
int numFlagBits = (m_Version == 1) ? GC_INFO_FLAGS_BIT_SIZE_VERSION_1 : GC_INFO_FLAGS_BIT_SIZE;
m_headerFlags = (GcInfoHeaderFlags)m_Reader.Read(numFlagBits);
m_headerFlags = (GcInfoHeaderFlags)m_Reader.Read(GC_INFO_FLAGS_BIT_SIZE);

remainingFlags &= ~DECODE_VARARG;
#ifdef DECODE_OLD_FORMATS
if (Version() < 4)
{
m_ReturnKind = (ReturnKind)((UINT32)m_Reader.Read(GcInfoEncoding::SIZE_OF_RETURN_KIND_IN_FAT_HEADER));
}
#endif
remainingFlags &= ~(DECODE_RETURN_KIND | DECODE_VARARG);
#if defined(TARGET_ARM) || defined(TARGET_ARM64) || defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64)
remainingFlags &= ~DECODE_HAS_TAILCALLS;
#endif
Expand All @@ -113,21 +118,21 @@ template <typename GcInfoEncoding> bool TGcInfoDecoder<GcInfoEncoding>::Predecod
{
// Note that normalization as a code offset can be different than
// normalization as code length
UINT32 normCodeLength = GcInfoEncoding::NORMALIZE_CODE_OFFSET(m_CodeLength);
UINT32 normCodeLength = NormalizeCodeOffset(m_CodeLength);

// Decode prolog/epilog information
UINT32 normPrologSize = (UINT32)m_Reader.DecodeVarLengthUnsigned(GcInfoEncoding::NORM_PROLOG_SIZE_ENCBASE) + 1;
UINT32 normEpilogSize = (UINT32)m_Reader.DecodeVarLengthUnsigned(GcInfoEncoding::NORM_EPILOG_SIZE_ENCBASE);

m_ValidRangeStart = GcInfoEncoding::DENORMALIZE_CODE_OFFSET(normPrologSize);
m_ValidRangeEnd = GcInfoEncoding::DENORMALIZE_CODE_OFFSET(normCodeLength - normEpilogSize);
m_ValidRangeStart = DenormalizeCodeOffset(normPrologSize);
m_ValidRangeEnd = DenormalizeCodeOffset(normCodeLength - normEpilogSize);
_ASSERTE(m_ValidRangeStart < m_ValidRangeEnd);
}
else if ((m_headerFlags & GC_INFO_HAS_GENERICS_INST_CONTEXT_MASK) != GC_INFO_HAS_GENERICS_INST_CONTEXT_NONE)
{
// Decode prolog information
UINT32 normPrologSize = (UINT32)m_Reader.DecodeVarLengthUnsigned(GcInfoEncoding::NORM_PROLOG_SIZE_ENCBASE) + 1;
m_ValidRangeStart = GcInfoEncoding::DENORMALIZE_CODE_OFFSET(normPrologSize);
m_ValidRangeStart = DenormalizeCodeOffset(normPrologSize);
// satisfy asserts that assume m_GSCookieValidRangeStart != 0 ==> m_GSCookieValidRangeStart < m_GSCookieValidRangeEnd
m_ValidRangeEnd = m_ValidRangeStart + 1;
}
Expand Down Expand Up @@ -258,6 +263,7 @@ TGcInfoDecoder<GcInfoEncoding>::TGcInfoDecoder(
: m_Reader(dac_cast<PTR_CBYTE>(gcInfoToken.Info))
, m_InstructionOffset(breakOffset)
, m_IsInterruptible(false)
, m_ReturnKind(RT_Illegal)
#ifdef _DEBUG
, m_Flags( flags )
, m_GcInfoAddress(dac_cast<PTR_CBYTE>(gcInfoToken.Info))
Expand Down Expand Up @@ -297,7 +303,13 @@ TGcInfoDecoder<GcInfoEncoding>::TGcInfoDecoder(
m_StackBaseRegister = NO_STACK_BASE_REGISTER;
}

remainingFlags &= ~DECODE_VARARG;
#ifdef DECODE_OLD_FORMATS
if (Version() < 4)
{
m_ReturnKind = (ReturnKind)((UINT32)m_Reader.Read(GcInfoEncoding::SIZE_OF_RETURN_KIND_IN_SLIM_HEADER));
}
#endif
remainingFlags &= ~(DECODE_RETURN_KIND | DECODE_VARARG);
#if defined(TARGET_ARM) || defined(TARGET_ARM64) || defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64)
remainingFlags &= ~DECODE_HAS_TAILCALLS;
#endif
Expand Down Expand Up @@ -365,14 +377,25 @@ TGcInfoDecoder<GcInfoEncoding>::TGcInfoDecoder(
{
if(m_NumSafePoints)
{
#ifdef DECODE_OLD_FORMATS
if (Version() < 4)
{
// Safepoints are encoded with a -1 adjustment
// DECODE_GC_LIFETIMES adjusts the offset accordingly, but DECODE_INTERRUPTIBILITY does not
// adjust here
UINT32 offset = flags & DECODE_INTERRUPTIBILITY ? m_InstructionOffset - 1 : m_InstructionOffset;
m_SafePointIndex = FindSafePoint(offset);
}
#else
m_SafePointIndex = FindSafePoint(m_InstructionOffset);
#endif
}
}
else if(flags & DECODE_FOR_RANGES_CALLBACK)
{
// Note that normalization as a code offset can be different than
// normalization as code length
UINT32 normCodeLength = GcInfoEncoding::NORMALIZE_CODE_OFFSET(m_CodeLength);
UINT32 normCodeLength = NormalizeCodeOffset(m_CodeLength);

UINT32 numBitsPerOffset = CeilOfLog2(normCodeLength);
m_Reader.Skip(m_NumSafePoints * numBitsPerOffset);
Expand Down Expand Up @@ -441,6 +464,14 @@ template <typename GcInfoEncoding> bool TGcInfoDecoder<GcInfoEncoding>::IsSafePo
if(m_NumSafePoints == 0)
return false;

#ifdef DECODE_OLD_FORMATS
if (Version() < 4)
{
// Safepoints are encoded with a -1 adjustment, adjust before searching.
codeOffset--;
}
#endif

size_t savedPos = m_Reader.GetCurrentPos();
UINT32 safePointIndex = FindSafePoint(codeOffset);
m_Reader.SetCurrentPos(savedPos);
Expand All @@ -462,7 +493,7 @@ UINT32 TGcInfoDecoder<GcInfoEncoding>::NarrowSafePointSearch(size_t savedPos, UI
INT32 low = 0;
INT32 high = (INT32)m_NumSafePoints;

const UINT32 numBitsPerOffset = CeilOfLog2(GcInfoEncoding::NORMALIZE_CODE_OFFSET(m_CodeLength));
const UINT32 numBitsPerOffset = CeilOfLog2(NormalizeCodeOffset(m_CodeLength));
while (high - low > MAX_LINEAR_SEARCH)
{
const INT32 mid = (low + high) / 2;
Expand All @@ -486,9 +517,9 @@ template <typename GcInfoEncoding> UINT32 TGcInfoDecoder<GcInfoEncoding>::FindSa
_ASSERTE(m_NumSafePoints > 0);
UINT32 result = m_NumSafePoints;
const size_t savedPos = m_Reader.GetCurrentPos();
const UINT32 numBitsPerOffset = CeilOfLog2(GcInfoEncoding::NORMALIZE_CODE_OFFSET(m_CodeLength));
const UINT32 numBitsPerOffset = CeilOfLog2(NormalizeCodeOffset(m_CodeLength));

const UINT32 normBreakOffset = GcInfoEncoding::NORMALIZE_CODE_OFFSET(breakOffset);
const UINT32 normBreakOffset = NormalizeCodeOffset(breakOffset);
UINT32 linearSearchStart = 0;
UINT32 linearSearchEnd = m_NumSafePoints;
if (linearSearchEnd - linearSearchStart > MAX_LINEAR_SEARCH)
Expand Down Expand Up @@ -523,12 +554,21 @@ template <typename GcInfoEncoding> void TGcInfoDecoder<GcInfoEncoding>::Enumerat
if(m_NumSafePoints == 0)
return;

const UINT32 numBitsPerOffset = CeilOfLog2(GcInfoEncoding::NORMALIZE_CODE_OFFSET(m_CodeLength));
const UINT32 numBitsPerOffset = CeilOfLog2(NormalizeCodeOffset(m_CodeLength));

for(UINT32 i = 0; i < m_NumSafePoints; i++)
{
UINT32 normOffset = (UINT32)m_Reader.Read(numBitsPerOffset);
UINT32 offset = GcInfoEncoding::DENORMALIZE_CODE_OFFSET(normOffset);
UINT32 offset = DenormalizeCodeOffset(normOffset);

#ifdef DECODE_OLD_FORMATS
if (Version() < 4)
{
// Safepoints are encoded with a -1 adjustment, adjust before reporting
offset++;
}
#endif

pCallback(this, offset, hCallback);
}
}
Expand All @@ -551,8 +591,8 @@ template <typename GcInfoEncoding> void TGcInfoDecoder<GcInfoEncoding>::Enumerat
UINT32 rangeStartOffsetNormalized = lastInterruptibleRangeStopOffsetNormalized + normStartDelta;
UINT32 rangeStopOffsetNormalized = rangeStartOffsetNormalized + normStopDelta;

UINT32 rangeStartOffset = GcInfoEncoding::DENORMALIZE_CODE_OFFSET(rangeStartOffsetNormalized);
UINT32 rangeStopOffset = GcInfoEncoding::DENORMALIZE_CODE_OFFSET(rangeStopOffsetNormalized);
UINT32 rangeStartOffset = DenormalizeCodeOffset(rangeStartOffsetNormalized);
UINT32 rangeStopOffset = DenormalizeCodeOffset(rangeStopOffsetNormalized);

bool fStop = pCallback(rangeStartOffset, rangeStopOffset, hCallback);
if (fStop)
Expand Down Expand Up @@ -635,6 +675,13 @@ template <typename GcInfoEncoding> UINT32 TGcInfoDecoder<GcInfoEncoding>::GetCod
return m_CodeLength;
}

template <typename GcInfoEncoding> ReturnKind TGcInfoDecoder<GcInfoEncoding>::GetReturnKind()
{
// SUPPORTS_DAC;
_ASSERTE(m_Flags & DECODE_RETURN_KIND);
return m_ReturnKind;
}

template <typename GcInfoEncoding> UINT32 TGcInfoDecoder<GcInfoEncoding>::GetStackBaseRegister()
{
return m_StackBaseRegister;
Expand Down Expand Up @@ -698,7 +745,7 @@ template <typename GcInfoEncoding> bool TGcInfoDecoder<GcInfoEncoding>::Enumerat

GcSlotDecoder<GcInfoEncoding> slotDecoder;

UINT32 normBreakOffset = GcInfoEncoding::NORMALIZE_CODE_OFFSET(m_InstructionOffset);
UINT32 normBreakOffset = NormalizeCodeOffset(m_InstructionOffset);

// Normalized break offset
// Relative to interruptible ranges #if PARTIALLY_INTERRUPTIBLE_GC_SUPPORTED
Expand Down
Loading