Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[cdac] Begin adding MethodDesc APIs to the RuntimeTypeSystem contract #104811

Merged
merged 25 commits into from
Jul 20, 2024
Merged
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
ffc4b8a
start GetMethodDescDataImpl
lambdageek Jul 8, 2024
9e0272a
WIP: managed GetMethodDescData skeleton
lambdageek Jul 8, 2024
29e404c
wip: MethodDesc
lambdageek Jul 9, 2024
9719c75
add MethodDescChunk
lambdageek Jul 10, 2024
f076f19
WIP: validating a MethodDesc
lambdageek Jul 11, 2024
c935626
checkpoint: MethodDesc validation
lambdageek Jul 12, 2024
fa42ef0
update contract
lambdageek Jul 12, 2024
27f4a96
fix RuntimeTypeSystem unit tests
lambdageek Jul 12, 2024
9dbd432
update contract
lambdageek Jul 15, 2024
793681f
fix GetMethodDescChunkPointerMayThrow
lambdageek Jul 15, 2024
a46f91e
fixup rebase
lambdageek Jul 16, 2024
3f82a89
add data descriptor description to the contract
lambdageek Jul 18, 2024
8111d53
Apply suggestions from code review
lambdageek Jul 19, 2024
07c810e
MayThrow -> Throwing
lambdageek Jul 19, 2024
6f1d9a8
Slot is ushort not byte
lambdageek Jul 19, 2024
fa42684
remove unused property
lambdageek Jul 19, 2024
9613999
add TargetPointer 32-/64-bit max constants
lambdageek Jul 19, 2024
214ffe9
use NewArrayHolder
lambdageek Jul 19, 2024
c6e057a
spelling
lambdageek Jul 19, 2024
b000f7a
add globals to RTS contract
lambdageek Jul 19, 2024
dc1812c
Merge remote-tracking branch 'origin/main' into cdac-methoddesc
lambdageek Jul 19, 2024
d4f6299
remove unused usings
lambdageek Jul 19, 2024
10f0943
constexpr cdac_offsets, not const
lambdageek Jul 19, 2024
515a3e3
Apply suggestions from code review
lambdageek Jul 20, 2024
1f182f1
make GetNumVtableSlots private
lambdageek Jul 20, 2024
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
62 changes: 60 additions & 2 deletions docs/design/datacontracts/RuntimeTypeSystem.md
Original file line number Diff line number Diff line change
@@ -4,10 +4,11 @@ This contract is for exploring the properties of the runtime types of values on

## APIs of contract

### TypeHandle

A `TypeHandle` is the runtime representation of the type information about a value which is represented as a TypeHandle.
Given a `TargetPointer` address, the `RuntimeTypeSystem` contract provides a `TypeHandle` for querying the details of the `TypeHandle`.


``` csharp
struct TypeHandle
{
@@ -28,6 +29,8 @@ internal enum CorElementType
A `TypeHandle` is the runtime representation of the type information about a value. This can be constructed from the address of a `TypeHandle` or a `MethodTable`.

``` csharp
partial interface IRuntimeTypeSystem : IContract
{
#region TypeHandle inspection APIs
public virtual TypeHandle GetTypeHandle(TargetPointer targetPointer);

@@ -73,10 +76,35 @@ A `TypeHandle` is the runtime representation of the type information about a val
public virtual bool IsFunctionPointer(TypeHandle typeHandle, out ReadOnlySpan<TypeHandle> retAndArgTypes, out byte callConv);

#endregion TypeHandle inspection APIs
}
```

### MethodDesc

A `MethodDesc` is the runtime representation of a managed method (either from IL, from reflection emit, or generated by the runtime).

```csharp
struct MethodDescHandle
{
// no public properties or constructors

internal TargetPointer Address { get; }
}
```

```csharp
partial interface IRuntimeTypeSystem : IContract
{
public virtual MethodDescHandle GetMethodDescHandle(TargetPointer methodDescPointer);

public virtual TargetPointer GetMethodTable(MethodDescHandle methodDesc);
}
```

## Version 1

### TypeHandle

The `MethodTable` inspection APIs are implemented in terms of the following flags on the runtime `MethodTable` structure:

``` csharp
@@ -233,7 +261,11 @@ static class RuntimeTypeSystem_1_Helpers
}
```

The contract depends on the global pointer value `FreeObjectMethodTablePointer`.
The contract depends on the following globals

| Global name | Meaning |
| --- | --- |
| `FreeObjectMethodTablePointer` | A pointer to the address of a `MethodTable` used by the GC to indicate reclaimed memory

The contract additionally depends on these data descriptors

@@ -251,6 +283,7 @@ The contract additionally depends on these data descriptors
| `EEClass` | `InternalCorElementType` | An InternalCorElementType uses the enum values of a CorElementType to indicate some of the information about the type of the type which uses the EEClass In particular, all reference types are CorElementType.Class, Enums are the element type of their underlying type and ValueTypes which can exactly be represented as an element type are represented as such, all other values types are represented as CorElementType.ValueType. |
| `EEClass` | `MethodTable` | Pointer to the canonical MethodTable of this type |
| `EEClass` | `NumMethods` | Count of methods attached to the EEClass |
| `EEClass` | `NumNonVirtualSlots` | Count of non-virtual slots for the EEClass |
| `EEClass` | `CorTypeAttr` | Various flags |
| `ArrayClass` | `Rank` | Rank of the associated array MethodTable |
| `TypeDesc` | `TypeAndFlags` | The lower 8 bits are the CorElementType of the `TypeDesc`, the upper 24 bits are reserved for flags |
@@ -523,3 +556,28 @@ The contract additionally depends on these data descriptors
return true;
}
```

