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
58 changes: 58 additions & 0 deletions docs/design/datacontracts/AuxiliarySymbols.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# Contract AuxiliarySymbols

This contract provides name resolution for helper functions whose executing code
resides at dynamically-determined addresses.

## APIs of contract

``` csharp
// Attempts to resolve a code address to a helper function name.
// Returns true if the address matches a known helper, with the name in symbolName.
// Returns false if the address does not match any known helper.
bool TryGetAuxiliarySymbolName(TargetPointer ip, out string symbolName);
```

## Version 1

Data descriptors used:
| Data Descriptor Name | Field | Meaning |
| --- | --- | --- |
| `AuxiliarySymbolInfo` | `Address` | Code pointer to the dynamically-located helper function |
| `AuxiliarySymbolInfo` | `Name` | Pointer to a null-terminated char string with the helper name |

Comment thread
rcj1 marked this conversation as resolved.
Global variables used:
| Global Name | Type | Purpose |
| --- | --- | --- |
| `AuxiliarySymbols` | TargetPointer | Pointer to an array of `AuxiliarySymbolInfo` entries |
| `AuxiliarySymbolCount` | TargetPointer | Pointer to the count of populated entries in the array |

Comment thread
rcj1 marked this conversation as resolved.
Contracts used: none

``` csharp
bool TryGetAuxiliarySymbolName(TargetPointer ip, out string? symbolName)
{
symbolName = null;

TargetCodePointer codePointer = CodePointerFromAddress(ip);

TargetPointer helperArray = target.ReadGlobalPointer("AuxiliarySymbols");
uint count = target.Read<uint>(target.ReadGlobalPointer("AuxiliarySymbolCount"));

uint entrySize = /* AuxiliarySymbolInfo size */;

for (uint i = 0; i < count; i++)
{
TargetPointer entryAddr = helperArray + (i * entrySize);
TargetCodePointer address = target.ReadCodePointer(entryAddr + /* AuxiliarySymbolInfo::Address offset */);
TargetPointer namePointer = target.ReadPointer(entryAddr + /* AuxiliarySymbolInfo::Name offset */);

if (address == codePointer && namePointer != TargetPointer.Null)
{
symbolName = target.ReadUtf8String(namePointer);
return true;
}
}

return false;
}
Comment thread
rcj1 marked this conversation as resolved.
```
48 changes: 6 additions & 42 deletions src/coreclr/debug/daccess/daccess.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5295,50 +5295,14 @@ ClrDataAccess::GetFullMethodName(
}

