Skip to content

Commit dfc7b4d

Browse files
elinor-fungmichaelgsharp
authored andcommitted
[cdac] Read contract descriptor from target (dotnet#101208)
- Get `DotNetRuntimeContractDescriptor` address from the target - Read contract descriptor to determine endianness and pointer size - Parse JSON descriptor and store contracts
1 parent b311fd1 commit dfc7b4d

10 files changed

+241
-46
lines changed

src/coreclr/debug/daccess/cdac.cpp

+8-12
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,12 @@ namespace
2828

2929
int ReadFromTargetCallback(uint64_t addr, uint8_t* dest, uint32_t count, void* context)
3030
{
31-
CDAC* cdac = reinterpret_cast<CDAC*>(context);
32-
return cdac->ReadFromTarget(addr, dest, count);
31+
ICorDebugDataTarget* target = reinterpret_cast<ICorDebugDataTarget*>(context);
32+
HRESULT hr = ReadFromDataTarget(target, addr, dest, count);
33+
if (FAILED(hr))
34+
return hr;
35+
36+
return S_OK;
3337
}
3438
}
3539

@@ -52,11 +56,12 @@ CDAC::CDAC(HMODULE module, uint64_t descriptorAddr, ICorDebugDataTarget* target)
5256
return;
5357
}
5458

59+
m_target->AddRef();
5560
decltype(&cdac_reader_init) init = reinterpret_cast<decltype(&cdac_reader_init)>(::GetProcAddress(m_module, "cdac_reader_init"));
5661
decltype(&cdac_reader_get_sos_interface) getSosInterface = reinterpret_cast<decltype(&cdac_reader_get_sos_interface)>(::GetProcAddress(m_module, "cdac_reader_get_sos_interface"));
5762
_ASSERTE(init != nullptr && getSosInterface != nullptr);
5863

59-
init(descriptorAddr, &ReadFromTargetCallback, this, &m_cdac_handle);
64+
init(descriptorAddr, &ReadFromTargetCallback, m_target, &m_cdac_handle);
6065
getSosInterface(m_cdac_handle, &m_sos);
6166
}
6267

@@ -77,12 +82,3 @@ IUnknown* CDAC::SosInterface()
7782
{
7883
return m_sos;
7984
}
80-
81-
int CDAC::ReadFromTarget(uint64_t addr, uint8_t* dest, uint32_t count)
82-
{
83-
HRESULT hr = ReadFromDataTarget(m_target, addr, dest, count);
84-
if (FAILED(hr))
85-
return hr;
86-
87-
return S_OK;
88-
}

src/coreclr/debug/daccess/cdac.h

+3-4
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ class CDAC final
2121
CDAC(CDAC&& other)
2222
: m_module{ other.m_module }
2323
, m_cdac_handle{ other.m_cdac_handle }
24-
, m_target{ other.m_target }
24+
, m_target{ other.m_target.Extract() }
2525
, m_sos{ other.m_sos.Extract() }
2626
{
2727
other.m_module = NULL;
@@ -34,7 +34,7 @@ class CDAC final
3434
{
3535
m_module = other.m_module;
3636
m_cdac_handle = other.m_cdac_handle;
37-
m_target = other.m_target;
37+
m_target = other.m_target.Extract();
3838
m_sos = other.m_sos.Extract();
3939

4040
other.m_module = NULL;
@@ -54,15 +54,14 @@ class CDAC final
5454

5555
// This does not AddRef the returned interface
5656
IUnknown* SosInterface();
57-
int ReadFromTarget(uint64_t addr, uint8_t* dest, uint32_t count);
5857

5958
private:
6059
CDAC(HMODULE module, uint64_t descriptorAddr, ICorDebugDataTarget* target);
6160

6261
private:
6362
HMODULE m_module;
6463
intptr_t m_cdac_handle;
65-
ICorDebugDataTarget* m_target;
64+
NonVMComHolder<ICorDebugDataTarget> m_target;
6665
NonVMComHolder<IUnknown> m_sos;
6766
};
6867

src/coreclr/debug/daccess/daccess.cpp

+7-3
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@
3030
#include <dactablerva.h>
3131
#else
3232
extern "C" bool TryGetSymbol(ICorDebugDataTarget* dataTarget, uint64_t baseAddress, const char* symbolName, uint64_t* symbolAddress);
33+
// cDAC depends on symbol lookup to find the contract descriptor
34+
#define CAN_USE_CDAC
3335
#endif
3436

3537
#include "dwbucketmanager.hpp"
@@ -5493,15 +5495,16 @@ ClrDataAccess::Initialize(void)
54935495
IfFailRet(GetDacGlobalValues());
54945496
IfFailRet(DacGetHostVtPtrs());
54955497

5498+
// TODO: [cdac] TryGetSymbol is only implemented for Linux, OSX, and Windows.
5499+
#ifdef CAN_USE_CDAC
54965500
CLRConfigNoCache enable = CLRConfigNoCache::Get("ENABLE_CDAC");
54975501
if (enable.IsSet())
54985502
{
54995503
DWORD val;
55005504
if (enable.TryAsInteger(10, val) && val == 1)
55015505
{
5502-
// TODO: [cdac] Get contract descriptor from exported symbol
55035506
uint64_t contractDescriptorAddr = 0;
5504-
//if (TryGetSymbol(m_pTarget, m_globalBase, "DotNetRuntimeContractDescriptor", &contractDescriptorAddr))
5507+
if (TryGetSymbol(m_pTarget, m_globalBase, "DotNetRuntimeContractDescriptor", &contractDescriptorAddr))
55055508
{
55065509
m_cdac = CDAC::Create(contractDescriptorAddr, m_pTarget);
55075510
if (m_cdac.IsValid())
@@ -5514,6 +5517,7 @@ ClrDataAccess::Initialize(void)
55145517
}
55155518
}
55165519
}
5520+
#endif
55175521

55185522
//
55195523
// DAC is now setup and ready to use
@@ -6946,7 +6950,7 @@ GetDacTableAddress(ICorDebugDataTarget* dataTarget, ULONG64 baseAddress, PULONG6
69466950
return E_INVALIDARG;
69476951
}
69486952
#endif
6949-
// On MacOS, FreeBSD or NetBSD use the RVA include file
6953+
// On FreeBSD, NetBSD, or SunOS use the RVA include file
69506954
*dacTableAddress = baseAddress + DAC_TABLE_RVA;
69516955
#else
69526956
// Otherwise, try to get the dac table address via the export symbol

src/native/managed/cdacreader/src/ContractDescriptorParser.cs

+18-3
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
using System;
55
using System.Collections.Generic;
6+
using System.Diagnostics.CodeAnalysis;
67
using System.Diagnostics.Contracts;
78
using System.Text.Json;
89
using System.Text.Json.Serialization;
@@ -23,13 +24,15 @@ public partial class ContractDescriptorParser
2324
/// <summary>
2425
/// Parses the "compact" representation of a contract descriptor.
2526
/// </summary>
27+
// Workaround for https://github.com/dotnet/runtime/issues/101205
28+
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(Root))]
2629
public static ContractDescriptor? ParseCompact(ReadOnlySpan<byte> json)
2730
{
2831
return JsonSerializer.Deserialize(json, ContractDescriptorContext.Default.ContractDescriptor);
2932
}
3033