### MethodDesc

The version 1 `MethodDesc` APIs depend on the `MethodDescAlignment` global and the `MethodDesc` and `MethodDescChunk` data descriptors.

| Global name | Meaning |
| --- | --- |
| `MethodDescAlignment` | `MethodDescChunk` trailing data is allocated in multiples of this constant. The size (in bytes) of each `MethodDesc` (or subclass) instance is a multiple of this constant.


In the runtime a `MethodDesc` implicitly belongs to a single `MethodDescChunk` and some common data is shared between method descriptors that belong to the same chunk. A single method table
will typically have multiple chunks. There are subkinds of MethodDescs at runtime of varying sizes (but the sizes must be mutliples of `MethodDescAlignment`) and each chunk contains method descriptors of the same size.

We depend on the following data descriptors:
| Data Descriptor Name | Field | Meaning |
| --- | --- | --- |
| `MethodDesc` | `ChunkIndex` | Offset of this `MethodDesc` relative to the end of its containing `MethodDescChunk` - in multiples of `MethodDescAlignment`
| `MethodDesc` | `Slot` | The method's slot
| `MethodDesc` | `Flags` | The method's flags
| `MethodDescChunk` | `MethodTable` | The method table set of methods belongs to
| `MethodDescChunk` | `Next` | The next chunk of methods
| `MethodDescChunk` | `Size` | The size of this `MethodDescChunk` following this `MethodDescChunk` header, minus 1. In multiples of `MethodDescAlignment`
| `MethodDescChunk` | `Count` | The number of `MethodDesc` entries in this chunk, minus 1.

**TODO(cdac)**
1 change: 1 addition & 0 deletions src/coreclr/debug/daccess/dacimpl.h
Original file line number Diff line number Diff line change
@@ -1243,6 +1243,7 @@ class ClrDataAccess
HRESULT GetObjectExceptionDataImpl(CLRDATA_ADDRESS objAddr, struct DacpExceptionObjectData *data);
HRESULT GetObjectStringDataImpl(CLRDATA_ADDRESS obj, unsigned int count, _Inout_updates_z_(count) WCHAR *stringData, unsigned int *pNeeded);
HRESULT GetUsefulGlobalsImpl(struct DacpUsefulGlobalsData *globalsData);
HRESULT GetMethodDescDataImpl(CLRDATA_ADDRESS methodDesc, CLRDATA_ADDRESS ip, struct DacpMethodDescData *data, ULONG cRevertedRejitVersions, DacpReJitData * rgRevertedRejitData, ULONG * pcNeededRevertedRejitData);

BOOL IsExceptionFromManagedCode(EXCEPTION_RECORD * pExceptionRecord);
#ifndef TARGET_UNIX
65 changes: 64 additions & 1 deletion src/coreclr/debug/daccess/request.cpp
Original file line number Diff line number Diff line change
@@ -1041,6 +1041,70 @@ HRESULT ClrDataAccess::GetMethodDescData(
}