PCSTR
ClrDataAccess::GetJitHelperName(
IN TADDR address,
IN bool dynamicHelpersOnly /*=false*/
)
ClrDataAccess::GetJitHelperName(IN TADDR address)
{
const static PCSTR s_rgHelperNames[] = {
#define JITHELPER(code,fn,sig) #code,
#include <jithelpers.h>
};
static_assert(ARRAY_SIZE(s_rgHelperNames) == CORINFO_HELP_COUNT);

#ifdef TARGET_UNIX
if (!dynamicHelpersOnly)
#else
if (!dynamicHelpersOnly && g_runtimeLoadedBaseAddress <= address &&
address < g_runtimeLoadedBaseAddress + g_runtimeVirtualSize)
#endif // TARGET_UNIX
{
// Read the whole table from the target in one shot for better performance
VMHELPDEF * pTable = static_cast<VMHELPDEF *>(
PTR_READ(dac_cast<TADDR>(&hlpFuncTable), CORINFO_HELP_COUNT * sizeof(VMHELPDEF)));

for (int i = 0; i < CORINFO_HELP_COUNT; i++)
{
if (address == pTable[i].pfnHelper)
return s_rgHelperNames[i];
}
}

// Check if its a dynamically generated JIT helper
const static CorInfoHelpFunc s_rgDynamicHCallIds[] = {
#define DYNAMICJITHELPER(code, fn, binderId) code,
#define JITHELPER(code, fn, binderId)
#include <jithelpers.h>
};

// Read the whole table from the target in one shot for better performance
VMHELPDEF * pDynamicTable = static_cast<VMHELPDEF *>(
PTR_READ(dac_cast<TADDR>(&hlpDynamicFuncTable), DYNAMIC_CORINFO_HELP_COUNT * sizeof(VMHELPDEF)));
for (unsigned d = 0; d < DYNAMIC_CORINFO_HELP_COUNT; d++)
PCODE pCode = PINSTRToPCODE(address);
for (unsigned i = 0; i < g_auxiliarySymbolCount; i++)
{
if (address == pDynamicTable[d].pfnHelper)
if (pCode == hlpAuxiliarySymbolTable[i].pfnAuxiliarySymbol)
{
return s_rgHelperNames[s_rgDynamicHCallIds[d]];
return hlpAuxiliarySymbolTable[i].name;
}
}
Comment thread
rcj1 marked this conversation as resolved.

Expand Down Expand Up @@ -5565,7 +5529,7 @@ ClrDataAccess::RawGetMethodName(

// Do not waste time looking up name for static helper. Debugger can get the actual name from .pdb.
PCSTR pHelperName;
pHelperName = GetJitHelperName(TO_TADDR(address), true /* dynamicHelpersOnly */);
pHelperName = GetJitHelperName(TO_TADDR(address));
if (pHelperName != NULL)
{
if (displacement)
Expand Down
3 changes: 1 addition & 2 deletions src/coreclr/debug/daccess/dacimpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -1205,8 +1205,7 @@ class ClrDataAccess
Thread* FindClrThreadByTaskId(ULONG64 taskId);
HRESULT IsPossibleCodeAddress(IN TADDR address);

PCSTR GetJitHelperName(IN TADDR address,
IN bool dynamicHelpersOnly = false);
PCSTR GetJitHelperName(IN TADDR address);
HRESULT GetFullMethodName(IN MethodDesc* methodDesc,
IN ULONG32 symbolChars,
IN ULONG32* symbolLen,
Expand Down
2 changes: 2 additions & 0 deletions src/coreclr/inc/dacvars.h
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,8 @@ DEFINE_DACVAR(PTR_InterpreterCodeManager, ExecutionManager__m_pInterpreterCodeMa

DEFINE_DACVAR_NO_DUMP(VMHELPDEF *, dac__hlpFuncTable, ::hlpFuncTable)
DEFINE_DACVAR(VMHELPDEF *, dac__hlpDynamicFuncTable, ::hlpDynamicFuncTable)
DEFINE_DACVAR(VMAUXILIARYSYMBOLDEF *, dac__hlpAuxiliarySymbolTable, ::hlpAuxiliarySymbolTable)
DEFINE_DACVAR(DWORD, dac__g_auxiliarySymbolCount, ::g_auxiliarySymbolCount)

DEFINE_DACVAR(PTR_StubManager, StubManager__g_pFirstManager, StubManager::g_pFirstManager)
DEFINE_DACVAR(PTR_PrecodeStubManager, PrecodeStubManager__g_pManager, PrecodeStubManager::g_pManager)
Expand Down
13 changes: 11 additions & 2 deletions src/coreclr/vm/datadescriptor/datadescriptor.inc
Original file line number Diff line number Diff line change
Expand Up @@ -1240,6 +1240,12 @@ CDAC_TYPE_FIELD(WebcilSectionHeader, /*uint32*/, PointerToRawData, offsetof(Webc
CDAC_TYPE_END(WebcilSectionHeader)
#endif

CDAC_TYPE_BEGIN(AuxiliarySymbolInfo)
CDAC_TYPE_SIZE(sizeof(VMAUXILIARYSYMBOLDEF))
CDAC_TYPE_FIELD(AuxiliarySymbolInfo, /*pointer*/, Address, offsetof(VMAUXILIARYSYMBOLDEF, pfnAuxiliarySymbol))
CDAC_TYPE_FIELD(AuxiliarySymbolInfo, /*pointer*/, Name, offsetof(VMAUXILIARYSYMBOLDEF, name))
CDAC_TYPE_END(AuxiliarySymbolInfo)

CDAC_TYPES_END()

CDAC_GLOBALS_BEGIN()
Expand Down Expand Up @@ -1409,6 +1415,8 @@ CDAC_GLOBAL(SyncBlockHashCodeMask, uint32, MASK_HASHCODE)

CDAC_GLOBAL_POINTER(GCLowestAddress, &g_lowest_address)
CDAC_GLOBAL_POINTER(GCHighestAddress, &g_highest_address)
CDAC_GLOBAL_POINTER(AuxiliarySymbols, &::hlpAuxiliarySymbolTable)
CDAC_GLOBAL_POINTER(AuxiliarySymbolCount, &::g_auxiliarySymbolCount)
#if FEATURE_COMINTEROP
CDAC_GLOBAL(CCWNumInterfaces, uint32, cdac_data<ComCallWrapper>::NumInterfaces)
CDAC_GLOBAL(CCWThisMask, nuint, cdac_data<ComCallWrapper>::ThisMask)
Expand All @@ -1426,13 +1434,15 @@ CDAC_GLOBAL(RCWInterfaceCacheSize, uint32, INTERFACE_ENTRY_CACHE_SIZE)
// When adding a new subdescriptor, EnumMemDescriptors must be updated appropriately.
CDAC_GLOBAL_SUB_DESCRIPTOR(GC, &(g_gc_dac_vars.gc_descriptor))

CDAC_GLOBAL_CONTRACT(AuxiliarySymbols, 1)
#if FEATURE_COMINTEROP
CDAC_GLOBAL_CONTRACT(BuiltInCOM, 1)
#endif // FEATURE_COMINTEROP
CDAC_GLOBAL_CONTRACT(CodeVersions, 1)
#ifdef FEATURE_COMWRAPPERS
CDAC_GLOBAL_CONTRACT(ComWrappers, 1)
#endif // FEATURE_COMWRAPPERS
CDAC_GLOBAL_CONTRACT(ConditionalWeakTable, 1)
CDAC_GLOBAL_CONTRACT(DacStreams, 1)
CDAC_GLOBAL_CONTRACT(DebugInfo, 2)
CDAC_GLOBAL_CONTRACT(EcmaMetadata, 1)
Expand All @@ -1449,10 +1459,9 @@ CDAC_GLOBAL_CONTRACT(RuntimeInfo, 1)
CDAC_GLOBAL_CONTRACT(RuntimeTypeSystem, 1)
CDAC_GLOBAL_CONTRACT(SHash, 1)
CDAC_GLOBAL_CONTRACT(SignatureDecoder, 1)
CDAC_GLOBAL_CONTRACT(ConditionalWeakTable, 1)
CDAC_GLOBAL_CONTRACT(SyncBlock, 1)
CDAC_GLOBAL_CONTRACT(StackWalk, 1)
CDAC_GLOBAL_CONTRACT(StressLog, 2)
CDAC_GLOBAL_CONTRACT(SyncBlock, 1)
CDAC_GLOBAL_CONTRACT(Thread, 1)

CDAC_GLOBALS_END()
18 changes: 18 additions & 0 deletions src/coreclr/vm/jithelpers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2506,6 +2506,24 @@ void _SetJitHelperFunction(DynamicCorInfoHelpFunc ftnNum, void * pFunc)
hlpDynamicFuncTable[ftnNum].pfnHelper = (PCODE)pFunc;
}

VMAUXILIARYSYMBOLDEF hlpAuxiliarySymbolTable[MAX_AUXILIARY_SYMBOLS];
DWORD g_auxiliarySymbolCount = 0;

void SetAuxiliarySymbol(void* pFunc, const char* name)
{
CONTRACTL
{
NOTHROW;
GC_NOTRIGGER;
}
CONTRACTL_END;

_ASSERTE(g_auxiliarySymbolCount < MAX_AUXILIARY_SYMBOLS);
hlpAuxiliarySymbolTable[g_auxiliarySymbolCount].pfnAuxiliarySymbol = (PCODE)pFunc;
hlpAuxiliarySymbolTable[g_auxiliarySymbolCount].name = name;
g_auxiliarySymbolCount++;
Comment thread
rcj1 marked this conversation as resolved.
}

PCODE LoadDynamicJitHelper(DynamicCorInfoHelpFunc ftnNum)
{
STANDARD_VM_CONTRACT;
Expand Down
2 changes: 2 additions & 0 deletions src/coreclr/vm/jitinterface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,8 @@
// Hence, we add them here.
GARY_IMPL(VMHELPDEF, hlpFuncTable, CORINFO_HELP_COUNT);
GARY_IMPL(VMHELPDEF, hlpDynamicFuncTable, DYNAMIC_CORINFO_HELP_COUNT);
GARY_IMPL(VMAUXILIARYSYMBOLDEF, hlpAuxiliarySymbolTable, MAX_AUXILIARY_SYMBOLS);
GVAL_IMPL_INIT(DWORD, g_auxiliarySymbolCount, 0);

#else // DACCESS_COMPILE

Expand Down
13 changes: 13 additions & 0 deletions src/coreclr/vm/jitinterface.h
Original file line number Diff line number Diff line change
Expand Up @@ -1005,13 +1005,25 @@ struct VMHELPDEF
bool IsDynamicHelper(DynamicCorInfoHelpFunc* dynamicFtnNum) const;
};

struct VMAUXILIARYSYMBOLDEF
{
PCODE pfnAuxiliarySymbol;
PTR_CSTR name;
};

#define MAX_AUXILIARY_SYMBOLS 7

#if defined(DACCESS_COMPILE)

GARY_DECL(VMHELPDEF, hlpFuncTable, CORINFO_HELP_COUNT);
GARY_DECL(VMAUXILIARYSYMBOLDEF, hlpAuxiliarySymbolTable, MAX_AUXILIARY_SYMBOLS);
GVAL_DECL(DWORD, g_auxiliarySymbolCount);

#else

extern "C" const VMHELPDEF hlpFuncTable[CORINFO_HELP_COUNT];
extern "C" VMAUXILIARYSYMBOLDEF hlpAuxiliarySymbolTable[MAX_AUXILIARY_SYMBOLS];
extern "C" DWORD g_auxiliarySymbolCount;

#ifdef FEATURE_PORTABLE_ENTRYPOINTS
extern "C" PCODE hlpFuncEntryPoints[CORINFO_HELP_COUNT];
Expand All @@ -1027,6 +1039,7 @@ GARY_DECL(VMHELPDEF, hlpDynamicFuncTable, DYNAMIC_CORINFO_HELP_COUNT);

#define SetJitHelperFunction(ftnNum, pFunc) _SetJitHelperFunction(DYNAMIC_##ftnNum, (void*)(pFunc))
void _SetJitHelperFunction(DynamicCorInfoHelpFunc ftnNum, void * pFunc);
void SetAuxiliarySymbol(void* pFunc, const char* name);

PCODE LoadDynamicJitHelper(DynamicCorInfoHelpFunc ftnNum);
bool HasILBasedDynamicJitHelper(DynamicCorInfoHelpFunc ftnNum);
Expand Down
4 changes: 4 additions & 0 deletions src/coreclr/vm/threads.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1082,6 +1082,7 @@ void InitThreadManager()

#define X86_WRITE_BARRIER_REGISTER(reg) \
SetJitHelperFunction(CORINFO_HELP_ASSIGN_REF_##reg, GetWriteBarrierCodeLocation((void*)JIT_WriteBarrier##reg)); \
SetAuxiliarySymbol(GetWriteBarrierCodeLocation((void*)JIT_WriteBarrier##reg), "JIT_WriteBarrier" #reg); \
ETW::MethodLog::StubInitialized((ULONGLONG)GetWriteBarrierCodeLocation((void*)JIT_WriteBarrier##reg), W("@WriteBarrier" #reg));

ENUM_X86_WRITE_BARRIER_REGISTERS()
Expand All @@ -1092,6 +1093,7 @@ void InitThreadManager()
JIT_WriteBarrier_Loc = GetWriteBarrierCodeLocation((void*)JIT_WriteBarrier);
#endif // TARGET_X86
SetJitHelperFunction(CORINFO_HELP_ASSIGN_REF, GetWriteBarrierCodeLocation((void*)JIT_WriteBarrier));
SetAuxiliarySymbol(GetWriteBarrierCodeLocation((void*)JIT_WriteBarrier), "JIT_WriteBarrier");
ETW::MethodLog::StubInitialized((ULONGLONG)GetWriteBarrierCodeLocation((void*)JIT_WriteBarrier), W("@WriteBarrier"));

#if defined(TARGET_ARM64) || defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64)
Expand All @@ -1101,8 +1103,10 @@ void InitThreadManager()

#if defined(TARGET_ARM64) || defined(TARGET_ARM) || defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64)
SetJitHelperFunction(CORINFO_HELP_CHECKED_ASSIGN_REF, GetWriteBarrierCodeLocation((void*)JIT_CheckedWriteBarrier));
SetAuxiliarySymbol(GetWriteBarrierCodeLocation((void*)JIT_CheckedWriteBarrier), "JIT_CheckedWriteBarrier");
ETW::MethodLog::StubInitialized((ULONGLONG)GetWriteBarrierCodeLocation((void*)JIT_CheckedWriteBarrier), W("@CheckedWriteBarrier"));
SetJitHelperFunction(CORINFO_HELP_ASSIGN_BYREF, GetWriteBarrierCodeLocation((void*)JIT_ByRefWriteBarrier));
SetAuxiliarySymbol(GetWriteBarrierCodeLocation((void*)JIT_ByRefWriteBarrier), "JIT_ByRefWriteBarrier");
ETW::MethodLog::StubInitialized((ULONGLONG)GetWriteBarrierCodeLocation((void*)JIT_ByRefWriteBarrier), W("@ByRefWriteBarrier"));
#endif // TARGET_ARM64 || TARGET_ARM || TARGET_LOONGARCH64 || TARGET_RISCV64

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,10 @@ public abstract class ContractRegistry
/// Gets an instance of the ConditionalWeakTable contract for the target.
/// </summary>
public virtual IConditionalWeakTable ConditionalWeakTable => GetContract<IConditionalWeakTable>();
/// <summary>
/// Gets an instance of the AuxiliarySymbols contract for the target.
/// </summary>
public virtual IAuxiliarySymbols AuxiliarySymbols => GetContract<IAuxiliarySymbols>();

public abstract TContract GetContract<TContract>() where TContract : IContract;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Diagnostics.CodeAnalysis;

namespace Microsoft.Diagnostics.DataContractReader.Contracts;

public interface IAuxiliarySymbols : IContract
{
static string IContract.Name { get; } = nameof(AuxiliarySymbols);
bool TryGetAuxiliarySymbolName(TargetPointer ip, [NotNullWhen(true)] out string? symbolName) => throw new NotImplementedException();
}

public readonly struct AuxiliarySymbols : IAuxiliarySymbols
{
// Everything throws NotImplementedException
}
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ public enum DataType
InterfaceEntry,
ComInterfaceEntry,
InternalComInterfaceDispatch,

AuxiliarySymbolInfo,

/* GC Data Types */

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,9 @@ public static class Globals
public const string GCHeapFreeableSohSegment = nameof(GCHeapFreeableSohSegment);
public const string GCHeapFreeableUohSegment = nameof(GCHeapFreeableUohSegment);
public const string GCHeapFreeRegions = nameof(GCHeapFreeRegions);
public const string AuxiliarySymbols = nameof(AuxiliarySymbols);
public const string AuxiliarySymbolCount = nameof(AuxiliarySymbolCount);

}
public static class FieldNames
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

namespace Microsoft.Diagnostics.DataContractReader.Contracts;

public sealed class AuxiliarySymbolsFactory : IContractFactory<IAuxiliarySymbols>
{
IAuxiliarySymbols IContractFactory<IAuxiliarySymbols>.CreateContract(Target target, int version)
{
return version switch
{
1 => new AuxiliarySymbols_1(target),
_ => default(AuxiliarySymbols),
};
}
}
Loading
Loading