3134
[JsonSerializable(typeof(ContractDescriptor))]
32-
[JsonSerializable(typeof(int))]
35+
[JsonSerializable(typeof(int?))]
3336
[JsonSerializable(typeof(string))]
3437
[JsonSerializable(typeof(Dictionary<string, int>))]
3538
[JsonSerializable(typeof(Dictionary<string, TypeDescriptor>))]
@@ -38,11 +41,17 @@ public partial class ContractDescriptorParser
3841
[JsonSerializable(typeof(TypeDescriptor))]
3942
[JsonSerializable(typeof(FieldDescriptor))]
4043
[JsonSerializable(typeof(GlobalDescriptor))]
44+
[JsonSerializable(typeof(Dictionary<string, JsonElement>))]
4145
[JsonSourceGenerationOptions(AllowTrailingCommas = true,
4246
DictionaryKeyPolicy = JsonKnownNamingPolicy.Unspecified, // contracts, types and globals are case sensitive
4347
PropertyNamingPolicy = JsonKnownNamingPolicy.CamelCase,
4448
NumberHandling = JsonNumberHandling.AllowReadingFromString,
45-
ReadCommentHandling = JsonCommentHandling.Skip)]
49+
ReadCommentHandling = JsonCommentHandling.Skip,
50+
UnmappedMemberHandling = JsonUnmappedMemberHandling.Skip,
51+
UnknownTypeHandling = JsonUnknownTypeHandling.JsonElement,
52+
Converters = [typeof(TypeDescriptorConverter),
53+
typeof(FieldDescriptorConverter),
54+
typeof(GlobalDescriptorConverter)])]
4655
internal sealed partial class ContractDescriptorContext : JsonSerializerContext
4756
{
4857
}
@@ -58,7 +67,13 @@ public class ContractDescriptor
5867
public Dictionary<string, GlobalDescriptor>? Globals { get; set; }
5968

6069
[JsonExtensionData]
61-
public Dictionary<string, object?>? Extras { get; set; }
70+
public Dictionary<string, JsonElement>? Extras { get; set; }
71+
72+
public override string ToString()
73+
{
74+
return $"Version: {Version}, Baseline: {Baseline}, Contracts: {Contracts?.Count}, Types: {Types?.Count}, Globals: {Globals?.Count}";
75+
}
76+
6277
}
6378

6479
[JsonConverter(typeof(TypeDescriptorConverter))]

src/native/managed/cdacreader/src/Entrypoints.cs

+4-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,10 @@ internal static class Entrypoints
1414
[UnmanagedCallersOnly(EntryPoint = $"{CDAC}init")]
1515
private static unsafe int Init(ulong descriptor, delegate* unmanaged<ulong, byte*, uint, void*, int> readFromTarget, void* readContext, IntPtr* handle)
1616
{
17-
Target target = new(descriptor, readFromTarget, readContext);
17+
// TODO: [cdac] Better error code/details
18+
if (!Target.TryCreate(descriptor, readFromTarget, readContext, out Target? target))
19+
return -1;
20+
1821
GCHandle gcHandle = GCHandle.Alloc(target);
1922
*handle = GCHandle.ToIntPtr(gcHandle);
2023
return 0;
+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using System.Text.Json.Serialization;
5+
6+
namespace Microsoft.Diagnostics.DataContractReader;
7+
8+
internal static class Root
9+
{
10+
// https://github.com/dotnet/runtime/issues/101205
11+
public static JsonDerivedTypeAttribute[] R1 = new JsonDerivedTypeAttribute[] { null! };
12+
}

0 commit comments

Comments
 (0)