SOSDacEnter();
if (m_cdacSos != NULL)
{
// Try the cDAC first - it will return E_NOTIMPL if it doesn't support this method yet. Fall back to the DAC.
hr = m_cdacSos->GetMethodDescData(methodDesc, ip, methodDescData, cRevertedRejitVersions, rgRevertedRejitData, pcNeededRevertedRejitData);
if (FAILED(hr))
{
hr = GetMethodDescDataImpl(methodDesc, ip, methodDescData, cRevertedRejitVersions, rgRevertedRejitData, pcNeededRevertedRejitData);
}
#ifdef _DEBUG
else
{
// Assert that the data is the same as what we get from the DAC.
DacpMethodDescData mdDataLocal;
NewArrayHolder<DacpReJitData> rgRevertedRejitDataLocal{};
if (rgRevertedRejitData != nullptr)
{
rgRevertedRejitDataLocal = new DacpReJitData[cRevertedRejitVersions];
}
ULONG cNeededRevertedRejitDataLocal = 0;
ULONG *pcNeededRevertedRejitDataLocal = NULL;
if (pcNeededRevertedRejitData != NULL)
{
pcNeededRevertedRejitDataLocal = &cNeededRevertedRejitDataLocal;
}
HRESULT hrLocal = GetMethodDescDataImpl(methodDesc, ip,&mdDataLocal, cRevertedRejitVersions, rgRevertedRejitDataLocal, pcNeededRevertedRejitDataLocal);
_ASSERTE(hr == hrLocal);
_ASSERTE(methodDescData->bHasNativeCode == mdDataLocal.bHasNativeCode);
_ASSERTE(methodDescData->bIsDynamic == mdDataLocal.bIsDynamic);
_ASSERTE(methodDescData->wSlotNumber == mdDataLocal.wSlotNumber);
_ASSERTE(methodDescData->NativeCodeAddr == mdDataLocal.NativeCodeAddr);
_ASSERTE(methodDescData->AddressOfNativeCodeSlot == mdDataLocal.AddressOfNativeCodeSlot);
//TODO[cdac]: assert the rest of mdDataLocal contains the same info as methodDescData
if (rgRevertedRejitData != NULL)
{
_ASSERTE (cNeededRevertedRejitDataLocal == *pcNeededRevertedRejitData);
for (ULONG i = 0; i < cNeededRevertedRejitDataLocal; i++)
{
_ASSERTE(rgRevertedRejitData[i].rejitID == rgRevertedRejitDataLocal[i].rejitID);
_ASSERTE(rgRevertedRejitData[i].NativeCodeAddr == rgRevertedRejitDataLocal[i].NativeCodeAddr);
_ASSERTE(rgRevertedRejitData[i].flags == rgRevertedRejitDataLocal[i].flags);
}
}
}
#endif
}
else
{
hr = GetMethodDescDataImpl(methodDesc, ip, methodDescData, cRevertedRejitVersions, rgRevertedRejitData, pcNeededRevertedRejitData);
}

SOSDacLeave();
return hr;
}

HRESULT ClrDataAccess::GetMethodDescDataImpl(
CLRDATA_ADDRESS methodDesc,
CLRDATA_ADDRESS ip,
struct DacpMethodDescData *methodDescData,
ULONG cRevertedRejitVersions,
DacpReJitData * rgRevertedRejitData,
ULONG * pcNeededRevertedRejitData)
{

HRESULT hr = S_OK;

PTR_MethodDesc pMD = PTR_MethodDesc(TO_TADDR(methodDesc));

@@ -1236,7 +1300,6 @@ HRESULT ClrDataAccess::GetMethodDescData(
}
}

SOSDacLeave();
return hr;
}

