Skip to content

Commit

Permalink
Merge dotnet/main into feature/fcalls-cleanups
Browse files Browse the repository at this point in the history
  • Loading branch information
am11 committed Oct 24, 2024
2 parents 3203c73 + 3db28cd commit be3a9b5
Show file tree
Hide file tree
Showing 72 changed files with 2,216 additions and 340 deletions.
2 changes: 1 addition & 1 deletion .devcontainer/android/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
ARG VARIANT="8.0-jammy"
ARG VARIANT="8.0-noble"
FROM mcr.microsoft.com/devcontainers/dotnet:${VARIANT}

# Set up machine requirements to build the repo
Expand Down
2 changes: 1 addition & 1 deletion .devcontainer/android/devcontainer.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"build": {
"dockerfile": "Dockerfile",
"args": {
"VARIANT": "8.0-jammy"
"VARIANT": "8.0-noble"
}
},
// The container needs to run privileged in order to use Linux KVM to create Android emulators.
Expand Down
52 changes: 52 additions & 0 deletions docs/design/datacontracts/PlatformMetadata.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# Contract PlatformMetadata

This contract exposes properties that describe the target platform

## APIs of contract

```csharp
internal enum CodePointerFlags : byte
{
// Set if the target process is executing on arm32
HasArm32ThumbBit = 0x1,
// Set if arm64e pointer authentication is used in the target process
HasArm64PtrAuth = 0x2,
}
// Returns a pointer to a structure describing platform-specific precode stubs properties
TargetPointer GetPrecodeMachineDescriptor();

// Returns flags describing the behavior of code pointers
CodePointerFlags GetCodePointerFlags();
```

## Version 1

Data descriptors used:
| Data Descriptor Name | Field | Meaning |
| --- | --- | --- |
| PlatformMetadata | PrecodeMachineDescriptor | precode stub-related platform specific properties |
| PlatformMetadata | CodePointerFlags | fields describing the behavior of target code pointers |

Global variables used:
| Global Name | Type | Purpose |
| --- | --- | --- |
| PlatformMetadata | pointer | address of the `PlatformMetadata` data |

Contracts used:
| Contract Name |
| --- |
| *none* |

```csharp
TargetPointer GetPrecodeMachineDescriptor()
{
TargetPointer metadataAddress = _target.ReadGlobalPointer("PlatformMetadata");
return metadataAddress + /* PlatformMetadata::PrecodeMachineDescriptor */
}

CodePointerFlags GetCodePointerFlags()
{
TargetPointer metadataAddress = _target.ReadGlobalPointer("PlatformMetadata");
return (CodePointerFlags)_target.Read<byte>(metadataAddress + /*PlatformMetadata::CodePointerFlags*/);
}
```
213 changes: 213 additions & 0 deletions docs/design/datacontracts/PrecodeStubs.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,213 @@
# Contract PrecodeStubs

