diff --git a/docs/design/datacontracts/Loader.md b/docs/design/datacontracts/Loader.md index dc56b8e33b7303..43455516d2b28e 100644 --- a/docs/design/datacontracts/Loader.md +++ b/docs/design/datacontracts/Loader.md @@ -56,6 +56,7 @@ ModuleHandle GetModuleHandleFromModulePtr(TargetPointer module); ModuleHandle GetModuleHandleFromAssemblyPtr(TargetPointer assemblyPointer); IEnumerable GetModuleHandles(TargetPointer appDomain, AssemblyIterationFlags iterationFlags); TargetPointer GetRootAssembly(); +string GetAppDomainFriendlyName(); TargetPointer GetModule(ModuleHandle handle); TargetPointer GetAssembly(ModuleHandle handle); TargetPointer GetPEAssembly(ModuleHandle handle); @@ -116,6 +117,7 @@ TargetPointer GetStubHeap(TargetPointer loaderAllocatorPointer); | `CGrowableSymbolStream` | `Size` | Size of the raw symbol stream buffer | | `AppDomain` | `RootAssembly` | Pointer to the root assembly | | `AppDomain` | `DomainAssemblyList` | ArrayListBase of assemblies in the AppDomain | +| `AppDomain` | `FriendlyName` | Friendly name of the AppDomain | | `LoaderAllocator` | `ReferenceCount` | Reference count of LoaderAllocator | | `LoaderAllocator` | `HighFrequencyHeap` | High-frequency heap of LoaderAllocator | | `LoaderAllocator` | `LowFrequencyHeap` | Low-frequency heap of LoaderAllocator | @@ -270,6 +272,15 @@ TargetPointer GetRootAssembly() return appDomain.RootAssembly; } +string ILoader.GetAppDomainFriendlyName() +{ + TargetPointer appDomainPointer = target.ReadGlobalPointer(Constants.Globals.AppDomain); + TargetPointer appDomain = target.ReadPointer(appDomainPointer) + TargetPointer pathStart = appDomain + /* AppDomain::FriendlyName offset */; + char[] name = // Read from target starting at pathStart until null terminator + return new string(name); +} + TargetPointer ILoader.GetModule(ModuleHandle handle) { return handle.Address; @@ -395,20 +406,20 @@ TargetPointer GetModuleLookupMapElement(TargetPointer table, uint token, out Tar uint index = rid; // have to read lookupMap an extra time upfront because only the first map // has valid supportedFlagsMask - TargetNUInt supportedFlagsMask = _target.ReadNUInt(table + /* ModuleLookupMap::SupportedFlagsMask */); + TargetNUInt supportedFlagsMask = target.ReadNUInt(table + /* ModuleLookupMap::SupportedFlagsMask */); do { - if (index < _target.Read(table + /*ModuleLookupMap::Count*/)) + if (index < target.Read(table + /*ModuleLookupMap::Count*/)) { - TargetPointer entryAddress = _target.ReadPointer(lookupMap + /*ModuleLookupMap::TableData*/) + (ulong)(index * _target.PointerSize); - TargetPointer rawValue = _target.ReadPointer(entryAddress); + TargetPointer entryAddress = target.ReadPointer(lookupMap + /*ModuleLookupMap::TableData*/) + (ulong)(index * target.PointerSize); + TargetPointer rawValue = target.ReadPointer(entryAddress); flags = rawValue & supportedFlagsMask; return rawValue & ~(supportedFlagsMask.Value); } else { - table = _target.ReadPointer(lookupMap + /*ModuleLookupMap::Next*/); - index -= _target.Read(lookupMap + /*ModuleLookupMap::Count*/); + table = target.ReadPointer(lookupMap + /*ModuleLookupMap::Next*/); + index -= target.Read(lookupMap + /*ModuleLookupMap::Count*/); } } while (table != TargetPointer.Null); return TargetPointer.Null; diff --git a/src/coreclr/debug/runtimeinfo/datadescriptor.inc b/src/coreclr/debug/runtimeinfo/datadescriptor.inc index 7b67aef397ca9b..34d76fce24f096 100644 --- a/src/coreclr/debug/runtimeinfo/datadescriptor.inc +++ b/src/coreclr/debug/runtimeinfo/datadescriptor.inc @@ -295,6 +295,7 @@ CDAC_TYPE_BEGIN(AppDomain) CDAC_TYPE_INDETERMINATE(AppDomain) CDAC_TYPE_FIELD(AppDomain, /*pointer*/, RootAssembly, cdac_data::RootAssembly) CDAC_TYPE_FIELD(AppDomain, /*DomainAssemblyList*/, DomainAssemblyList, cdac_data::DomainAssemblyList) +CDAC_TYPE_FIELD(AppDomain, /*pointer*/, FriendlyName, cdac_data::FriendlyName) CDAC_TYPE_END(AppDomain) CDAC_TYPE_BEGIN(SystemDomain) diff --git a/src/coreclr/vm/appdomain.hpp b/src/coreclr/vm/appdomain.hpp index 4a9ee03c857821..8a42c4d7cd213f 100644 --- a/src/coreclr/vm/appdomain.hpp +++ b/src/coreclr/vm/appdomain.hpp @@ -1571,6 +1571,7 @@ struct cdac_data { static constexpr size_t RootAssembly = offsetof(AppDomain, m_pRootAssembly); static constexpr size_t DomainAssemblyList = offsetof(AppDomain, m_Assemblies) + offsetof(AppDomain::DomainAssemblyList, m_array); + static constexpr size_t FriendlyName = offsetof(AppDomain, m_friendlyName); }; typedef DPTR(class SystemDomain) PTR_SystemDomain; diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/ILoader.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/ILoader.cs index 384cb9e20c84a2..85cf26fafdb12d 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/ILoader.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/ILoader.cs @@ -79,6 +79,7 @@ public interface ILoader : IContract ModuleHandle GetModuleHandleFromAssemblyPtr(TargetPointer assemblyPointer) => throw new NotImplementedException(); IEnumerable GetModuleHandles(TargetPointer appDomain, AssemblyIterationFlags iterationFlags) => throw new NotImplementedException(); TargetPointer GetRootAssembly() => throw new NotImplementedException(); + string GetAppDomainFriendlyName() => throw new NotImplementedException(); TargetPointer GetModule(ModuleHandle handle) => throw new NotImplementedException(); TargetPointer GetAssembly(ModuleHandle handle) => throw new NotImplementedException(); TargetPointer GetPEAssembly(ModuleHandle handle) => throw new NotImplementedException(); diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Loader_1.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Loader_1.cs index cb0cc5a66c977a..2f1223fe9fd045 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Loader_1.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Loader_1.cs @@ -139,6 +139,16 @@ TargetPointer ILoader.GetRootAssembly() Data.AppDomain appDomain = _target.ProcessedData.GetOrAdd(_target.ReadPointer(appDomainPointer)); return appDomain.RootAssembly; } + + string ILoader.GetAppDomainFriendlyName() + { + TargetPointer appDomainPointer = _target.ReadGlobalPointer(Constants.Globals.AppDomain); + Data.AppDomain appDomain = _target.ProcessedData.GetOrAdd(_target.ReadPointer(appDomainPointer)); + return appDomain.FriendlyName != TargetPointer.Null + ? _target.ReadUtf16String(appDomain.FriendlyName) + : string.Empty; + } + TargetPointer ILoader.GetModule(ModuleHandle handle) { return handle.Address; diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/AppDomain.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/AppDomain.cs index a0df88ed1faa28..cd21ff7172abce 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/AppDomain.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/AppDomain.cs @@ -14,8 +14,10 @@ public AppDomain(Target target, TargetPointer address) RootAssembly = target.ReadPointer(address + (ulong)type.Fields[nameof(RootAssembly)].Offset); DomainAssemblyList = address + (ulong)type.Fields[nameof(DomainAssemblyList)].Offset; + FriendlyName = target.ReadPointer(address + (ulong)type.Fields[nameof(FriendlyName)].Offset); } public TargetPointer RootAssembly { get; init; } public TargetPointer DomainAssemblyList { get; init; } + public TargetPointer FriendlyName { get; init; } } diff --git a/src/native/managed/cdac/mscordaccore_universal/Legacy/SOSDacImpl.cs b/src/native/managed/cdac/mscordaccore_universal/Legacy/SOSDacImpl.cs index f196e9a42e177c..c727d2a147a684 100644 --- a/src/native/managed/cdac/mscordaccore_universal/Legacy/SOSDacImpl.cs +++ b/src/native/managed/cdac/mscordaccore_universal/Legacy/SOSDacImpl.cs @@ -227,7 +227,62 @@ int ISOSDacInterface.GetAppDomainList(uint count, [In, MarshalUsing(CountElement return hr; } int ISOSDacInterface.GetAppDomainName(ClrDataAddress addr, uint count, char* name, uint* pNeeded) - => _legacyImpl is not null ? _legacyImpl.GetAppDomainName(addr, count, name, pNeeded) : HResults.E_NOTIMPL; + { + int hr = HResults.S_OK; + try + { + ILoader loader = _target.Contracts.Loader; + string friendlyName = loader.GetAppDomainFriendlyName(); + TargetPointer systemDomainPtr = _target.ReadGlobalPointer(Constants.Globals.SystemDomain); + ClrDataAddress systemDomain = _target.ReadPointer(systemDomainPtr).ToClrDataAddress(_target); + if (addr == systemDomain || friendlyName == string.Empty) + { + if (pNeeded is not null) + { + *pNeeded = 1; + } + if (name is not null && count > 0) + { + name[0] = '\0'; // Set the first character to null terminator + } + } + else + { + if (pNeeded is not null) + { + *pNeeded = (uint)(friendlyName.Length + 1); // +1 for null terminator + } + + if (name is not null && count > 0) + { + OutputBufferHelpers.CopyStringToBuffer(name, count, pNeeded, friendlyName); + } + } + } + catch (System.Exception ex) + { + hr = ex.HResult; + } +#if DEBUG + if (_legacyImpl is not null) + { + uint neededLocal; + char[] nameLocal = new char[count]; + int hrLocal; + fixed (char* ptr = nameLocal) + { + hrLocal = _legacyImpl.GetAppDomainName(addr, count, ptr, &neededLocal); + } + Debug.Assert(hrLocal == hr, $"cDAC: {hr:x}, DAC: {hrLocal:x}"); + if (hr == HResults.S_OK) + { + Debug.Assert(pNeeded == null || *pNeeded == neededLocal); + Debug.Assert(name == null || new ReadOnlySpan(nameLocal, 0, (int)neededLocal - 1).SequenceEqual(new string(name))); + } + } +#endif + return hr; + } int ISOSDacInterface.GetAppDomainStoreData(void* data) { DacpAppDomainStoreData* appDomainStoreData = (DacpAppDomainStoreData*)data;