19 changes: 18 additions & 1 deletion src/coreclr/debug/runtimeinfo/datadescriptor.h
Original file line number Diff line number Diff line change
@@ -202,7 +202,7 @@ CDAC_TYPE_FIELD(Module, /*pointer*/, TypeDefToMethodTableMap, cdac_offsets<Modul
CDAC_TYPE_FIELD(Module, /*pointer*/, TypeRefToMethodTableMap, cdac_offsets<Module>::TypeRefToMethodTableMap)
CDAC_TYPE_END(Module)

// Metadata
// RuntimeTypeSystem

CDAC_TYPE_BEGIN(MethodTable)
CDAC_TYPE_INDETERMINATE(MethodTable)
@@ -223,6 +223,7 @@ CDAC_TYPE_FIELD(EEClass, /*pointer*/, MethodTable, cdac_offsets<EEClass>::Method
CDAC_TYPE_FIELD(EEClass, /*uint16*/, NumMethods, cdac_offsets<EEClass>::NumMethods)
CDAC_TYPE_FIELD(EEClass, /*uint32*/, CorTypeAttr, cdac_offsets<EEClass>::CorTypeAttr)
CDAC_TYPE_FIELD(EEClass, /*uint8*/, InternalCorElementType, cdac_offsets<EEClass>::InternalCorElementType)
CDAC_TYPE_FIELD(EEClass, /*uint16*/, NumNonVirtualSlots, cdac_offsets<EEClass>::NumNonVirtualSlots)
CDAC_TYPE_END(EEClass)

CDAC_TYPE_BEGIN(ArrayClass)
@@ -263,6 +264,21 @@ CDAC_TYPE_FIELD(DynamicMetadata, /*uint32*/, Size, cdac_offsets<DynamicMetadata>
CDAC_TYPE_FIELD(DynamicMetadata, /*inline byte array*/, Data, cdac_offsets<DynamicMetadata>::Data)
CDAC_TYPE_END(DynamicMetadata)

CDAC_TYPE_BEGIN(MethodDesc)
CDAC_TYPE_INDETERMINATE(MethodDesc)
CDAC_TYPE_FIELD(MethodDesc, /*uint8*/, ChunkIndex, cdac_offsets<MethodDesc>::ChunkIndex)
CDAC_TYPE_FIELD(MethodDesc, /*uint16*/, Slot, cdac_offsets<MethodDesc>::Slot)
CDAC_TYPE_FIELD(MethodDesc, /*uint16*/, Flags, cdac_offsets<MethodDesc>::Flags)
CDAC_TYPE_END(MethodDesc)

CDAC_TYPE_BEGIN(MethodDescChunk)
CDAC_TYPE_SIZE(sizeof(MethodDescChunk))
CDAC_TYPE_FIELD(MethodDescChunk, /*pointer*/, MethodTable, cdac_offsets<MethodDescChunk>::MethodTable)
CDAC_TYPE_FIELD(MethodDescChunk, /*pointer*/, Next, cdac_offsets<MethodDescChunk>::Next)
CDAC_TYPE_FIELD(MethodDescChunk, /*uint8*/, Size, cdac_offsets<MethodDescChunk>::Size)
CDAC_TYPE_FIELD(MethodDescChunk, /*uint8*/, Count, cdac_offsets<MethodDescChunk>::Count)
CDAC_TYPE_END(MethodDescChunk)

CDAC_TYPES_END()

CDAC_GLOBALS_BEGIN()
@@ -282,6 +298,7 @@ CDAC_GLOBAL(ObjectToMethodTableUnmask, uint8, 1 | 1 << 1 | 1 << 2)
CDAC_GLOBAL(ObjectToMethodTableUnmask, uint8, 1 | 1 << 1)
#endif //TARGET_64BIT
CDAC_GLOBAL(SOSBreakingChangeVersion, uint8, SOS_BREAKING_CHANGE_VERSION)
CDAC_GLOBAL(MethodDescAlignment, uint64, MethodDesc::ALIGNMENT)
CDAC_GLOBAL_POINTER(ExceptionMethodTable, &::g_pExceptionClass)
CDAC_GLOBAL_POINTER(FreeObjectMethodTable, &::g_pFreeObjectMethodTable)
CDAC_GLOBAL_POINTER(ObjectMethodTable, &::g_pObjectClass)
1 change: 1 addition & 0 deletions src/coreclr/vm/class.h
Original file line number Diff line number Diff line change
@@ -1807,6 +1807,7 @@ template<> struct cdac_offsets<EEClass>
static constexpr size_t MethodTable = offsetof(EEClass, m_pMethodTable);
static constexpr size_t NumMethods = offsetof(EEClass, m_NumMethods);
static constexpr size_t CorTypeAttr = offsetof(EEClass, m_dwAttrClass);
static constexpr size_t NumNonVirtualSlots = offsetof(EEClass, m_NumNonVirtualSlots);
};

// --------------------------------------------------------------------------------------------
20 changes: 20 additions & 0 deletions src/coreclr/vm/method.hpp
Original file line number Diff line number Diff line change
@@ -1908,6 +1908,15 @@ class MethodDesc
public:
static void Init();
#endif

template<typename T> friend struct ::cdac_offsets;
};

template<> struct cdac_offsets<MethodDesc>
{
static constexpr size_t ChunkIndex = offsetof(MethodDesc, m_chunkIndex);
static constexpr size_t Slot = offsetof(MethodDesc, m_wSlotNumber);
static constexpr size_t Flags = offsetof(MethodDesc, m_wFlags);
};

#ifndef DACCESS_COMPILE
@@ -2328,6 +2337,17 @@ class MethodDescChunk
UINT16 m_flagsAndTokenRange;

// Followed by array of method descs...

template<typename T> friend struct ::cdac_offsets;
};