This contract provides support for examining [precode](../coreclr/botr/method-descriptor.md#precode): small fragments of code used to implement temporary entry points and an efficient wrapper for stubs.

## APIs of contract

```csharp
// Gets a pointer to the MethodDesc for a given stub entrypoint
TargetPointer GetMethodDescFromStubAddress(TargetCodePointer entryPoint);
```

## Version 1

Data descriptors used:
| Data Descriptor Name | Field | Meaning |
| --- | --- | --- |
| PrecodeMachineDescriptor | OffsetOfPrecodeType | See `ReadPrecodeType` |
| PrecodeMachineDescriptor | ShiftOfPrecodeType | See `ReadPrecodeType` |
| PrecodeMachineDescriptor | ReadWidthOfPrecodeType | See `ReadPrecodeType` |
| PrecodeMachineDescriptor | StubCodePageSize | Size of a precode code page (in bytes) |
| PrecodeMachineDescriptor | CodePointerToInstrPointerMask | mask to apply to code pointers to get an address (see arm32 note)
| PrecodeMachineDescriptor | StubPrecodeType | precode sort byte for stub precodes |
| PrecodeMachineDescriptor | HasPInvokeImportPrecode | 1 if platform supports PInvoke precode stubs |
| PrecodeMachineDescriptor | PInvokeImportPrecodeType| precode sort byte for PInvoke precode stubs, if supported |
| PrecodeMachineDescriptor | HasFixupPrecode | 1 if platform supports fixup precode stubs |
| PrecodeMachineDescriptor | FixupPrecodeType| precode sort byte for fixup precode stubs, if supported |
| StubPrecodeData | MethodDesc | pointer to the MethodDesc associated with this stub precode |
| StubPrecodeData | Type | precise sort of stub precode |
| FixupPrecodeData | MethodDesc | pointer to the MethodDesc associated with this fixup precode |

arm32 note: the `CodePointerToInstrPointerMask` is used to convert IP values that may include an arm Thumb bit (for example extracted from disassembling a call instruction or from a snapshot of the registers) into an address. On other architectures applying the mask is a no-op.


Global variables used:
| Global Name | Type | Purpose |
| --- | --- | --- |
| PrecodeMachineDescriptor | pointer | address of the `PrecodeMachineDescriptor` data |

Contracts used:
| Contract Name |
| --- |
| `PlatformMetadata` |

### Determining the precode type

An initial approximation of the precode type relies on a particular pattern at a known offset from the precode entrypoint.
The precode type is expected to be encoded as an immediate. On some platforms the value is spread over multiple instruction bytes and may need to be right-shifted.

```
private byte ReadPrecodeType(TargetPointer instrPointer)
{
if (MachineDescriptor.ReadWidthOfPrecodeType == 1)
{
byte precodeType = _target.Read<byte>(instrPointer + MachineDescriptor.OffsetOfPrecodeType);
return (byte)(precodeType >> MachineDescriptor.ShiftOfPrecodeType);
}
else if (MachineDescriptor.ReadWidthOfPrecodeType == 2)
{
ushort precodeType = _target.Read<ushort>(instrPointer + MachineDescriptor.OffsetOfPrecodeType);
return (byte)(precodeType >> MachineDescriptor.ShiftOfPrecodeType);
}
else
{
throw new InvalidOperationException($"Invalid precode type width {MachineDescriptor.ReadWidthOfPrecodeType}");
}
}
```

After the initial precode type is determined, for stub precodes a refined precode type is extracted from the stub precode data.

```csharp
private KnownPrecodeType? TryGetKnownPrecodeType(TargetPointer instrAddress)
{
// We get the precode type in two phases:
// 1. Read the precode type from the intruction address.
// 2. If it's "stub", look at the stub data and get the actual precode type - it could be stub,
// but it could also be a pinvoke precode
// precode.h Precode::GetType()
byte approxPrecodeType = ReadPrecodeType(instrAddress);
byte exactPrecodeType;
if (approxPrecodeType == MachineDescriptor.StubPrecodeType)
{
// get the actual type from the StubPrecodeData
Data.StubPrecodeData stubPrecodeData = GetStubPrecodeData(instrAddress);
exactPrecodeType = stubPrecodeData.Type;
}
else
{
exactPrecodeType = approxPrecodeType;
}

if (exactPrecodeType == MachineDescriptor.StubPrecodeType)
{
return KnownPrecodeType.Stub;
}
else if (MachineDescriptor.PInvokeImportPrecodeType is byte ndType && exactPrecodeType == ndType)
{
return KnownPrecodeType.PInvokeImport;
}
else if (MachineDescriptor.FixupPrecodeType is byte fixupType && exactPrecodeType == fixupType)
{
return KnownPrecodeType.Fixup;
}
else if (MachineDescriptor.ThisPointerRetBufPrecodeType is byte thisPtrRetBufType && exactPrecodeType == thisPtrRetBufType)
{
return KnownPrecodeType.ThisPtrRetBuf;
}
else
{
return null;
}
}
```

### `MethodDescFromStubAddress`

```csharp
internal enum KnownPrecodeType
{
Stub = 1,
PInvokeImport, // also known as NDirectImport in the runtime
Fixup,
ThisPtrRetBuf,
}

internal abstract class ValidPrecode
{
public TargetPointer InstrPointer { get; }
public KnownPrecodeType PrecodeType { get; }

protected ValidPrecode(TargetPointer instrPointer, KnownPrecodeType precodeType)
{
InstrPointer = instrPointer;
PrecodeType = precodeType;
}

internal abstract TargetPointer GetMethodDesc(Target target, Data.PrecodeMachineDescriptor precodeMachineDescriptor);

}

internal class StubPrecode : ValidPrecode
{
internal StubPrecode(TargetPointer instrPointer, KnownPrecodeType type = KnownPrecodeType.Stub) : base(instrPointer, type) { }

internal override TargetPointer GetMethodDesc(Target target, Data.PrecodeMachineDescriptor precodeMachineDescriptor)
{
TargetPointer stubPrecodeDataAddress = InstrPointer + precodeMachineDescriptor.StubCodePageSize;
return target.ReadPointer (stubPrecodeDataAddress + /* offset of StubPrecodeData.MethodDesc */ );
}
}

internal sealed class PInvokeImportPrecode : StubPrecode
{
internal PInvokeImportPrecode(TargetPointer instrPointer) : base(instrPointer, KnownPrecodeType.PInvokeImport) { }
}

internal sealed class FixupPrecode : ValidPrecode
{
internal FixupPrecode(TargetPointer instrPointer) : base(instrPointer, KnownPrecodeType.Fixup) { }
internal override TargetPointer GetMethodDesc(Target target, Data.PrecodeMachineDescriptor precodeMachineDescriptor)
{
TargetPointer fixupPrecodeDataAddress = InstrPointer + precodeMachineDescriptor.StubCodePageSize;
return target.ReadPointer (fixupPrecodeDataAddress + /* offset of FixupPrecodeData.MethodDesc */);
}
}

internal sealed class ThisPtrRetBufPrecode : ValidPrecode
{
internal ThisPtrRetBufPrecode(TargetPointer instrPointer) : base(instrPointer, KnownPrecodeType.ThisPtrRetBuf) { }

internal override TargetPointer GetMethodDesc(Target target, Data.PrecodeMachineDescriptor precodeMachineDescriptor)
{
throw new NotImplementedException(); // TODO(cdac)
}
}

internal TargetPointer CodePointerReadableInstrPointer(TargetCodePointer codePointer)
{
// Mask off the thumb bit, if we're on arm32, to get the actual instruction pointer
ulong instrPointer = (ulong)codePointer.AsTargetPointer & MachineDescriptor.CodePointerToInstrPointerMask.Value;
return new TargetPointer(instrPointer);
}


internal ValidPrecode GetPrecodeFromEntryPoint(TargetCodePointer entryPoint)
{
TargetPointer instrPointer = CodePointerReadableInstrPointer(entryPoint);
if (IsAlignedInstrPointer(instrPointer) && TryGetKnownPrecodeType(instrPointer) is KnownPrecodeType precodeType)
{
switch (precodeType)
{
case KnownPrecodeType.Stub:
return new StubPrecode(instrPointer);
case KnownPrecodeType.Fixup:
return new FixupPrecode(instrPointer);
case KnownPrecodeType.PInvokeImport:
return new PInvokeImportPrecode(instrPointer);
case KnownPrecodeType.ThisPtrRetBuf:
return new ThisPtrRetBufPrecode(instrPointer);
default:
break;
}
}
throw new InvalidOperationException($"Invalid precode type 0x{instrPointer:x16}");
}

TargetPointer IPrecodeStubs.GetMethodDescFromStubAddress(TargetCodePointer entryPoint)
{
ValidPrecode precode = GetPrecodeFromEntryPoint(entryPoint);

return precode.GetMethodDesc(_target, MachineDescriptor);
}
```
8 changes: 4 additions & 4 deletions eng/testing/BrowserVersions.props
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
<Project>
<PropertyGroup>
<linux_ChromeVersion>129.0.6668.58</linux_ChromeVersion>
<linux_ChromeRevision>1343869</linux_ChromeRevision>
<linux_ChromeBaseSnapshotUrl>https://storage.googleapis.com/chromium-browser-snapshots/Linux_x64/1343872</linux_ChromeBaseSnapshotUrl>
<linux_V8Version>12.9.202</linux_V8Version>
<linux_ChromeVersion>130.0.6723.58</linux_ChromeVersion>
<linux_ChromeRevision>1356013</linux_ChromeRevision>
<linux_ChromeBaseSnapshotUrl>https://storage.googleapis.com/chromium-browser-snapshots/Linux_x64/1356035</linux_ChromeBaseSnapshotUrl>
<linux_V8Version>13.0.245</linux_V8Version>
<win_ChromeVersion>130.0.6723.44</win_ChromeVersion>
<win_ChromeRevision>1356013</win_ChromeRevision>
<win_ChromeBaseSnapshotUrl>https://storage.googleapis.com/chromium-browser-snapshots/Win_x64/1356075</win_ChromeBaseSnapshotUrl>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3915,13 +3915,18 @@ private void CreateInstanceCheckThis()
}