template<>
struct cdac_offsets<MethodDescChunk>
{
static constexpr size_t MethodTable = offsetof(MethodDescChunk, m_methodTable);
static constexpr size_t Next = offsetof(MethodDescChunk, m_next);
static constexpr size_t Size = offsetof(MethodDescChunk, m_size);
static constexpr size_t Count = offsetof(MethodDescChunk, m_count);
};

inline int MethodDesc::GetMethodDescChunkIndex() const
2 changes: 1 addition & 1 deletion src/coreclr/vm/methodtable.h
Original file line number Diff line number Diff line change
@@ -621,7 +621,7 @@ struct DynamicStaticsInfo
// If it has, then we don't need to do anything
return false;
}

if (isClassInitedByUpdatingStaticPointer)
{
oldValFromInterlockedOp = InterlockedCompareExchangeT(pAddr, newVal, oldVal);
2 changes: 2 additions & 0 deletions src/native/managed/cdacreader/src/Constants.cs
Original file line number Diff line number Diff line change
@@ -25,5 +25,7 @@ internal static class Globals

internal const string MiniMetaDataBuffAddress = nameof(MiniMetaDataBuffAddress);
internal const string MiniMetaDataBuffMaxSize = nameof(MiniMetaDataBuffMaxSize);

internal const string MethodDescAlignment = nameof(MethodDescAlignment);
}
}
18 changes: 17 additions & 1 deletion src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem.cs
Original file line number Diff line number Diff line change
@@ -55,16 +55,27 @@ internal enum CorElementType
Sentinel = 0x41,
}

internal readonly struct MethodDescHandle
{
internal MethodDescHandle(TargetPointer address)
{
Address = address;
}

internal TargetPointer Address { get; }
}

internal interface IRuntimeTypeSystem : IContract
{
static string IContract.Name => nameof(RuntimeTypeSystem);
static IContract IContract.Create(Target target, int version)
{
TargetPointer targetPointer = target.ReadGlobalPointer(Constants.Globals.FreeObjectMethodTable);
TargetPointer freeObjectMethodTable = target.ReadPointer(targetPointer);
ulong methodDescAlignment = target.ReadGlobal<ulong>(Constants.Globals.MethodDescAlignment);
return version switch
{
1 => new RuntimeTypeSystem_1(target, freeObjectMethodTable),
1 => new RuntimeTypeSystem_1(target, freeObjectMethodTable, methodDescAlignment),
_ => default(RuntimeTypeSystem),
};
}
@@ -113,6 +124,11 @@ static IContract IContract.Create(Target target, int version)
public virtual bool IsFunctionPointer(TypeHandle typeHandle, out ReadOnlySpan<TypeHandle> retAndArgTypes, out byte callConv) => throw new NotImplementedException();
// Returns null if the TypeHandle is not a class/struct/generic variable
#endregion TypeHandle inspection APIs

#region MethodDesc inspection APIs
public virtual MethodDescHandle GetMethodDescHandle(TargetPointer targetPointer) => throw new NotImplementedException();
public virtual TargetPointer GetMethodTable(MethodDescHandle methodDesc) => throw new NotImplementedException();
#endregion MethodDesc inspection APIs
}

internal struct RuntimeTypeSystem : IRuntimeTypeSystem
Loading

Unchanged files with check annotations Beta

ContinueOnError="ErrorAndContinue" />
<!-- Given we ErrorAndContinue we need to propagate the error if the overall task failed -->
<Error Condition="'$(MSBuildLastTaskResult)'=='false'" />

Check failure on line 25 in src/tests/Common/dir.traversal.targets

Azure Pipelines / runtime (Build linux-x64 Debug NativeAOT)

src/tests/Common/dir.traversal.targets#L25

src/tests/Common/dir.traversal.targets(25,5): error : (No message specified) [/__w/1/s/src/tests/build.proj]
</Target>
<Target Name="CleanAllProjects">
<Message Importance="High" Text="$(MsgPrefix)Building managed test group $(__TestGroupToBuild): $(GroupBuildCmd)" />
<Exec Command="$(GroupBuildCmd)" />

Check failure on line 620 in src/tests/build.proj

Azure Pipelines / runtime (Build linux-x64 Debug NativeAOT)

src/tests/build.proj#L620

src/tests/build.proj(620,5): error MSB3073: The command ""/__w/1/s/dotnet.sh" msbuild /__w/1/s/src/tests/build.proj /t:Build "/p:TargetArchitecture=x64" "/p:Configuration=Debug" "/p:LibrariesConfiguration=Release" "/p:TasksConfiguration=Debug" "/p:TargetOS=linux" "/p:ToolsOS=" "/p:PackageOS=" "/p:RuntimeFlavor=coreclr" "/p:RuntimeVariant=" "/p:CLRTestBuildAllTargets=" "/p:UseCodeFlowEnforcement=" "/p:__TestGroupToBuild=3" "/p:__SkipRestorePackages=1" /nodeReuse:false /maxcpucount /bl:/__w/1/s/artifacts//log/Debug/InnerManagedTestBuild.3.binlog "/p:CrossBuild=true" "/p:DefaultBuildAllTarget=BuildNativeAot"" exited with code 1.
</Target>
<Target Name="CheckTestBuildStep"
<!-- Use IgnoreStandardErrorWarningFormat because Arcade sets WarnAsError and there's an existing warning in the native build. -->
<Message Text="Executing &quot;$(MSBuildThisFileDirectory)$(_CoreClrBuildScript)&quot; @(_CoreClrBuildArg->'%(Identity)',' ')" Importance="High" />
<Exec Command="&quot;$(MSBuildThisFileDirectory)$(_CoreClrBuildScript)&quot; @(_CoreClrBuildArg->'%(Identity)',' ')"

Check failure on line 108 in src/coreclr/runtime.proj

Azure Pipelines / runtime (Build linux-armel checked CoreCLR_NonPortable)

src/coreclr/runtime.proj#L108

src/coreclr/runtime.proj(108,5): error MSB3073: (NETCORE_ENGINEERING_TELEMETRY=Build) The command ""/__w/1/s/src/coreclr/build-runtime.sh" -armel -checked -ci -cross -portablebuild=false -os linux -outputrid tizen.9.0.0-armel -cmakeargs "-DCLR_DOTNET_HOST_PATH=/__w/1/s/.dotnet/dotnet" -cmakeargs "-DCDAC_BUILD_TOOL_BINARY_PATH=/__w/1/s/artifacts/bin/coreclr/linux.armel.Checked/cdac-build-tool/cdac-build-tool.dll"" exited with code 1.

Check failure on line 108 in src/coreclr/runtime.proj

Azure Pipelines / runtime

src/coreclr/runtime.proj#L108

src/coreclr/runtime.proj(108,5): error MSB3073: (NETCORE_ENGINEERING_TELEMETRY=Build) The command ""/__w/1/s/src/coreclr/build-runtime.sh" -armel -checked -ci -cross -portablebuild=false -os linux -outputrid tizen.9.0.0-armel -cmakeargs "-DCLR_DOTNET_HOST_PATH=/__w/1/s/.dotnet/dotnet" -cmakeargs "-DCDAC_BUILD_TOOL_BINARY_PATH=/__w/1/s/artifacts/bin/coreclr/linux.armel.Checked/cdac-build-tool/cdac-build-tool.dll"" exited with code 1.
IgnoreStandardErrorWarningFormat="true" />
</Target>