MethodBase? invokeMethod;
object? state = null;
object? state;

try
{
invokeMethod = binder.BindToMethod(bindingAttr, cons, ref args, null, culture, null, out state);
}
catch (MissingMethodException) { invokeMethod = null; }
catch (MissingMethodException innerMME)
{
// Rethrows to rewrite a message to include the class name.
// Make sure the original exception is set as an inner exception.
throw new MissingMethodException(SR.Format(SR.MissingConstructor_Name, FullName), innerMME);
}

if (invokeMethod is null)
{
Expand Down
1 change: 1 addition & 0 deletions src/coreclr/debug/runtimeinfo/contractpointerdata.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include <stddef.h>
#include <stdint.h>

#include "cdacplatformmetadata.hpp"
#include "threads.h"
#include "vars.hpp"

Expand Down
2 changes: 2 additions & 0 deletions src/coreclr/debug/runtimeinfo/contracts.jsonc
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
"ExecutionManager": 1,
"Loader": 1,
"Object": 1,
"PlatformMetadata": 1,
"PrecodeStubs": 1,
"RuntimeTypeSystem": 1,
"Thread": 1
}
1 change: 1 addition & 0 deletions src/coreclr/debug/runtimeinfo/datadescriptor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include "static_assert.h"

#include <sospriv.h>
#include "cdacplatformmetadata.hpp"
#include "methodtable.h"
#include "threads.h"

Expand Down
37 changes: 37 additions & 0 deletions src/coreclr/debug/runtimeinfo/datadescriptor.h
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,42 @@ CDAC_TYPE_FIELD(MethodDescVersioningState, /*pointer*/, NativeCodeVersionNode, c
CDAC_TYPE_FIELD(MethodDescVersioningState, /*uint8*/, Flags, cdac_data<MethodDescVersioningState>::Flags)
CDAC_TYPE_END(MethodDescVersioningState)

CDAC_TYPE_BEGIN(PrecodeMachineDescriptor)
CDAC_TYPE_INDETERMINATE(PrecodeMachineDescriptor)
CDAC_TYPE_FIELD(PrecodeMachineDescriptor, /*uint8*/, ReadWidthOfPrecodeType, offsetof(PrecodeMachineDescriptor, ReadWidthOfPrecodeType))
CDAC_TYPE_FIELD(PrecodeMachineDescriptor, /*uint8*/, ShiftOfPrecodeType, offsetof(PrecodeMachineDescriptor, ShiftOfPrecodeType))
CDAC_TYPE_FIELD(PrecodeMachineDescriptor, /*uint8*/, OffsetOfPrecodeType, offsetof(PrecodeMachineDescriptor, OffsetOfPrecodeType))
CDAC_TYPE_FIELD(PrecodeMachineDescriptor, /*uint8*/, InvalidPrecodeType, offsetof(PrecodeMachineDescriptor, InvalidPrecodeType))
CDAC_TYPE_FIELD(PrecodeMachineDescriptor, /*uint8*/, StubPrecodeType, offsetof(PrecodeMachineDescriptor, StubPrecodeType))
#ifdef HAS_NDIRECT_IMPORT_PRECODE
CDAC_TYPE_FIELD(PrecodeMachineDescriptor, /*uint8*/, PInvokeImportPrecodeType, offsetof(PrecodeMachineDescriptor, PInvokeImportPrecodeType))
#endif
#ifdef HAS_FIXUP_PRECODE
CDAC_TYPE_FIELD(PrecodeMachineDescriptor, /*uint8*/, FixupPrecodeType, offsetof(PrecodeMachineDescriptor, FixupPrecodeType))
#endif
#ifdef HAS_THISPTR_RETBUF_PRECODE
CDAC_TYPE_FIELD(PrecodeMachineDescriptor, /*uint8*/, ThisPointerRetBufPrecodeType, offsetof(PrecodeMachineDescriptor, ThisPointerRetBufPrecodeType))
#endif
CDAC_TYPE_FIELD(PrecodeMachineDescriptor, /*uint32*/, StubCodePageSize, offsetof(PrecodeMachineDescriptor, StubCodePageSize))
CDAC_TYPE_END(PrecodeMachineDescriptor)

CDAC_TYPE_BEGIN(PlatformMetadata)
CDAC_TYPE_INDETERMINATE(PlatformMetadata)
CDAC_TYPE_FIELD(PlatformMetadata, /*PrecodeMachineDescriptor*/, PrecodeMachineDescriptor, offsetof(CDacPlatformMetadata, precode))
CDAC_TYPE_FIELD(PlatformMetadata, /*uint8*/, CodePointerFlags, offsetof(CDacPlatformMetadata, codePointerFlags))
CDAC_TYPE_END(PlatformMetadata)

CDAC_TYPE_BEGIN(StubPrecodeData)
CDAC_TYPE_INDETERMINATE(StubPrecodeData)
CDAC_TYPE_FIELD(StubPrecodeData, /*pointer*/, MethodDesc, offsetof(StubPrecodeData, MethodDesc))
CDAC_TYPE_FIELD(StubPrecodeData, /*uint8*/, Type, offsetof(StubPrecodeData, Type))
CDAC_TYPE_END(StubPrecodeData)

CDAC_TYPE_BEGIN(FixupPrecodeData)
CDAC_TYPE_INDETERMINATE(FixupPrecodeData)
CDAC_TYPE_FIELD(FixupPrecodeData, /*pointer*/, MethodDesc, offsetof(FixupPrecodeData, MethodDesc))
CDAC_TYPE_END(FixupPrecodeData)

CDAC_TYPE_BEGIN(RangeSectionMap)
CDAC_TYPE_INDETERMINATE(RangeSectionMap)
CDAC_TYPE_FIELD(RangeSectionMap, /*pointer*/, TopLevelData, cdac_data<RangeSectionMap>::TopLevelData)
Expand Down Expand Up @@ -444,6 +480,7 @@ CDAC_GLOBAL_POINTER(SyncTableEntries, &::g_pSyncTable)
CDAC_GLOBAL_POINTER(MiniMetaDataBuffAddress, &::g_MiniMetaDataBuffAddress)
CDAC_GLOBAL_POINTER(MiniMetaDataBuffMaxSize, &::g_MiniMetaDataBuffMaxSize)
CDAC_GLOBAL_POINTER(ExecutionManagerCodeRangeMapAddress, cdac_data<ExecutionManager>::CodeRangeMapAddress)
CDAC_GLOBAL_POINTER(PlatformMetadata, &::g_cdacPlatformMetadata)
CDAC_GLOBALS_END()

#undef CDAC_BASELINE
Expand Down
Loading

0 comments on commit be3a9b5

Please sign in to comment.