From b7e7737ed120fe2a72d6a925d0714e57e80f79f4 Mon Sep 17 00:00:00 2001 From: Lee Culver Date: Fri, 31 Mar 2023 12:54:25 -0700 Subject: [PATCH 001/111] Add -list to !sos maddress (#3798) - Added a way to list all kinds of a specific memory type - Added caching to NativeAddressHelper, as it was recalculating every run --- .../MAddressCommand.cs | 50 ++++++++++++++++++- .../NativeAddressHelper.cs | 31 ++++++++++-- 2 files changed, 74 insertions(+), 7 deletions(-) diff --git a/src/Microsoft.Diagnostics.ExtensionCommands/MAddressCommand.cs b/src/Microsoft.Diagnostics.ExtensionCommands/MAddressCommand.cs index 670719f193..7e59762b94 100644 --- a/src/Microsoft.Diagnostics.ExtensionCommands/MAddressCommand.cs +++ b/src/Microsoft.Diagnostics.ExtensionCommands/MAddressCommand.cs @@ -17,6 +17,7 @@ public sealed class MAddressCommand : CommandBase private const string ReserveFlag = "-reserve"; private const string ReserveHeuristicFlag = "-reserveHeuristic"; private const string ForceHandleTableFlag = "-forceHandleTable"; + private const string ListFlag = "-list"; [Option(Name = SummaryFlag, Aliases = new string[] { "-stat", }, Help = "Only print summary table.")] public bool Summary { get; set; } @@ -33,6 +34,9 @@ public sealed class MAddressCommand : CommandBase [Option(Name = ForceHandleTableFlag, Help = "We only tag the HandleTable if we can do so efficiently on newer runtimes. This option ensures we always tag HandleTable memory, even if it will take a long time.")] public bool IncludeHandleTableIfSlow { get; set; } + [Option(Name = ListFlag, Help = "A separated list of regions to list allocations for.")] + public string List { get; set; } + [ServiceImport] public NativeAddressHelper AddressHelper { get; set; } @@ -59,7 +63,7 @@ public override void Invoke() CollapseReserveRegions(ranges); } - if (!Summary) + if (!Summary && List is null) { int kindSize = ranges.Max(r => r.Type.ToString().Length); int stateSize = ranges.Max(r => r.State.ToString().Length); @@ -120,8 +124,46 @@ orderby Size descending } - // Print summary table unconditionally + if (List is not null) { + // Print a list of the specified memory regions, ordered by size descending. + + string[] requested = List.Split(new char[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries); + foreach (string kind in requested) + { + if (!ranges.Any(r => r.Name.Equals(kind, StringComparison.OrdinalIgnoreCase))) + { + Console.WriteLineError($"No memory regions match '{kind}'."); + } + else + { + Console.WriteLine($"{kind} Memory Regions:"); + + TableOutput output = new(Console, (16, "x12"), (16, "n0"), (8, ""), (12, ""), (12, "")); + output.WriteRow("Base Address", "Size (bytes)", "Size", "Mem State", "Mem Type", "Mem Protect"); + + ulong totalSize = 0; + int count = 0; + + IEnumerable matching = ranges.Where(r => r.Name.Equals(kind, StringComparison.OrdinalIgnoreCase)).OrderByDescending(s => s.Size); + foreach (DescribedRegion region in matching) + { + output.WriteRow(region.Start, region.Size, region.Size.ConvertToHumanReadable(), region.State, region.Type, region.Protection); + + count++; + totalSize += region.Size; + } + + Console.WriteLine($"{totalSize:n0} bytes ({totalSize.ConvertToHumanReadable()}) in {count:n0} regions"); + Console.WriteLine(); + } + } + } + + if (List is null || Summary) + { + // Show the summary table in almost every case, unless the user specified -list without -summary. + var grouped = from mem in ranges let name = mem.Name group mem by name into g @@ -192,6 +234,10 @@ Include reserved memory (MEM_RESERVE) in the output. This is usually only that reserve region HeapReserve. Note that this is a heuristic and NOT intended to be completely accurate. This can be useful to try to figure out what is creating large amount of MEM_RESERVE regions. + + {ListFlag} + A separated list of region types (as maddress defines them) to print the base + addresses and sizes of. This list may be separated by , or ""in quotes"". "); } } diff --git a/src/Microsoft.Diagnostics.ExtensionCommands/NativeAddressHelper.cs b/src/Microsoft.Diagnostics.ExtensionCommands/NativeAddressHelper.cs index 9d6f5f02e7..8a2c03cfff 100644 --- a/src/Microsoft.Diagnostics.ExtensionCommands/NativeAddressHelper.cs +++ b/src/Microsoft.Diagnostics.ExtensionCommands/NativeAddressHelper.cs @@ -15,6 +15,8 @@ namespace Microsoft.Diagnostics.ExtensionCommands [ServiceExport(Scope = ServiceScope.Target)] public sealed class NativeAddressHelper { + private ((bool, bool, bool, bool) Key, DescribedRegion[] Result) _previous; + [ServiceImport] public ITarget Target { get; set; } @@ -58,8 +60,27 @@ public sealed class NativeAddressHelper /// If !address fails we will throw InvalidOperationException. This is usually /// because symbols for ntdll couldn't be found. /// An enumerable of memory ranges. - internal IEnumerable EnumerateAddressSpace(bool tagClrMemoryRanges, bool includeReserveMemory, bool tagReserveMemoryHeuristically, bool includeHandleTableIfSlow) + public IEnumerable EnumerateAddressSpace(bool tagClrMemoryRanges, bool includeReserveMemory, bool tagReserveMemoryHeuristically, bool includeHandleTableIfSlow) + { + (bool, bool, bool, bool) key = (tagClrMemoryRanges, includeReserveMemory, tagReserveMemoryHeuristically, includeHandleTableIfSlow); + + if (_previous.Result is not null && _previous.Key == key) + { + return _previous.Result; + } + + DescribedRegion[] result = EnumerateAddressSpaceWorker(tagClrMemoryRanges, includeReserveMemory, tagReserveMemoryHeuristically, includeHandleTableIfSlow); + _previous = (key, result); + + // Use AsReadOnly to ensure no modifications to the cached value + return Array.AsReadOnly(result); + } + + private DescribedRegion[] EnumerateAddressSpaceWorker(bool tagClrMemoryRanges, bool includeReserveMemory, bool tagReserveMemoryHeuristically, bool includeHandleTableIfSlow) { + Console.WriteLineWarning("Enumerating and tagging the entire address space and caching the result..."); + Console.WriteLineWarning("Subsequent runs of this command should be faster."); + bool printedTruncatedWarning = false; IEnumerable addressResult = from region in MemoryRegionService.EnumerateRegions() @@ -90,9 +111,9 @@ internal IEnumerable EnumerateAddressSpace(bool tagClrMemoryRan if (!printedTruncatedWarning) { - Console.WriteLine($"Warning: Could not find a memory range for {mem.Address:x} - {mem.Kind}."); - Console.WriteLine($"This crash dump may not be a full dump!"); - Console.WriteLine(""); + Console.WriteLineWarning($"Warning: Could not find a memory range for {mem.Address:x} - {mem.Kind}."); + Console.WriteLineWarning($"This crash dump may not be a full dump!"); + Console.WriteLineWarning(""); printedTruncatedWarning = true; } @@ -477,7 +498,7 @@ public enum ClrMemoryKind HandleTable, } - internal sealed class DescribedRegion : IMemoryRegion + public sealed class DescribedRegion : IMemoryRegion { public DescribedRegion() { From 1a7cbc277e7107aa1151a648f1e93a716f543346 Mon Sep 17 00:00:00 2001 From: Lee Culver Date: Tue, 4 Apr 2023 09:06:28 -0700 Subject: [PATCH 002/111] Add !dumpheap fragmentation statistics (#3799) In my previous !dumpheap change I overlooked the fragmentation output. This adds fragmentation output in the exact same was as the previous C++ code. The new code now validates the Free region is actually followed by the next object, and that those objects do not live on the Pinned, Frozen, or Large object heaps. --- .../DumpHeapCommand.cs | 7 ++- .../DumpHeapService.cs | 62 +++++++++++++++++-- .../NotReachableInRangeCommand.cs | 2 +- .../ObjSizeCommand.cs | 2 +- src/SOS/Strike/strike.cpp | 1 - 5 files changed, 66 insertions(+), 8 deletions(-) diff --git a/src/Microsoft.Diagnostics.ExtensionCommands/DumpHeapCommand.cs b/src/Microsoft.Diagnostics.ExtensionCommands/DumpHeapCommand.cs index 4ba19ae1cf..c62435f1d3 100644 --- a/src/Microsoft.Diagnostics.ExtensionCommands/DumpHeapCommand.cs +++ b/src/Microsoft.Diagnostics.ExtensionCommands/DumpHeapCommand.cs @@ -128,6 +128,7 @@ public override void Invoke() }); } + bool printFragmentation = false; DumpHeapService.DisplayKind displayKind = DumpHeapService.DisplayKind.Normal; if (ThinLock) { @@ -141,8 +142,12 @@ public override void Invoke() { displayKind = DumpHeapService.DisplayKind.Short; } + else + { + printFragmentation = true; + } - DumpHeap.PrintHeap(objectsToPrint, displayKind, StatOnly); + DumpHeap.PrintHeap(objectsToPrint, displayKind, StatOnly, printFragmentation); } private void ParseArguments() diff --git a/src/Microsoft.Diagnostics.ExtensionCommands/DumpHeapService.cs b/src/Microsoft.Diagnostics.ExtensionCommands/DumpHeapService.cs index 8de3862967..f9687f8f33 100644 --- a/src/Microsoft.Diagnostics.ExtensionCommands/DumpHeapService.cs +++ b/src/Microsoft.Diagnostics.ExtensionCommands/DumpHeapService.cs @@ -18,6 +18,7 @@ namespace Microsoft.Diagnostics.ExtensionCommands [ServiceExport(Scope = ServiceScope.Runtime)] public class DumpHeapService { + private const ulong FragmentationBlockMinSize = 512 * 1024; private const char StringReplacementCharacter = '.'; [ServiceImport] @@ -34,8 +35,12 @@ public enum DisplayKind Strings } - public void PrintHeap(IEnumerable objects, DisplayKind displayKind, bool statsOnly) + public void PrintHeap(IEnumerable objects, DisplayKind displayKind, bool statsOnly, bool printFragmentation) { + List<(ClrObject Free, ClrObject Next)> fragmentation = null; + Dictionary<(string String, ulong Size), uint> stringTable = null; + Dictionary stats = new(); + TableOutput thinLockOutput = null; TableOutput objectTable = new(Console, (12, "x12"), (12, "x12"), (12, ""), (0, "")); if (!statsOnly && (displayKind is DisplayKind.Normal or DisplayKind.Strings)) @@ -43,9 +48,7 @@ public void PrintHeap(IEnumerable objects, DisplayKind displayKind, b objectTable.WriteRow("Address", "MT", "Size"); } - Dictionary stats = new(); - Dictionary<(string String, ulong Size), uint> stringTable = null; - + ClrObject lastFreeObject = default; foreach (ClrObject obj in objects) { if (displayKind == DisplayKind.ThinLock) @@ -77,6 +80,35 @@ public void PrintHeap(IEnumerable objects, DisplayKind displayKind, b objectTable.WriteRow(new DmlDumpObj(obj), new DmlDumpHeap(obj.Type?.MethodTable ?? 0), size, obj.IsFree ? "Free" : ""); } + if (printFragmentation) + { + if (lastFreeObject.IsFree && obj.IsValid && !obj.IsFree) + { + // Check to see if the previous object lands directly before this one. We don't want + // to print fragmentation after changing segments, or after an allocation context. + if (lastFreeObject.Address + lastFreeObject.Size == obj.Address) + { + // Also, don't report fragmentation for Large/Pinned/Frozen segments. This check + // is a little slow, so we do this last. + ClrSegment seg = obj.Type.Heap.GetSegmentByAddress(obj); + if (seg is not null && seg.Kind is not GCSegmentKind.Large or GCSegmentKind.Pinned or GCSegmentKind.Frozen) + { + fragmentation ??= new(); + fragmentation.Add((lastFreeObject, obj)); + } + } + } + + if (obj.IsFree && size >= FragmentationBlockMinSize) + { + lastFreeObject = obj; + } + else + { + lastFreeObject = default; + } + } + if (displayKind == DisplayKind.Strings) { // We only read a maximum of 1024 characters for each string. This may lead to some collisions if strings are unique @@ -198,6 +230,28 @@ orderby Size Console.WriteLine($"Total {stats.Values.Sum(r => r.Count):n0} objects, {stats.Values.Sum(r => (long)r.Size):n0} bytes"); } } + + // Print fragmentation if we calculated it + PrintFragmentation(fragmentation); + } + + private void PrintFragmentation(List<(ClrObject Free, ClrObject Next)> fragmentation) + { + if (fragmentation is null || fragmentation.Count == 0) + { + return; + } + + TableOutput output = new(Console, (16, "x12"), (12, "n0"), (16, "x12")); + + Console.WriteLine(); + Console.WriteLine("Fragmented blocks larger than 0.5 MB:"); + output.WriteRow("Address", "Size", "Followed By"); + + foreach ((ClrObject free, ClrObject next) in fragmentation) + { + output.WriteRow(free.Address, free.Size, new DmlDumpObj(next.Address), next.Type?.Name ?? ""); + } } private string Sanitize(string str, int maxLen) diff --git a/src/Microsoft.Diagnostics.ExtensionCommands/NotReachableInRangeCommand.cs b/src/Microsoft.Diagnostics.ExtensionCommands/NotReachableInRangeCommand.cs index 55ed214c4a..59e399e303 100644 --- a/src/Microsoft.Diagnostics.ExtensionCommands/NotReachableInRangeCommand.cs +++ b/src/Microsoft.Diagnostics.ExtensionCommands/NotReachableInRangeCommand.cs @@ -62,7 +62,7 @@ public override void Invoke() ulong curr = start; IEnumerable liveObjs = EnumerateLiveObjectsInRange(end, curr); - DumpHeap.PrintHeap(liveObjs, Short ? DumpHeapService.DisplayKind.Short : DumpHeapService.DisplayKind.Normal, statsOnly: false); + DumpHeap.PrintHeap(liveObjs, Short ? DumpHeapService.DisplayKind.Short : DumpHeapService.DisplayKind.Normal, statsOnly: false, printFragmentation: false); } private IEnumerable EnumerateLiveObjectsInRange(ulong end, ulong curr) diff --git a/src/Microsoft.Diagnostics.ExtensionCommands/ObjSizeCommand.cs b/src/Microsoft.Diagnostics.ExtensionCommands/ObjSizeCommand.cs index 71b08ed536..0beb0e98f0 100644 --- a/src/Microsoft.Diagnostics.ExtensionCommands/ObjSizeCommand.cs +++ b/src/Microsoft.Diagnostics.ExtensionCommands/ObjSizeCommand.cs @@ -49,7 +49,7 @@ public override void Invoke() Console.WriteLine(); DumpHeapService.DisplayKind displayKind = Strings ? DumpHeapService.DisplayKind.Strings : DumpHeapService.DisplayKind.Normal; - DumpHeap.PrintHeap(GetTransitiveClosure(obj), displayKind, Stat); + DumpHeap.PrintHeap(GetTransitiveClosure(obj), displayKind, Stat, printFragmentation: false); } private static IEnumerable GetTransitiveClosure(ClrObject obj) diff --git a/src/SOS/Strike/strike.cpp b/src/SOS/Strike/strike.cpp index f7715c32fa..e1470e45b0 100644 --- a/src/SOS/Strike/strike.cpp +++ b/src/SOS/Strike/strike.cpp @@ -3833,7 +3833,6 @@ DECLARE_API(DumpRuntimeTypes) return Status; } -#define MIN_FRAGMENTATIONBLOCK_BYTES (1024*512) namespace sos { class FragmentationBlock From e8536be55f56ccbd93eb59a96057dee171d207c2 Mon Sep 17 00:00:00 2001 From: Lee Culver Date: Tue, 4 Apr 2023 12:37:05 -0700 Subject: [PATCH 003/111] Fix IndexOutOfRangeException (#3800) * Fix IndexOutOfRangeException Fix an IndexOutOfRangeException with !sos maddress. * Add initial parts length check * One more fix --- ...MemoryRegionServiceFromDebuggerServices.cs | 36 +++++++++++++++---- 1 file changed, 30 insertions(+), 6 deletions(-) diff --git a/src/SOS/SOS.Extensions/MemoryRegionServiceFromDebuggerServices.cs b/src/SOS/SOS.Extensions/MemoryRegionServiceFromDebuggerServices.cs index 7b60998623..15c729c1df 100644 --- a/src/SOS/SOS.Extensions/MemoryRegionServiceFromDebuggerServices.cs +++ b/src/SOS/SOS.Extensions/MemoryRegionServiceFromDebuggerServices.cs @@ -56,16 +56,28 @@ public IEnumerable EnumerateRegions() else { string[] parts = ((line[0] == '+') ? line.Substring(1) : line).Split(new char[] { ' ' }, 6, StringSplitOptions.RemoveEmptyEntries); - ulong start = ulong.Parse(parts[0].Replace("`", ""), System.Globalization.NumberStyles.HexNumber); - ulong end = ulong.Parse(parts[1].Replace("`", ""), System.Globalization.NumberStyles.HexNumber); + if (parts.Length < 2) + { + continue; + } + + if (!ulong.TryParse(parts[0].Replace("`", ""), System.Globalization.NumberStyles.HexNumber, null, out ulong start)) + { + continue; + } + + if (!ulong.TryParse(parts[1].Replace("`", ""), System.Globalization.NumberStyles.HexNumber, null, out ulong end)) + { + continue; + } int index = 3; - if (Enum.TryParse(parts[index], ignoreCase: true, out MemoryRegionType type)) + if (GetEnumValue(parts, index, out MemoryRegionType type)) { index++; } - if (Enum.TryParse(parts[index], ignoreCase: true, out MemoryRegionState state)) + if (GetEnumValue(parts, index, out MemoryRegionState state)) { index++; } @@ -103,7 +115,7 @@ public IEnumerable EnumerateRegions() index++; } - string description = parts[index++].Trim(); + string description = index < parts.Length ? parts[index++].Trim() : ""; // On Linux, !address is reporting this as MEM_PRIVATE or MEM_UNKNOWN if (description == "Image") @@ -119,7 +131,7 @@ public IEnumerable EnumerateRegions() } string image = null; - if (type == MemoryRegionType.MEM_IMAGE) + if (type == MemoryRegionType.MEM_IMAGE && index < parts.Length) { image = parts[index].Substring(1, parts[index].Length - 2); index++; @@ -187,6 +199,18 @@ public IEnumerable EnumerateRegions() } } + private static bool GetEnumValue(string[] parts, int index, out T type) + where T : struct + { + if (index < parts.Length) + { + return Enum.TryParse(parts[index], ignoreCase: true, out type); + } + + type = default; + return false; + } + private (int hresult, string output) RunCommandWithOutput(string command) { using DbgEngOutputHolder dbgengOutput = new(_client); From 770823e3480788bfe3fafeabf0ecf8809366db7b Mon Sep 17 00:00:00 2001 From: Lee Culver Date: Wed, 5 Apr 2023 11:19:23 -0700 Subject: [PATCH 004/111] maddress -orderBySize (#3803) Added an option to order the output of !maddress by size descending, as requested by the GC team. --- .../MAddressCommand.cs | 25 +++++++++++++------ 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/src/Microsoft.Diagnostics.ExtensionCommands/MAddressCommand.cs b/src/Microsoft.Diagnostics.ExtensionCommands/MAddressCommand.cs index 7e59762b94..b57f14f2c1 100644 --- a/src/Microsoft.Diagnostics.ExtensionCommands/MAddressCommand.cs +++ b/src/Microsoft.Diagnostics.ExtensionCommands/MAddressCommand.cs @@ -18,6 +18,7 @@ public sealed class MAddressCommand : CommandBase private const string ReserveHeuristicFlag = "-reserveHeuristic"; private const string ForceHandleTableFlag = "-forceHandleTable"; private const string ListFlag = "-list"; + private const string BySizeFlag = "-orderBySize"; [Option(Name = SummaryFlag, Aliases = new string[] { "-stat", }, Help = "Only print summary table.")] public bool Summary { get; set; } @@ -34,7 +35,10 @@ public sealed class MAddressCommand : CommandBase [Option(Name = ForceHandleTableFlag, Help = "We only tag the HandleTable if we can do so efficiently on newer runtimes. This option ensures we always tag HandleTable memory, even if it will take a long time.")] public bool IncludeHandleTableIfSlow { get; set; } - [Option(Name = ListFlag, Help = "A separated list of regions to list allocations for.")] + [Option(Name = BySizeFlag, Help = "List the raw addresses by size, not by base address.")] + public bool BySize { get; set; } + + [Option(Name = ListFlag, Help = "A separated list of memory regions to list allocations for.")] public string List { get; set; } [ServiceImport] @@ -76,7 +80,8 @@ public override void Invoke() }; output.WriteRowWithSpacing('-', "Memory Kind", "StartAddr", "EndAddr-1", "Size", "Type", "State", "Protect", "Image"); - foreach (DescribedRegion mem in ranges) + IOrderedEnumerable ordered = BySize ? ranges.OrderByDescending(r => r.Size).ThenBy(r => r.Start) : ranges.OrderBy(r => r.Start); + foreach (DescribedRegion mem in ordered) { Console.CancellationToken.ThrowIfCancellationRequested(); @@ -105,7 +110,7 @@ orderby Size descending Divider = " | " }; - output.WriteRowWithSpacing('-', "Image", "Regions", "Size", "Size (bytes)"); + output.WriteRowWithSpacing('-', "Image", "Count", "Size", "Size (bytes)"); int count = 0; long size = 0; @@ -126,7 +131,7 @@ orderby Size descending if (List is not null) { - // Print a list of the specified memory regions, ordered by size descending. + // Print a list of the specified memory kind, ordered by size descending. string[] requested = List.Split(new char[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries); foreach (string kind in requested) @@ -154,7 +159,7 @@ orderby Size descending totalSize += region.Size; } - Console.WriteLine($"{totalSize:n0} bytes ({totalSize.ConvertToHumanReadable()}) in {count:n0} regions"); + Console.WriteLine($"{totalSize:n0} bytes ({totalSize.ConvertToHumanReadable()}) in {count:n0} memory regions"); Console.WriteLine(); } } @@ -181,7 +186,7 @@ orderby Size descending Divider = " | " }; - output.WriteRowWithSpacing('-', "Region Type", "Count", "Size", "Size (bytes)"); + output.WriteRowWithSpacing('-', "Memory Type", "Count", "Size", "Size (bytes)"); int count = 0; long size = 0; @@ -212,7 +217,7 @@ with information about CLR's heaps. Flags: {SummaryFlag} - Show only a summary table of memory regions and not the list of every address region. + Show only a summary table of memory regions and not the list of every memory region. {ImagesFlag} Summarizes the memory ranges consumed by images in the process. @@ -236,8 +241,12 @@ intended to be completely accurate. This can be useful to try to figure out what is creating large amount of MEM_RESERVE regions. {ListFlag} - A separated list of region types (as maddress defines them) to print the base + A separated list of memory region types (as maddress defines them) to print the base addresses and sizes of. This list may be separated by , or ""in quotes"". + + {BySizeFlag} + Order the list of memory blocks by size (descending) when printing the list + of all memory blocks instead of by address. "); } } From 7029b45e619037bf4becddb6663ceab6ddfb9879 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Thu, 6 Apr 2023 15:56:31 +0000 Subject: [PATCH 005/111] [main] Update dependencies from dotnet/source-build-reference-packages (#3787) [main] Update dependencies from dotnet/source-build-reference-packages --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 7f8369c2f7..badddd4196 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -47,9 +47,9 @@ https://github.com/dotnet/runtime a64420c79cb63c485138f4f1352b8730f27d7b19 - + https://github.com/dotnet/source-build-reference-packages - dc842f8fab4bd38db9334a312a990d198b971fc2 + 09c4d8e93c5b78897bccb4f27e0c373647fb3985 diff --git a/eng/Versions.props b/eng/Versions.props index 143aad16b7..e829665383 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -68,7 +68,7 @@ 7.0.0-beta.22316.2 10.0.18362 13.0.1 - 8.0.0-alpha.1.23178.3 + 8.0.0-alpha.1.23205.5 1.2.0-beta-23165-02 From dfc285c42bfd39b9c37eae441661637a981ca698 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Thu, 6 Apr 2023 16:34:02 +0000 Subject: [PATCH 006/111] Update dependencies from https://github.com/dotnet/aspnetcore build 20230406.4 (#3807) [main] Update dependencies from dotnet/aspnetcore --- eng/Version.Details.xml | 8 ++++---- eng/Versions.props | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index badddd4196..c3a99f987a 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -31,13 +31,13 @@ https://github.com/dotnet/installer 51e06f6931e859f56564556fa6ba519761fa7141 - + https://github.com/dotnet/aspnetcore - c0acf059eddd7e70498804dcc99a7c7b33732417 + 5d65ee05af31b5a6a0e4faec09e7501b474a997a - + https://github.com/dotnet/aspnetcore - c0acf059eddd7e70498804dcc99a7c7b33732417 + 5d65ee05af31b5a6a0e4faec09e7501b474a997a https://github.com/dotnet/runtime diff --git a/eng/Versions.props b/eng/Versions.props index e829665383..a9e72015cf 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -21,8 +21,8 @@ 8.0.0-preview.3.23155.1 8.0.0-preview.3.23155.1 - 8.0.0-preview.4.23179.5 - 8.0.0-preview.4.23179.5 + 8.0.0-preview.4.23206.4 + 8.0.0-preview.4.23206.4 8.0.100-preview.3.23156.1 From 3bd1eff057442ba320963ae78d8ed048de9461d6 Mon Sep 17 00:00:00 2001 From: Lee Culver Date: Thu, 6 Apr 2023 17:21:23 -0700 Subject: [PATCH 007/111] Update ClrMD version (#3804) I moved the the "Generation" enum to ClrMD itself. It's far more useful (and accurate) to talk about an object's generation as a member of an enum which describes it rather than a simple integer. This change flowed through the SOS commands which used ClrSegment.GetGeneration. I manually tested all commands affected. --- eng/Version.Details.xml | 8 ++-- eng/Versions.props | 2 +- .../ExtensionMethodHelpers.cs | 34 -------------- .../FindEphemeralReferencesToLOHCommand.cs | 21 ++++++--- .../FindReferencesToEphemeralCommand.cs | 13 +++--- .../GCHeapStatCommand.cs | 45 ++++++++++++------- .../GCWhereCommand.cs | 24 +++++----- .../Generation.cs | 16 ------- .../SizeStatsCommand.cs | 22 ++++----- 9 files changed, 76 insertions(+), 109 deletions(-) delete mode 100644 src/Microsoft.Diagnostics.ExtensionCommands/Generation.cs diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index c3a99f987a..74f2539ede 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -4,13 +4,13 @@ https://github.com/dotnet/symstore e09f81a0b38786cb20f66b589a8b88b6997a62da - + https://github.com/microsoft/clrmd - e61e6bdb23739ad2c59616b6c8d6659f4558c88d + 3368bf4451a9441076595022fdff0f2bbea57b1b - + https://github.com/microsoft/clrmd - e61e6bdb23739ad2c59616b6c8d6659f4558c88d + 3368bf4451a9441076595022fdff0f2bbea57b1b diff --git a/eng/Versions.props b/eng/Versions.props index a9e72015cf..9fad78388e 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -45,7 +45,7 @@ 5.0.0 1.1.0 - 3.0.0-beta.23177.1 + 3.0.0-beta.23205.1 16.9.0-beta1.21055.5 3.0.7 diff --git a/src/Microsoft.Diagnostics.ExtensionCommands/ExtensionMethodHelpers.cs b/src/Microsoft.Diagnostics.ExtensionCommands/ExtensionMethodHelpers.cs index 15f81d59ff..5f35b39381 100644 --- a/src/Microsoft.Diagnostics.ExtensionCommands/ExtensionMethodHelpers.cs +++ b/src/Microsoft.Diagnostics.ExtensionCommands/ExtensionMethodHelpers.cs @@ -37,39 +37,5 @@ internal static ulong FindMostCommonPointer(this IEnumerable enumerable) group ptr by ptr into g orderby g.Count() descending select g.First()).First(); - - internal static Generation GetGeneration(this ClrObject obj, ClrSegment knownSegment) - { - if (knownSegment is null) - { - knownSegment = obj.Type.Heap.GetSegmentByAddress(obj); - if (knownSegment is null) - { - return Generation.Error; - } - } - - if (knownSegment.Kind == GCSegmentKind.Ephemeral) - { - return knownSegment.GetGeneration(obj) switch - { - 0 => Generation.Gen0, - 1 => Generation.Gen1, - 2 => Generation.Gen2, - _ => Generation.Error - }; - } - - return knownSegment.Kind switch - { - GCSegmentKind.Generation0 => Generation.Gen0, - GCSegmentKind.Generation1 => Generation.Gen1, - GCSegmentKind.Generation2 => Generation.Gen2, - GCSegmentKind.Large => Generation.Large, - GCSegmentKind.Pinned => Generation.Pinned, - GCSegmentKind.Frozen => Generation.Frozen, - _ => Generation.Error - }; - } } } diff --git a/src/Microsoft.Diagnostics.ExtensionCommands/FindEphemeralReferencesToLOHCommand.cs b/src/Microsoft.Diagnostics.ExtensionCommands/FindEphemeralReferencesToLOHCommand.cs index d28166badb..c7fa399b83 100644 --- a/src/Microsoft.Diagnostics.ExtensionCommands/FindEphemeralReferencesToLOHCommand.cs +++ b/src/Microsoft.Diagnostics.ExtensionCommands/FindEphemeralReferencesToLOHCommand.cs @@ -130,8 +130,8 @@ public override void Invoke() Console.CancellationToken.ThrowIfCancellationRequested(); // This handles both regions and segments - Generation gen = obj.GetGeneration(seg); - if (gen is not Generation.Gen0 or Generation.Gen1) + Generation gen = seg.GetGeneration(obj); + if (gen is not Generation.Generation0 or Generation.Generation1) { continue; } @@ -145,8 +145,7 @@ public override void Invoke() continue; } - Generation refGen = objRef.GetGeneration(null); - if (refGen == Generation.Large) + if (GetGenerationWithoutSegment(objRef) == Generation.Large) { yield return (obj, objRef); } @@ -174,8 +173,7 @@ public override void Invoke() continue; } - Generation refGen = objRef.GetGeneration(null); - if (refGen is Generation.Gen0 or Generation.Gen1) + if (GetGenerationWithoutSegment(objRef) is Generation.Generation0 or Generation.Generation1) { yield return (obj, objRef); } @@ -183,5 +181,16 @@ public override void Invoke() } } } + + private Generation GetGenerationWithoutSegment(ClrObject obj) + { + ClrSegment seg = Runtime.Heap.GetSegmentByAddress(obj); + if (seg is not null) + { + return seg.GetGeneration(obj); + } + + return Generation.Unknown; + } } } diff --git a/src/Microsoft.Diagnostics.ExtensionCommands/FindReferencesToEphemeralCommand.cs b/src/Microsoft.Diagnostics.ExtensionCommands/FindReferencesToEphemeralCommand.cs index e77660dbd1..8c5f3c0eac 100644 --- a/src/Microsoft.Diagnostics.ExtensionCommands/FindReferencesToEphemeralCommand.cs +++ b/src/Microsoft.Diagnostics.ExtensionCommands/FindReferencesToEphemeralCommand.cs @@ -88,8 +88,8 @@ private IEnumerable FindObjectsWithEphemeralReferences() Console.CancellationToken.ThrowIfCancellationRequested(); // Skip this object if it's gen0 or we hit an error - Generation objGen = obj.GetGeneration(seg); - if (objGen is Generation.Gen0 or Generation.Error) + Generation objGen = seg.GetGeneration(obj); + if (objGen is Generation.Generation0 or Generation.Unknown) { continue; } @@ -108,10 +108,11 @@ private IEnumerable FindObjectsWithEphemeralReferences() ulong refObjSize = objRef.Size; - Generation refGen = objRef.GetGeneration(null); + ClrSegment refSeg = Runtime.Heap.GetSegmentByAddress(objRef); + Generation refGen = refSeg?.GetGeneration(objRef) ?? Generation.Unknown; switch (refGen) { - case Generation.Gen0: + case Generation.Generation0: gen0 ??= new EphemeralRefCount() { Object = obj, @@ -128,8 +129,8 @@ private IEnumerable FindObjectsWithEphemeralReferences() break; - case Generation.Gen1: - if (objGen > Generation.Gen1) + case Generation.Generation1: + if (objGen > Generation.Generation1) { gen1 ??= new EphemeralRefCount() { diff --git a/src/Microsoft.Diagnostics.ExtensionCommands/GCHeapStatCommand.cs b/src/Microsoft.Diagnostics.ExtensionCommands/GCHeapStatCommand.cs index 062eb694b9..a7c24db50a 100644 --- a/src/Microsoft.Diagnostics.ExtensionCommands/GCHeapStatCommand.cs +++ b/src/Microsoft.Diagnostics.ExtensionCommands/GCHeapStatCommand.cs @@ -217,25 +217,22 @@ private HeapInfo GetHeapInfo(ClrSubHeap heap) continue; } - GenerationInfo gen = seg.GetGeneration(obj) switch + GenerationInfo genInfo = result.GetInfoByGeneration(seg.GetGeneration(obj)); + if (genInfo is not null) { - 0 => result.Gen0, - 1 => result.Gen1, - _ => result.Gen2, - }; - - if (obj.IsFree) - { - result.Ephemeral.Free += obj.Size; - gen.Free += obj.Size; - } - else - { - gen.Allocated += obj.Size; - - if (IncludeUnreachable && !LiveObjects.IsLive(obj)) + if (obj.IsFree) + { + result.Ephemeral.Free += obj.Size; + genInfo.Free += obj.Size; + } + else { - gen.Unrooted += obj.Size; + genInfo.Allocated += obj.Size; + + if (IncludeUnreachable && !LiveObjects.IsLive(obj)) + { + genInfo.Unrooted += obj.Size; + } } } } @@ -307,6 +304,20 @@ private sealed class HeapInfo Frozen = left.Frozen + right.Frozen, }; } + + public GenerationInfo GetInfoByGeneration(Generation gen) + { + return gen switch + { + Generation.Generation0 => Gen0, + Generation.Generation1 => Gen1, + Generation.Generation2 => Gen2, + Generation.Large => LoH, + Generation.Pinned => PoH, + Generation.Frozen => Frozen, + _ => null + }; + } } private sealed class GenerationInfo diff --git a/src/Microsoft.Diagnostics.ExtensionCommands/GCWhereCommand.cs b/src/Microsoft.Diagnostics.ExtensionCommands/GCWhereCommand.cs index 3967c4bb32..fad8d35df1 100644 --- a/src/Microsoft.Diagnostics.ExtensionCommands/GCWhereCommand.cs +++ b/src/Microsoft.Diagnostics.ExtensionCommands/GCWhereCommand.cs @@ -54,22 +54,18 @@ public override void Invoke() { generation = "reserve"; } - else if (segment.Kind == GCSegmentKind.Frozen) - { - generation = "frozen"; - } - else if (segment.Kind == GCSegmentKind.Pinned) - { - generation = "pinned"; - } - else if (segment.Kind == GCSegmentKind.Large) - { - generation = "large"; - } else { - int gen = segment.GetGeneration(address); - generation = gen != -1 ? gen.ToString() : "???"; + generation = segment.GetGeneration(address) switch + { + Generation.Generation0 => "0", + Generation.Generation1 => "1", + Generation.Generation2 => "2", + Generation.Frozen => "frozen", + Generation.Pinned => "pinned", + Generation.Large => "large", + _ => "???", + }; } object addressColumn = segment.ObjectRange.Contains(address) ? new DmlListNearObj(address) : address; diff --git a/src/Microsoft.Diagnostics.ExtensionCommands/Generation.cs b/src/Microsoft.Diagnostics.ExtensionCommands/Generation.cs deleted file mode 100644 index 990ef71a2d..0000000000 --- a/src/Microsoft.Diagnostics.ExtensionCommands/Generation.cs +++ /dev/null @@ -1,16 +0,0 @@ -// 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.ExtensionCommands -{ - internal enum Generation - { - Gen0, - Gen1, - Gen2, - Large, - Pinned, - Frozen, - Error, - } -} diff --git a/src/Microsoft.Diagnostics.ExtensionCommands/SizeStatsCommand.cs b/src/Microsoft.Diagnostics.ExtensionCommands/SizeStatsCommand.cs index 61e88f7a37..5208edaa48 100644 --- a/src/Microsoft.Diagnostics.ExtensionCommands/SizeStatsCommand.cs +++ b/src/Microsoft.Diagnostics.ExtensionCommands/SizeStatsCommand.cs @@ -16,9 +16,9 @@ public sealed class SizeStatsCommand : CommandBase public override void Invoke() { - SizeStats(Generation.Gen0, isFree: false); - SizeStats(Generation.Gen1, isFree: false); - SizeStats(Generation.Gen2, isFree: false); + SizeStats(Generation.Generation0, isFree: false); + SizeStats(Generation.Generation1, isFree: false); + SizeStats(Generation.Generation2, isFree: false); SizeStats(Generation.Large, isFree: false); bool hasPinned = Runtime.Heap.Segments.Any(seg => seg.Kind == GCSegmentKind.Pinned); @@ -32,9 +32,9 @@ public override void Invoke() SizeStats(Generation.Frozen, isFree: false); } - SizeStats(Generation.Gen0, isFree: true); - SizeStats(Generation.Gen1, isFree: true); - SizeStats(Generation.Gen2, isFree: true); + SizeStats(Generation.Generation0, isFree: true); + SizeStats(Generation.Generation1, isFree: true); + SizeStats(Generation.Generation2, isFree: true); SizeStats(Generation.Large, isFree: true); if (hasPinned) @@ -62,7 +62,7 @@ private void SizeStats(Generation requestedGen, bool isFree) // If Kind == Ephemeral, we have to further filter by object generation if (seg.Kind == GCSegmentKind.Ephemeral) { - if (obj.GetGeneration(seg) != requestedGen) + if (seg.GetGeneration(obj) != requestedGen) { continue; } @@ -104,10 +104,10 @@ private static bool FilterByGeneration(ClrSegment seg, Generation gen) { return seg.Kind switch { - GCSegmentKind.Ephemeral => gen <= Generation.Gen2, - GCSegmentKind.Generation0 => gen == Generation.Gen0, - GCSegmentKind.Generation1 => gen == Generation.Gen1, - GCSegmentKind.Generation2 => gen == Generation.Gen2, + GCSegmentKind.Ephemeral => gen <= Generation.Generation2, + GCSegmentKind.Generation0 => gen == Generation.Generation0, + GCSegmentKind.Generation1 => gen == Generation.Generation1, + GCSegmentKind.Generation2 => gen == Generation.Generation2, GCSegmentKind.Frozen => gen == Generation.Frozen, GCSegmentKind.Pinned => gen == Generation.Pinned, GCSegmentKind.Large => gen == Generation.Large, From 4e60167eba65c7c6f5b3afb403b01665f5dda668 Mon Sep 17 00:00:00 2001 From: Lee Culver Date: Mon, 10 Apr 2023 10:22:32 -0700 Subject: [PATCH 008/111] Reimplement !traverseheap (#3810) * Add TraverseHeapCommand * Remove HeapTraverser * Remove TypeTree * Remove Flags --- .../TraverseHeapCommand.cs | 163 +++++ src/SOS/SOS.Hosting/Commands/SOSCommand.cs | 1 - src/SOS/Strike/gcroot.cpp | 635 ------------------ src/SOS/Strike/strike.cpp | 75 +-- src/SOS/Strike/util.h | 124 ---- src/SOS/lldbplugin/soscommand.cpp | 1 - 6 files changed, 165 insertions(+), 834 deletions(-) create mode 100644 src/Microsoft.Diagnostics.ExtensionCommands/TraverseHeapCommand.cs diff --git a/src/Microsoft.Diagnostics.ExtensionCommands/TraverseHeapCommand.cs b/src/Microsoft.Diagnostics.ExtensionCommands/TraverseHeapCommand.cs new file mode 100644 index 0000000000..64647201a0 --- /dev/null +++ b/src/Microsoft.Diagnostics.ExtensionCommands/TraverseHeapCommand.cs @@ -0,0 +1,163 @@ +// 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.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Xml; +using Microsoft.Diagnostics.DebugServices; +using Microsoft.Diagnostics.Runtime; + +namespace Microsoft.Diagnostics.ExtensionCommands +{ + [Command(Name = "traverseheap", Help = "Writes out heap information to a file in a format understood by the CLR Profiler.")] + public class TraverseHeapCommand : CommandBase + { + [ServiceImport] + public ClrRuntime Runtime { get; set; } + + [ServiceImport] + public RootCacheService RootCache { get; set; } + + [Option(Name = "-xml")] + public bool Xml { get; set; } + + [Argument(Name = "filename")] + public string Filename { get; set; } + + public override void Invoke() + { + if (string.IsNullOrWhiteSpace(Filename)) + { + throw new ArgumentException($"Output filename cannot be empty.", nameof(Filename)); + } + + // create file early in case it throws + using StreamWriter output = File.CreateText(Filename); + using (XmlWriter xml = Xml ? XmlWriter.Create(output, new XmlWriterSettings() { Indent = true, OmitXmlDeclaration = true }) : null) + { + using StreamWriter text = Xml ? null : output; + + // must be called first to initialize types + (MemoryStream rootObjectStream, Dictionary types) = WriteRootsAndObjects(); + + xml?.WriteStartElement("gcheap"); + xml?.WriteStartElement("types"); + + foreach (KeyValuePair kv in types.OrderBy(kv => kv.Value)) + { + string name = kv.Key?.Name ?? $"error-reading-type-name:{kv.Key.MethodTable:x}"; + int typeId = kv.Value; + + xml?.WriteStartElement("type"); + xml?.WriteAttributeString("id", typeId.ToString()); + xml?.WriteAttributeString("name", name); + xml?.WriteEndElement(); + + text?.WriteLine($"t {typeId} 0 {name}"); + } + xml?.WriteEndElement(); + + xml?.Flush(); + text?.Flush(); + + output.WriteLine(); + output.Flush(); + + rootObjectStream.Position = 0; + rootObjectStream.CopyTo(output.BaseStream); + + xml?.WriteEndElement(); + } + } + + private (MemoryStream Stream, Dictionary Types) WriteRootsAndObjects() + { + Dictionary types = new(); + MemoryStream rootObjectStream = new(); + + using StreamWriter text = Xml ? null : new StreamWriter(rootObjectStream, Encoding.Default, 4096, leaveOpen: true); + using XmlWriter xml = Xml ? XmlWriter.Create(rootObjectStream, new XmlWriterSettings() + { + CloseOutput = false, + Indent = true, + OmitXmlDeclaration = true, + ConformanceLevel = ConformanceLevel.Fragment + }) : null; + + int currObj = 1; + int currType = 1; + + xml?.WriteStartElement("roots"); + text?.Write("r"); + foreach (ClrRoot root in RootCache.EnumerateRoots()) + { + string kind = root switch + { + ClrStackRoot => "stack", + ClrHandle => "handle", + _ => "finalizer" + }; + + xml?.WriteStartElement("root"); + xml?.WriteAttributeString("kind", kind); + xml?.WriteAttributeString("address", FormatHex(root.Address)); + xml?.WriteEndElement(); + + text?.Write(" "); + text?.Write(FormatHex(root.Address)); + } + xml?.WriteEndElement(); + text?.WriteLine(); + + xml?.WriteStartElement("objects"); + foreach (ClrObject obj in Runtime.Heap.EnumerateObjects()) + { + if (!obj.IsValid) + { + continue; + } + + ulong size = obj.Size; + int objId = currObj++; + if (!types.TryGetValue(obj.Type, out int typeId)) + { + typeId = types[obj.Type] = currType++; + } + + xml?.WriteStartElement("object"); + xml?.WriteAttributeString("address", FormatHex(obj.Address)); + xml?.WriteAttributeString("typeid", typeId.ToString()); + xml?.WriteAttributeString("size", size.ToString()); + + text?.WriteLine($"n {objId} 1 {typeId} {size}"); + text?.WriteLine($"! 1 {FormatHex(obj.Address)} {objId}"); + + text?.Write($"o {FormatHex(obj.Address)} {typeId} {size} "); // trailing space intentional + + if (obj.ContainsPointers) + { + foreach (ClrObject objRef in obj.EnumerateReferences(considerDependantHandles: true)) + { + xml?.WriteStartElement("member"); + xml?.WriteAttributeString("address", FormatHex(objRef.Address)); + xml?.WriteEndElement(); + + text?.Write($" "); + text?.Write(FormatHex(objRef.Address)); + } + } + + text?.WriteLine(); + xml?.WriteEndElement(); + } + xml?.WriteEndElement(); + + return (rootObjectStream, types); + } + + private static string FormatHex(ulong address) => $"0x{address:x16}"; + } +} diff --git a/src/SOS/SOS.Hosting/Commands/SOSCommand.cs b/src/SOS/SOS.Hosting/Commands/SOSCommand.cs index 8a126eed95..355ccc3116 100644 --- a/src/SOS/SOS.Hosting/Commands/SOSCommand.cs +++ b/src/SOS/SOS.Hosting/Commands/SOSCommand.cs @@ -50,7 +50,6 @@ namespace SOS.Hosting [Command(Name = "syncblk", DefaultOptions = "SyncBlk", Help = "Displays the SyncBlock holder info.")] [Command(Name = "threadpool", DefaultOptions = "ThreadPool", Help = "Lists basic information about the thread pool.")] [Command(Name = "threadstate", DefaultOptions = "ThreadState", Help = "Pretty prints the meaning of a threads state.")] - [Command(Name = "traverseheap", DefaultOptions = "TraverseHeap", Help = "Writes out heap information to a file in a format understood by the CLR Profiler.")] [Command(Name = "verifyobj", DefaultOptions = "VerifyObj", Help = "Checks the object for signs of corruption.")] [Command(Name = "comstate", DefaultOptions = "COMState", Flags = CommandFlags.Windows, Help = "Lists the COM apartment model for each thread.")] [Command(Name = "dumprcw", DefaultOptions = "DumpRCW", Flags = CommandFlags.Windows, Help = "Displays information about a Runtime Callable Wrapper.")] diff --git a/src/SOS/Strike/gcroot.cpp b/src/SOS/Strike/gcroot.cpp index d725339e5a..34df3bc577 100644 --- a/src/SOS/Strike/gcroot.cpp +++ b/src/SOS/Strike/gcroot.cpp @@ -96,76 +96,8 @@ bool LinearReadCache::MoveToPage(TADDR addr, unsigned int size) } -static const char *NameForHandle(unsigned int type) -{ - switch (type) - { - case 0: - return "weak short"; - case 1: - return "weak long"; - case 2: - return "strong"; - case 3: - return "pinned"; - case 5: - return "ref counted"; - case 6: - return "dependent"; - case 7: - return "async pinned"; - case 8: - return "sized ref"; - case 9: - return "weak WinRT"; - } - - return "unknown"; -} - /////////////////////////////////////////////////////////////////////////////// -void GetDependentHandleMap(std::unordered_map>& map) -{ - unsigned int type = HNDTYPE_DEPENDENT; - ToRelease handles; - - HRESULT hr = g_sos->GetHandleEnumForTypes(&type, 1, &handles); - - if (FAILED(hr)) - { - ExtOut("Failed to walk dependent handles. GCRoot may miss paths.\n"); - return; - } - - SOSHandleData data[4]; - unsigned int fetched = 0; - - do - { - hr = handles->Next(ARRAY_SIZE(data), data, &fetched); - - if (FAILED(hr)) - { - ExtOut("Error walking dependent handles. GCRoot may miss paths.\n"); - return; - } - - for (unsigned int i = 0; i < fetched; ++i) - { - if (data[i].Secondary != 0) - { - TADDR obj = 0; - TADDR target = TO_TADDR(data[i].Secondary); - - MOVE(obj, TO_TADDR(data[i].Handle)); - - map[obj].push_back(target); - } - } - } while (fetched == ARRAY_SIZE(data)); -} - UINT FindAllPinnedAndStrong(DWORD_PTR handlearray[], UINT arraySize) { unsigned int fetched = 0; @@ -610,573 +542,6 @@ BOOL VerifyObject(const GCHeapDetails &heap, DWORD_PTR objAddr, DWORD_PTR MTAddr return VerifyObject(heap, seg, objAddr, MTAddr, objSize, bVerifyMember); } -//////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////// -typedef void (*TYPETREEVISIT)(size_t methodTable, size_t ID, LPVOID token); - -// TODO remove this. MethodTableCache already maps method tables to -// various information. We don't need TypeTree to do this too. -// Straightfoward to do, but low priority. -class TypeTree -{ -private: - size_t methodTable; - size_t ID; - TypeTree *pLeft; - TypeTree *pRight; - -public: - TypeTree(size_t MT) : methodTable(MT),ID(0),pLeft(NULL),pRight(NULL) { } - - BOOL isIn(size_t MT, size_t *pID) - { - TypeTree *pCur = this; - - while (pCur) - { - if (MT == pCur->methodTable) - { - if (pID) - *pID = pCur->ID; - return TRUE; - } - else if (MT < pCur->methodTable) - pCur = pCur->pLeft; - else - pCur = pCur->pRight; - } - - return FALSE; - } - - BOOL insert(size_t MT) - { - TypeTree *pCur = this; - - while (pCur) - { - if (MT == pCur->methodTable) - return TRUE; - else if ((MT < pCur->methodTable)) - { - if (pCur->pLeft) - pCur = pCur->pLeft; - else - break; - } - else if (pCur->pRight) - pCur = pCur->pRight; - else - break; - } - - // If we got here, we need to append at the current node. - TypeTree *pNewNode = new TypeTree(MT); - if (pNewNode == NULL) - return FALSE; - - if (MT < pCur->methodTable) - pCur->pLeft = pNewNode; - else - pCur->pRight = pNewNode; - - return TRUE; - } - - static void destroy(TypeTree *pStart) - { - TypeTree *pCur = pStart; - - if (pCur) - { - destroy(pCur->pLeft); - destroy(pCur->pRight); - delete [] pCur; - } - } - - static void visit_inorder(TypeTree *pStart, TYPETREEVISIT pFunc, LPVOID token) - { - TypeTree *pCur = pStart; - - if (pCur) - { - visit_inorder(pCur->pLeft, pFunc, token); - pFunc (pCur->methodTable, pCur->ID, token); - visit_inorder(pCur->pRight, pFunc, token); - } - } - - static void setTypeIDs(TypeTree *pStart, size_t *pCurID) - { - TypeTree *pCur = pStart; - - if (pCur) - { - setTypeIDs(pCur->pLeft, pCurID); - pCur->ID = *pCurID; - (*pCurID)++; - setTypeIDs(pCur->pRight, pCurID); - } - } - -}; - -/////////////////////////////////////////////////////////////////////////////// -// - -HeapTraverser::HeapTraverser(bool verify) -{ - m_format = 0; - m_file = NULL; - m_objVisited = 0; - m_pTypeTree = NULL; - m_curNID = 1; - m_verify = verify; -} - -HeapTraverser::~HeapTraverser() -{ - if (m_pTypeTree) { - TypeTree::destroy(m_pTypeTree); - m_pTypeTree = NULL; - } -} - -BOOL HeapTraverser::Initialize() -{ - if (!GCHeapsTraverse (HeapTraverser::GatherTypes, this, m_verify)) - { - ExtOut("Error during heap traverse\n"); - return FALSE; - } - - GetDependentHandleMap(mDependentHandleMap); - - size_t startID = 1; - TypeTree::setTypeIDs(m_pTypeTree, &startID); - - return TRUE; -} - -BOOL HeapTraverser::CreateReport (FILE *fp, int format) -{ - if (fp == NULL || (format!=FORMAT_XML && format != FORMAT_CLRPROFILER)) - { - return FALSE; - } - - m_file = fp; - m_format = format; - - PrintSection(TYPE_START,TRUE); - - PrintSection(TYPE_TYPES,TRUE); - TypeTree::visit_inorder(m_pTypeTree, HeapTraverser::PrintOutTree, this); - PrintSection(TYPE_TYPES,FALSE); - - ExtOut("tracing roots...\n"); - PrintSection(TYPE_ROOTS,TRUE); - PrintRootHead(); - - TraceHandles(); - FindGCRootOnStacks(); - - PrintRootTail(); - PrintSection(TYPE_ROOTS,FALSE); - - // now print type tree - PrintSection(TYPE_OBJECTS,TRUE); - ExtOut("\nWalking heap...\n"); - m_objVisited = 0; // for UI updates - GCHeapsTraverse (HeapTraverser::PrintHeap, this, FALSE); // Never verify on the second pass - PrintSection(TYPE_OBJECTS,FALSE); - - PrintSection(TYPE_START,FALSE); - - m_file = NULL; - return TRUE; -} - -void HeapTraverser::insert(size_t mTable) -{ - if (m_pTypeTree == NULL) - { - m_pTypeTree = new TypeTree(mTable); - if (m_pTypeTree == NULL) - { - ReportOOM(); - return; - } - } - else - { - m_pTypeTree->insert(mTable); - } -} - -size_t HeapTraverser::getID(size_t mTable) -{ - if (m_pTypeTree == NULL) - { - return 0; - } - // IDs start at 1, so we can return 0 if not found. - size_t ret; - if (m_pTypeTree->isIn(mTable,&ret)) - { - return ret; - } - - return 0; -} - -void replace(std::string &str, const char* toReplace, const char* replaceWith) -{ - const size_t replaceLen = strlen(toReplace); - const size_t replaceWithLen = strlen(replaceWith); - - size_t i = str.find(toReplace); - while (i != std::wstring::npos) - { - str.replace(i, replaceLen, replaceWith); - i = str.find(toReplace, i + replaceWithLen); - } -} - -void HeapTraverser::PrintType(size_t ID, LPCWSTR wname) -{ - if (m_format==FORMAT_XML) - { - int len = (int)_wcslen(wname); - int size = WideCharToMultiByte(CP_ACP, 0, wname, len, NULL, 0, NULL, NULL); - char *buffer = (char*)_alloca(size + 1); - WideCharToMultiByte(CP_ACP, 0, wname, len, buffer, size, NULL, NULL); - buffer[size] = '\0'; - - // Sanitize name based on XML spec. - std::string name(buffer); - replace(name, "&", "&"); - replace(name, "\"", """); - replace(name, "'", "'"); - replace(name, "<", "<"); - replace(name, ">", ">"); - - fprintf(m_file, - "\n", - ID, name.c_str()); - } - else if (m_format==FORMAT_CLRPROFILER) - { - fprintf(m_file, - "t %d 0 %S\n", - ID, wname); - } -} - -void HeapTraverser::PrintObjectHead(size_t objAddr,size_t typeID,size_t Size) -{ - if (m_format==FORMAT_XML) - { - fprintf(m_file, - "\n", - (PBYTE)objAddr,typeID, Size); - } - else if (m_format==FORMAT_CLRPROFILER) - { - fprintf(m_file, - "n %d 1 %d %d\n", - m_curNID,typeID,Size); - - fprintf(m_file, - "! 1 0x%p %d\n", - (PBYTE)objAddr,m_curNID); - - m_curNID++; - - fprintf(m_file, - "o 0x%p %d %d ", - (PBYTE)objAddr,typeID,Size); - } -} - -void HeapTraverser::PrintLoaderAllocator(size_t memberValue) -{ - if (m_format == FORMAT_XML) - { - fprintf(m_file, - " \n", - (PBYTE)memberValue); - } - else if (m_format == FORMAT_CLRPROFILER) - { - fprintf(m_file, - " 0x%p", - (PBYTE)memberValue); - } -} - -void HeapTraverser::PrintObjectMember(size_t memberValue, bool dependentHandle) -{ - if (m_format==FORMAT_XML) - { - fprintf(m_file, - " \n", - (PBYTE)memberValue, dependentHandle ? " dependentHandle=\"1\"" : ""); - } - else if (m_format==FORMAT_CLRPROFILER) - { - fprintf(m_file, - " 0x%p", - (PBYTE)memberValue); - } -} - -void HeapTraverser::PrintObjectTail() -{ - if (m_format==FORMAT_XML) - { - fprintf(m_file, - "\n"); - } - else if (m_format==FORMAT_CLRPROFILER) - { - fprintf(m_file, - "\n"); - } -} - -void HeapTraverser::PrintRootHead() -{ - if (m_format==FORMAT_CLRPROFILER) - { - fprintf(m_file, - "r "); - } -} - -void HeapTraverser::PrintRoot(LPCWSTR kind,size_t Value) -{ - if (m_format==FORMAT_XML) - { - fprintf(m_file, - "\n", - kind, - (PBYTE)Value); - } - else if (m_format==FORMAT_CLRPROFILER) - { - fprintf(m_file, - "0x%p ", - (PBYTE)Value); - } -} - -void HeapTraverser::PrintRootTail() -{ - if (m_format==FORMAT_CLRPROFILER) - { - fprintf(m_file, - "\n"); - } -} - -void HeapTraverser::PrintSection(int Type,BOOL bOpening) -{ - const char *const pTypes[] = {"","","",""}; - const char *const pTypeEnds[] = {"","","",""}; - - if (m_format==FORMAT_XML) - { - if ((Type >= 0) && (Type < TYPE_HIGHEST)) - { - fprintf(m_file,"%s\n",bOpening ? pTypes[Type] : pTypeEnds[Type]); - } - else - { - ExtOut ("INVALID TYPE %d\n", Type); - } - } - else if (m_format==FORMAT_CLRPROFILER) - { - if ((Type == TYPE_START) && !bOpening) // a final newline is needed - { - fprintf(m_file,"\n"); - } - } -} - -void HeapTraverser::FindGCRootOnStacks() -{ - ArrayHolder threadList = NULL; - int numThreads = 0; - - // GetThreadList calls ReportOOM so we don't need to do that here. - HRESULT hr = GetThreadList(&threadList, &numThreads); - if (FAILED(hr) || !threadList) - { - ExtOut("Failed to enumerate threads in the process.\n"); - return; - } - - int total = 0; - DacpThreadData vThread; - for (int i = 0; i < numThreads; i++) - { - if (FAILED(vThread.Request(g_sos, threadList[i]))) - continue; - - if (vThread.osThreadId) - { - unsigned int refCount = 0; - ArrayHolder refs = NULL; - - if (FAILED(::GetGCRefs(vThread.osThreadId, &refs, &refCount, NULL, NULL))) - { - ExtOut("Failed to walk thread %x\n", vThread.osThreadId); - continue; - } - - for (unsigned int i = 0; i < refCount; ++i) - if (refs[i].Object) - PrintRoot(W("stack"), TO_TADDR(refs[i].Object)); - } - } - -} - - -/* static */ void HeapTraverser::PrintOutTree(size_t methodTable, size_t ID, - LPVOID token) -{ - HeapTraverser *pHolder = (HeapTraverser *) token; - NameForMT_s(methodTable, g_mdName, mdNameLen); - pHolder->PrintType(ID,g_mdName); -} - - -/* static */ void HeapTraverser::PrintHeap(DWORD_PTR objAddr,size_t Size, - DWORD_PTR methodTable, LPVOID token) -{ - if (!IsMTForFreeObj (methodTable)) - { - HeapTraverser *pHolder = (HeapTraverser *) token; - pHolder->m_objVisited++; - size_t ID = pHolder->getID(methodTable); - - pHolder->PrintObjectHead(objAddr, ID, Size); - pHolder->PrintRefs(objAddr, methodTable, Size); - pHolder->PrintObjectTail(); - - if (pHolder->m_objVisited % 1024 == 0) { - ExtOut("."); - if (pHolder->m_objVisited % (1024*64) == 0) - ExtOut("\r\n"); - } - } -} - -void HeapTraverser::TraceHandles() -{ - unsigned int fetched = 0; - SOSHandleData data[64]; - - ToRelease handles; - HRESULT hr = g_sos->GetHandleEnum(&handles); - if (FAILED(hr)) - return; - - do - { - hr = handles->Next(ARRAY_SIZE(data), data, &fetched); - - if (FAILED(hr)) - break; - - for (unsigned int i = 0; i < fetched; ++i) - PrintRoot(W("handle"), (size_t)data[i].Handle); - } while (fetched == ARRAY_SIZE(data)); -} - -/* static */ void HeapTraverser::GatherTypes(DWORD_PTR objAddr,size_t Size, - DWORD_PTR methodTable, LPVOID token) -{ - if (!IsMTForFreeObj (methodTable)) - { - HeapTraverser *pHolder = (HeapTraverser *) token; - pHolder->insert(methodTable); - } -} - -void HeapTraverser::PrintRefs(size_t obj, size_t methodTable, size_t size) -{ - DWORD_PTR dwAddr = methodTable; - - // TODO: pass info to callback having to lookup the MethodTableInfo again - MethodTableInfo* info = g_special_mtCache.Lookup((DWORD_PTR)methodTable); - _ASSERTE(info->IsInitialized()); // This is the second pass, so we should be initialized - - if (!info->bContainsPointers && !info->bCollectible) - return; - - if (info->bContainsPointers) - { - // Fetch the GCInfo from the other process - CGCDesc *map = info->GCInfo; - if (map == NULL) - { - INT_PTR nEntries; - move_xp (nEntries, dwAddr-sizeof(PVOID)); - bool arrayOfVC = false; - if (nEntries<0) - { - arrayOfVC = true; - nEntries = -nEntries; - } - - size_t nSlots = 1+nEntries*sizeof(CGCDescSeries)/sizeof(DWORD_PTR); - info->GCInfoBuffer = new DWORD_PTR[nSlots]; - if (info->GCInfoBuffer == NULL) - { - ReportOOM(); - return; - } - - if (FAILED(rvCache->Read(TO_CDADDR(dwAddr - nSlots*sizeof(DWORD_PTR)), - info->GCInfoBuffer, (ULONG) (nSlots*sizeof(DWORD_PTR)), NULL))) - return; - - map = info->GCInfo = (CGCDesc*)(info->GCInfoBuffer+nSlots); - info->ArrayOfVC = arrayOfVC; - } - } - - mCache.EnsureRangeInCache((TADDR)obj, (unsigned int)size); - for (sos::RefIterator itr(obj, info->GCInfo, info->ArrayOfVC, &mCache); itr; ++itr) - { - if (*itr && (!m_verify || sos::IsObject(*itr))) - { - if (itr.IsLoaderAllocator()) - { - PrintLoaderAllocator(*itr); - } - else - { - PrintObjectMember(*itr, false); - } - } - } - - std::unordered_map>::iterator itr = mDependentHandleMap.find((TADDR)obj); - if (itr != mDependentHandleMap.end()) - { - for (std::list::iterator litr = itr->second.begin(); litr != itr->second.end(); ++litr) - { - PrintObjectMember(*litr, true); - } - } -} - void sos::ObjectIterator::BuildError(char *out, size_t count, const char *format, ...) const { if (out == NULL || count == 0) diff --git a/src/SOS/Strike/strike.cpp b/src/SOS/Strike/strike.cpp index e1470e45b0..08b39a1a23 100644 --- a/src/SOS/Strike/strike.cpp +++ b/src/SOS/Strike/strike.cpp @@ -3647,80 +3647,9 @@ void PrintGCStat(HeapStat *inStat, const char* label=NULL) DECLARE_API(TraverseHeap) { - INIT_API(); + INIT_API_EXT(); MINIDUMP_NOT_SUPPORTED(); - ONLY_SUPPORTED_ON_WINDOWS_TARGET(); - - BOOL bXmlFormat = FALSE; - BOOL bVerify = FALSE; - StringHolder Filename; - - CMDOption option[] = - { // name, vptr, type, hasValue - {"-xml", &bXmlFormat, COBOOL, FALSE}, - {"-verify", &bVerify, COBOOL, FALSE}, - }; - CMDValue arg[] = - { // vptr, type - {&Filename.data, COSTRING}, - }; - size_t nArg; - if (!GetCMDOption(args, option, ARRAY_SIZE(option), arg, ARRAY_SIZE(arg), &nArg)) - { - return Status; - } - - if (nArg != 1) - { - ExtOut("usage: %straverseheap [-xml] filename\n", SOSPrefix); - return Status; - } - - if (!g_snapshot.Build()) - { - ExtOut("Unable to build snapshot of the garbage collector state\n"); - return Status; - } - - FILE* file = fopen(Filename.data, "w"); - if (file == nullptr) { - ExtOut("Unable to open file %s (%d)\n", strerror(errno), errno); - return Status; - } - - if (!bVerify) - ExtOut("Assuming a uncorrupted GC heap. If this is a crash dump consider -verify option\n"); - - HeapTraverser traverser(bVerify != FALSE); - - ExtOut("Writing %s format to file %s\n", bXmlFormat ? "Xml" : "CLRProfiler", Filename.data); - ExtOut("Gathering types...\n"); - - // TODO: there may be a canonical list of methodtables in the runtime that we can - // traverse instead of exploring the gc heap for that list. We could then simplify the - // tree structure to a sorted list of methodtables, and the index is the ID. - - // TODO: "Traversing object members" code should be generalized and shared between - // gcroot and traverseheap. Also dumpheap can begin using GCHeapsTraverse. - - if (!traverser.Initialize()) - { - ExtOut("Error initializing heap traversal\n"); - fclose(file); - return Status; - } - - if (!traverser.CreateReport (file, bXmlFormat ? FORMAT_XML : FORMAT_CLRPROFILER)) - { - ExtOut("Unable to write heap report\n"); - fclose(file); - return Status; - } - - fclose(file); - ExtOut("\nfile %s saved\n", Filename.data); - - return Status; + return ExecuteCommand("traverseheap", args); } struct PrintRuntimeTypeArgs diff --git a/src/SOS/Strike/util.h b/src/SOS/Strike/util.h index 74745734d2..6400aafa50 100644 --- a/src/SOS/Strike/util.h +++ b/src/SOS/Strike/util.h @@ -2891,130 +2891,6 @@ class LinearReadCache int mMisses, mReads, mMisaligned; }; - -/////////////////////////////////////////////////////////////////////////////////////////// -// -// Methods for creating a database out of the gc heap and it's roots in xml format or CLRProfiler format -// - -#include -#include -#include - -class TypeTree; -enum { FORMAT_XML=0, FORMAT_CLRPROFILER=1 }; -enum { TYPE_START=0,TYPE_TYPES=1,TYPE_ROOTS=2,TYPE_OBJECTS=3,TYPE_HIGHEST=4}; -class HeapTraverser -{ -private: - TypeTree *m_pTypeTree; - size_t m_curNID; - FILE *m_file; - int m_format; // from the enum above - size_t m_objVisited; // for UI updates - bool m_verify; - LinearReadCache mCache; - - std::unordered_map> mDependentHandleMap; - -public: - HeapTraverser(bool verify); - ~HeapTraverser(); - - FILE *getFile() { return m_file; } - - BOOL Initialize(); - BOOL CreateReport (FILE *fp, int format); - -private: - // First all types are added to a tree - void insert(size_t mTable); - size_t getID(size_t mTable); - - // Functions for writing to the output file. - void PrintType(size_t ID,LPCWSTR name); - - void PrintObjectHead(size_t objAddr,size_t typeID,size_t Size); - void PrintObjectMember(size_t memberValue, bool dependentHandle); - void PrintLoaderAllocator(size_t memberValue); - void PrintObjectTail(); - - void PrintRootHead(); - void PrintRoot(LPCWSTR kind,size_t Value); - void PrintRootTail(); - - void PrintSection(int Type,BOOL bOpening); - - // Root and object member helper functions - void FindGCRootOnStacks(); - void PrintRefs(size_t obj, size_t methodTable, size_t size); - - // Callback functions used during traversals - static void GatherTypes(DWORD_PTR objAddr,size_t Size,DWORD_PTR methodTable, LPVOID token); - static void PrintHeap(DWORD_PTR objAddr,size_t Size,DWORD_PTR methodTable, LPVOID token); - static void PrintOutTree(size_t methodTable, size_t ID, LPVOID token); - void TraceHandles(); -}; - -// -// Helper class used for type-safe bitflags -// T - the enum type specifying the individual bit flags -// U - the underlying/storage type -// Requirement: -// sizeof(T) <= sizeof(U) -// -template -struct Flags -{ - typedef T UnderlyingType; - typedef U BitFlagEnumType; - - static_assert_no_msg(sizeof(BitFlagEnumType) <= sizeof(UnderlyingType)); - - Flags(UnderlyingType v) - : m_val(v) - { } - - Flags(BitFlagEnumType v) - : m_val(v) - { } - - Flags(const Flags& other) - : m_val(other.m_val) - { } - - Flags& operator = (const Flags& other) - { m_val = other.m_val; return *this; } - - Flags operator | (Flags other) const - { return Flags(m_val | other._val); } - - void operator |= (Flags other) - { m_val |= other.m_val; } - - Flags operator & (Flags other) const - { return Flags(m_val & other.m_val); } - - void operator &= (Flags other) - { m_val &= other.m_val; } - - Flags operator ^ (Flags other) const - { return Flags(m_val ^ other._val); } - - void operator ^= (Flags other) - { m_val ^= other.m_val; } - - BOOL operator == (Flags other) const - { return m_val == other.m_val; } - - BOOL operator != (Flags other) const - { return m_val != other.m_val; } - - -private: - UnderlyingType m_val; -}; - // Helper class used in ClrStackFromPublicInterface() to keep track of explicit EE Frames // (i.e., "internal frames") on the stack. Call Init() with the appropriate // ICorDebugThread3, and this class will initialize itself with the set of internal diff --git a/src/SOS/lldbplugin/soscommand.cpp b/src/SOS/lldbplugin/soscommand.cpp index 30164a4634..6bd2fe0452 100644 --- a/src/SOS/lldbplugin/soscommand.cpp +++ b/src/SOS/lldbplugin/soscommand.cpp @@ -222,7 +222,6 @@ sosCommandInitialize(lldb::SBDebugger debugger) g_services->AddCommand("threadpool", new sosCommand("ThreadPool"), "Displays info about the runtime thread pool."); g_services->AddCommand("threadstate", new sosCommand("ThreadState"), "Pretty prints the meaning of a threads state."); g_services->AddCommand("token2ee", new sosCommand("token2ee"), "Displays the MethodTable structure and MethodDesc structure for the specified token and module."); - g_services->AddCommand("traverseheap", new sosCommand("TraverseHeap"), "Writes out heap information to a file in a format understood by the CLR Profiler."); g_services->AddCommand("verifyheap", new sosCommand("VerifyHeap"), "Checks the GC heap for signs of corruption."); g_services->AddCommand("verifyobj", new sosCommand("VerifyObj"), "Checks the object that is passed as an argument for signs of corruption."); return true; From 61919a2f961a681b3e7618a6abc9ee4652d3ff04 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Tue, 11 Apr 2023 17:23:36 +0000 Subject: [PATCH 009/111] Update dependencies from https://github.com/dotnet/source-build-reference-packages build 20230411.2 (#3814) [main] Update dependencies from dotnet/source-build-reference-packages --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 74f2539ede..94bbcaf97b 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -47,9 +47,9 @@ https://github.com/dotnet/runtime a64420c79cb63c485138f4f1352b8730f27d7b19 - + https://github.com/dotnet/source-build-reference-packages - 09c4d8e93c5b78897bccb4f27e0c373647fb3985 + c053ca210364dfa4904006b811249f14743e853e diff --git a/eng/Versions.props b/eng/Versions.props index 9fad78388e..f7b4eab8fb 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -68,7 +68,7 @@ 7.0.0-beta.22316.2 10.0.18362 13.0.1 - 8.0.0-alpha.1.23205.5 + 8.0.0-alpha.1.23211.2 1.2.0-beta-23165-02 From 5ce78f66d89ea529e459abddb129ab36cb5bd936 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Tue, 11 Apr 2023 17:49:42 +0000 Subject: [PATCH 010/111] Update dependencies from https://github.com/dotnet/aspnetcore build 20230410.11 (#3817) [main] Update dependencies from dotnet/aspnetcore --- eng/Version.Details.xml | 8 ++++---- eng/Versions.props | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 94bbcaf97b..c3b646553d 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -31,13 +31,13 @@ https://github.com/dotnet/installer 51e06f6931e859f56564556fa6ba519761fa7141 - + https://github.com/dotnet/aspnetcore - 5d65ee05af31b5a6a0e4faec09e7501b474a997a + 63642be229e26f4a766bc1cb7a7c3fc5f72eecdb - + https://github.com/dotnet/aspnetcore - 5d65ee05af31b5a6a0e4faec09e7501b474a997a + 63642be229e26f4a766bc1cb7a7c3fc5f72eecdb https://github.com/dotnet/runtime diff --git a/eng/Versions.props b/eng/Versions.props index f7b4eab8fb..a68ff3c139 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -21,8 +21,8 @@ 8.0.0-preview.3.23155.1 8.0.0-preview.3.23155.1 - 8.0.0-preview.4.23206.4 - 8.0.0-preview.4.23206.4 + 8.0.0-preview.4.23210.11 + 8.0.0-preview.4.23210.11 8.0.100-preview.3.23156.1 From 001ca0376d167571f01e6383c656fb863e3f429a Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Wed, 12 Apr 2023 17:48:51 +0000 Subject: [PATCH 011/111] Update dependencies from https://github.com/dotnet/aspnetcore build 20230412.2 (#3821) [main] Update dependencies from dotnet/aspnetcore --- eng/Version.Details.xml | 8 ++++---- eng/Versions.props | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index c3b646553d..7b6cdab958 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -31,13 +31,13 @@ https://github.com/dotnet/installer 51e06f6931e859f56564556fa6ba519761fa7141 - + https://github.com/dotnet/aspnetcore - 63642be229e26f4a766bc1cb7a7c3fc5f72eecdb + 7d0c27344d193cb6ad263732d1fef6d3e0fd1f71 - + https://github.com/dotnet/aspnetcore - 63642be229e26f4a766bc1cb7a7c3fc5f72eecdb + 7d0c27344d193cb6ad263732d1fef6d3e0fd1f71 https://github.com/dotnet/runtime diff --git a/eng/Versions.props b/eng/Versions.props index a68ff3c139..7e957902dc 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -21,8 +21,8 @@ 8.0.0-preview.3.23155.1 8.0.0-preview.3.23155.1 - 8.0.0-preview.4.23210.11 - 8.0.0-preview.4.23210.11 + 8.0.0-preview.4.23212.2 + 8.0.0-preview.4.23212.2 8.0.100-preview.3.23156.1 From 150df3e48e8c9158dc5f6c0bbb045b9a69414de9 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Wed, 12 Apr 2023 10:54:49 -0700 Subject: [PATCH 012/111] Update dependencies from https://github.com/dotnet/source-build-reference-packages build 20230412.2 (#3820) Microsoft.SourceBuild.Intermediate.source-build-reference-packages From Version 8.0.0-alpha.1.23211.2 -> To Version 8.0.0-alpha.1.23212.2 Co-authored-by: dotnet-maestro[bot] --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 7b6cdab958..e15c03db7e 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -47,9 +47,9 @@ https://github.com/dotnet/runtime a64420c79cb63c485138f4f1352b8730f27d7b19 - + https://github.com/dotnet/source-build-reference-packages - c053ca210364dfa4904006b811249f14743e853e + 02ee87c8a232a9786b56cd2102cf318559e72210 diff --git a/eng/Versions.props b/eng/Versions.props index 7e957902dc..a3cdbd9b89 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -68,7 +68,7 @@ 7.0.0-beta.22316.2 10.0.18362 13.0.1 - 8.0.0-alpha.1.23211.2 + 8.0.0-alpha.1.23212.2 1.2.0-beta-23165-02 From da1cbd2f65477455e09605f0c0f45bb54f446ab0 Mon Sep 17 00:00:00 2001 From: Lee Culver Date: Wed, 12 Apr 2023 13:33:06 -0700 Subject: [PATCH 013/111] Change lldb behavior for new managed command implementations (#3822) --- src/SOS/lldbplugin/soscommand.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/SOS/lldbplugin/soscommand.cpp b/src/SOS/lldbplugin/soscommand.cpp index 6bd2fe0452..24b5a6e654 100644 --- a/src/SOS/lldbplugin/soscommand.cpp +++ b/src/SOS/lldbplugin/soscommand.cpp @@ -155,7 +155,7 @@ sosCommandInitialize(lldb::SBDebugger debugger) { g_services->AddCommand("sos", new sosCommand(nullptr), "Executes various coreclr debugging commands. Use the syntax 'sos '. For more information, see 'soshelp'."); g_services->AddCommand("ext", new sosCommand(nullptr), "Executes various coreclr debugging commands. Use the syntax 'sos '. For more information, see 'soshelp'."); - g_services->AddCommand("analyzeoom", new sosCommand("AnalyzeOOM"), "Provides a stack trace of managed code only."); + g_services->AddManagedCommand("analyzeoom", "Provides a stack trace of managed code only."); g_services->AddCommand("bpmd", new sosCommand("bpmd"), "Creates a breakpoint at the specified managed method in the specified module."); g_services->AddManagedCommand("clrmodules", "Lists the managed modules in the process."); g_services->AddCommand("clrstack", new sosCommand("ClrStack"), "Provides a stack trace of managed code only."); @@ -170,7 +170,7 @@ sosCommandInitialize(lldb::SBDebugger debugger) g_services->AddCommand("dumpdelegate", new sosCommand("DumpDelegate"), "Displays information about a delegate."); g_services->AddCommand("dumpdomain", new sosCommand("DumpDomain"), "Displays information about the all assemblies within all the AppDomains or the specified one."); g_services->AddCommand("dumpgcdata", new sosCommand("DumpGCData"), "Displays information about the GC data."); - g_services->AddCommand("dumpheap", new sosCommand("DumpHeap"), "Displays info about the garbage-collected heap and collection statistics about objects."); + g_services->AddManagedCommand("dumpheap", "Displays info about the garbage-collected heap and collection statistics about objects."); g_services->AddCommand("dumpil", new sosCommand("DumpIL"), "Displays the Microsoft intermediate language (MSIL) that's associated with a managed method."); g_services->AddCommand("dumplog", new sosCommand("DumpLog"), "Writes the contents of an in-memory stress log to the specified file."); g_services->AddCommand("dumpmd", new sosCommand("DumpMD"), "Displays information about a MethodDesc structure at the specified address."); @@ -184,7 +184,7 @@ sosCommandInitialize(lldb::SBDebugger debugger) g_services->AddCommand("dumpstackobjects", new sosCommand("DumpStackObjects"), "Displays all managed objects found within the bounds of the current stack."); g_services->AddCommand("dso", new sosCommand("DumpStackObjects"), "Displays all managed objects found within the bounds of the current stack."); g_services->AddCommand("dumpvc", new sosCommand("DumpVC"), "Displays info about the fields of a value class."); - g_services->AddCommand("eeheap", new sosCommand("EEHeap"), "Displays info about process memory consumed by internal runtime data structures."); + g_services->AddManagedCommand("eeheap", "Displays info about process memory consumed by internal runtime data structures."); g_services->AddCommand("eestack", new sosCommand("EEStack"), "Runs dumpstack on all threads in the process."); g_services->AddCommand("eeversion", new sosCommand("EEVersion"), "Displays information about the runtime and SOS versions."); g_services->AddCommand("ehinfo", new sosCommand("EHInfo"), "Displays the exception handling blocks in a JIT-ed method."); @@ -192,10 +192,10 @@ sosCommandInitialize(lldb::SBDebugger debugger) g_services->AddCommand("findappdomain", new sosCommand("FindAppDomain"), "Attempts to resolve the AppDomain of a GC object."); g_services->AddCommand("findroots", new sosCommand("FindRoots"), "Finds and displays object roots across GC collections."); g_services->AddCommand("gchandles", new sosCommand("GCHandles"), "Displays statistics about garbage collector handles in the process."); - g_services->AddCommand("gcheapstat", new sosCommand("GCHeapStat"), "Displays statistics about garbage collector."); + g_services->AddManagedCommand("gcheapstat", "Displays statistics about garbage collector."); g_services->AddCommand("gcinfo", new sosCommand("GCInfo"), "Displays info JIT GC encoding for a method."); - g_services->AddCommand("gcroot", new sosCommand("GCRoot"), "Displays info about references (or roots) to an object at the specified address."); - g_services->AddCommand("gcwhere", new sosCommand("GCWhere"), "Displays the location in the GC heap of the specified address."); + g_services->AddManagedCommand("gcroot", "Displays info about references (or roots) to an object at the specified address."); + g_services->AddManagedCommand("gcwhere", "Displays the location in the GC heap of the specified address."); g_services->AddCommand("histclear", new sosCommand("HistClear"), "Releases any resources used by the family of Hist commands."); g_services->AddCommand("histinit", new sosCommand("HistInit"), "Initializes the SOS structures from the stress log saved in the debuggee."); g_services->AddCommand("histobj", new sosCommand("HistObj"), "Examines all stress log relocation records and displays the chain of garbage collection relocations that may have led to the address passed in as an argument."); @@ -207,7 +207,7 @@ sosCommandInitialize(lldb::SBDebugger debugger) g_services->AddManagedCommand("loadsymbols", "Loads the .NET Core native module symbols."); g_services->AddManagedCommand("logging", "Enables/disables internal SOS logging."); g_services->AddCommand("name2ee", new sosCommand("Name2EE"), "Displays the MethodTable structure and EEClass structure for the specified type or method in the specified module."); - g_services->AddCommand("objsize", new sosCommand("ObjSize"), "Displays the size of the specified object."); + g_services->AddManagedCommand("objsize", "Displays the size of the specified object."); g_services->AddCommand("pathto", new sosCommand("PathTo"), "Displays the GC path from to ."); g_services->AddCommand("pe", new sosCommand("PrintException"), "Displays and formats fields of any object derived from the Exception class at the specified address."); g_services->AddCommand("printexception", new sosCommand("PrintException"), "Displays and formats fields of any object derived from the Exception class at the specified address."); @@ -222,7 +222,7 @@ sosCommandInitialize(lldb::SBDebugger debugger) g_services->AddCommand("threadpool", new sosCommand("ThreadPool"), "Displays info about the runtime thread pool."); g_services->AddCommand("threadstate", new sosCommand("ThreadState"), "Pretty prints the meaning of a threads state."); g_services->AddCommand("token2ee", new sosCommand("token2ee"), "Displays the MethodTable structure and MethodDesc structure for the specified token and module."); - g_services->AddCommand("verifyheap", new sosCommand("VerifyHeap"), "Checks the GC heap for signs of corruption."); + g_services->AddManagedCommand("verifyheap", "Checks the GC heap for signs of corruption."); g_services->AddCommand("verifyobj", new sosCommand("VerifyObj"), "Checks the object that is passed as an argument for signs of corruption."); return true; } From ac9350fcd7c25c19c5eca49bbeaa13b405855ffb Mon Sep 17 00:00:00 2001 From: Juan Hoyos <19413848+hoyosjs@users.noreply.github.com> Date: Wed, 12 Apr 2023 14:25:40 -0700 Subject: [PATCH 014/111] Update Logging and AsyncInterfaces versions (#3819) * Update Logging and AsyncInterfaces versions * Update Versions.props --- eng/Versions.props | 8 +++----- .../Microsoft.Diagnostics.Monitoring.EventPipe.csproj | 2 +- .../Microsoft.Diagnostics.NETCore.Client.csproj | 8 ++++++-- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/eng/Versions.props b/eng/Versions.props index a3cdbd9b89..cc637c1da6 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -44,13 +44,10 @@ 5.0.0 - 1.1.0 + 6.0.0 3.0.0-beta.23205.1 16.9.0-beta1.21055.5 3.0.7 - - 2.1.1 - 6.0.0 6.0.0 @@ -58,7 +55,8 @@ 2.0.0-beta1.20468.1 2.0.0-beta1.20074.1 5.0.0 - 4.5.4 + 4.5.1 + 4.5.5 4.3.0 4.7.2 4.7.1 diff --git a/src/Microsoft.Diagnostics.Monitoring.EventPipe/Microsoft.Diagnostics.Monitoring.EventPipe.csproj b/src/Microsoft.Diagnostics.Monitoring.EventPipe/Microsoft.Diagnostics.Monitoring.EventPipe.csproj index cf1089533a..aef58a9d4f 100644 --- a/src/Microsoft.Diagnostics.Monitoring.EventPipe/Microsoft.Diagnostics.Monitoring.EventPipe.csproj +++ b/src/Microsoft.Diagnostics.Monitoring.EventPipe/Microsoft.Diagnostics.Monitoring.EventPipe.csproj @@ -26,7 +26,7 @@ - + diff --git a/src/Microsoft.Diagnostics.NETCore.Client/Microsoft.Diagnostics.NETCore.Client.csproj b/src/Microsoft.Diagnostics.NETCore.Client/Microsoft.Diagnostics.NETCore.Client.csproj index de97cad6fd..094b309355 100644 --- a/src/Microsoft.Diagnostics.NETCore.Client/Microsoft.Diagnostics.NETCore.Client.csproj +++ b/src/Microsoft.Diagnostics.NETCore.Client/Microsoft.Diagnostics.NETCore.Client.csproj @@ -22,8 +22,12 @@ - - + + + + + + From 8c4c649a255a222da405d52887777b62458fc002 Mon Sep 17 00:00:00 2001 From: Lee Culver Date: Wed, 12 Apr 2023 14:36:19 -0700 Subject: [PATCH 015/111] Reimplement !verifyobj and !dumpruntimetypes (#3811) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Update ClrMD Version * Add C# based VerifyHeap command * Fix verifyobj command impl * Add !sos dumpruntimetypes * Remove dead code * Remove object verification code * Remove last use of RefIterator * Remove RefIterator * Test updates * Update src/Microsoft.Diagnostics.ExtensionCommands/ExtensionMethodHelpers.cs Co-authored-by: Günther Foidl * Update src/Microsoft.Diagnostics.ExtensionCommands/VerifyObjectCommand.cs Co-authored-by: Günther Foidl * Fix managed commands * Update soscommand.cpp --------- Co-authored-by: Günther Foidl --- eng/Version.Details.xml | 8 +- eng/Versions.props | 2 +- .../DumpObjGCRefsHelper.cs | 94 +++ .../DumpRuntimeTypeCommand.cs | 66 ++ .../ExtensionMethodHelpers.cs | 3 + .../TableOutput.cs | 17 + .../VerifyHeapCommand.cs | 2 +- .../VerifyObjectCommand.cs | 57 ++ src/SOS/SOS.Hosting/Commands/SOSCommand.cs | 2 - src/SOS/SOS.UnitTests/Scripts/GCTests.script | 8 +- src/SOS/Strike/eeheap.cpp | 437 ----------- src/SOS/Strike/gcroot.cpp | 683 ------------------ src/SOS/Strike/sos.cpp | 181 ----- src/SOS/Strike/sos.h | 95 --- src/SOS/Strike/strike.cpp | 174 +---- src/SOS/Strike/util.h | 9 - src/SOS/lldbplugin/soscommand.cpp | 4 +- 17 files changed, 256 insertions(+), 1586 deletions(-) create mode 100644 src/Microsoft.Diagnostics.ExtensionCommands/DumpObjGCRefsHelper.cs create mode 100644 src/Microsoft.Diagnostics.ExtensionCommands/DumpRuntimeTypeCommand.cs create mode 100644 src/Microsoft.Diagnostics.ExtensionCommands/VerifyObjectCommand.cs diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index e15c03db7e..6dfbbd8a91 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -4,13 +4,13 @@ https://github.com/dotnet/symstore e09f81a0b38786cb20f66b589a8b88b6997a62da - + https://github.com/microsoft/clrmd - 3368bf4451a9441076595022fdff0f2bbea57b1b + 677f1b9c6fa27b1d2988eac9d51c8a5ea8698fdd - + https://github.com/microsoft/clrmd - 3368bf4451a9441076595022fdff0f2bbea57b1b + 677f1b9c6fa27b1d2988eac9d51c8a5ea8698fdd diff --git a/eng/Versions.props b/eng/Versions.props index cc637c1da6..cf0b959d03 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -45,7 +45,7 @@ 5.0.0 6.0.0 - 3.0.0-beta.23205.1 + 3.0.0-beta.23210.1 16.9.0-beta1.21055.5 3.0.7 6.0.0 diff --git a/src/Microsoft.Diagnostics.ExtensionCommands/DumpObjGCRefsHelper.cs b/src/Microsoft.Diagnostics.ExtensionCommands/DumpObjGCRefsHelper.cs new file mode 100644 index 0000000000..fb81fa121c --- /dev/null +++ b/src/Microsoft.Diagnostics.ExtensionCommands/DumpObjGCRefsHelper.cs @@ -0,0 +1,94 @@ +// 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.Linq; +using System.Text; +using Microsoft.Diagnostics.DebugServices; +using Microsoft.Diagnostics.Runtime; +using static Microsoft.Diagnostics.ExtensionCommands.TableOutput; + +namespace Microsoft.Diagnostics.ExtensionCommands +{ + [Command(Name = "dumpobjgcrefs", Help = "A helper command to implement !dumpobj -refs")] + public sealed class DumpObjGCRefsHelper : CommandBase + { + [ServiceImport] + public ClrRuntime Runtime { get; set; } + + [Argument(Name = "object")] + public string ObjectAddress { get; set; } + + public override void Invoke() + { + if (!TryParseAddress(ObjectAddress, out ulong objAddress)) + { + throw new ArgumentException($"Invalid object address: '{ObjectAddress}'", nameof(ObjectAddress)); + } + + ClrObject obj = Runtime.Heap.GetObject(objAddress); + if (!obj.IsValid) + { + Console.WriteLine($"Unable to walk object references, invalid object."); + return; + } + + ClrReference[] refs = obj.EnumerateReferencesWithFields(carefully: false, considerDependantHandles: false).ToArray(); + if (refs.Length == 0 ) + { + Console.WriteLine("GC Refs: none"); + return; + } + + Console.WriteLine("GC Refs:"); + + int fieldNameLen = Math.Max(refs.Max(r => GetFieldName(r)?.Length ?? 0), 5); + int offsetLen = Math.Max(refs.Max(r => r.Offset.ToSignedHexString().Length), 6); + + TableOutput output = new(Console, (fieldNameLen, ""), (offsetLen, ""), (16, "x12")); + output.WriteRow("Field", "Offset", "Object", "Type"); + foreach (ClrReference objRef in refs) + { + output.WriteRow(GetFieldName(objRef), objRef.Offset, new DmlDumpObj(objRef.Object), objRef.Object.Type?.Name); + } + } + + private static string GetFieldName(ClrReference objRef) + { + if (objRef.Field is null) + { + return null; + } + + if (objRef.InnerField is null) + { + return objRef.Field?.Name; + } + + StringBuilder sb = new(260); + bool foundOneFieldName = false; + + for (ClrReference? curr = objRef; curr.HasValue; curr = curr.Value.InnerField) + { + if (sb.Length > 0) + { + sb.Append('.'); + } + + string fieldName = curr.Value.Field?.Name; + if (string.IsNullOrWhiteSpace(fieldName)) + { + sb.Append("???"); + } + else + { + sb.Append(fieldName); + foundOneFieldName = true; + } + } + + // Make sure we don't just return "???.???.???" + return foundOneFieldName ? sb.ToString() : null; + } + } +} diff --git a/src/Microsoft.Diagnostics.ExtensionCommands/DumpRuntimeTypeCommand.cs b/src/Microsoft.Diagnostics.ExtensionCommands/DumpRuntimeTypeCommand.cs new file mode 100644 index 0000000000..a1fee8ad8d --- /dev/null +++ b/src/Microsoft.Diagnostics.ExtensionCommands/DumpRuntimeTypeCommand.cs @@ -0,0 +1,66 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using Microsoft.Diagnostics.DebugServices; +using Microsoft.Diagnostics.Runtime; +using static Microsoft.Diagnostics.ExtensionCommands.TableOutput; + +namespace Microsoft.Diagnostics.ExtensionCommands +{ + [Command(Name = "dumpruntimetypes", Help = "Finds all System.RuntimeType objects in the GC heap and prints the type name and MethodTable they refer too.")] + public sealed class DumpRuntimeTypeCommand : CommandBase + { + [ServiceImport] + public ClrRuntime Runtime { get; set; } + + public override void Invoke() + { + TableOutput output = null; + + foreach (ClrObject runtimeType in Runtime.Heap.EnumerateObjects()) + { + Console.CancellationToken.ThrowIfCancellationRequested(); + if (!runtimeType.IsValid || !runtimeType.IsRuntimeType) + { + continue; + } + + if (!runtimeType.TryReadField("m_handle", out nuint m_handle)) + { + continue; + } + + ClrAppDomain domain = null; + string typeName; + bool isMethodTable = (m_handle & 2) == 0; + if (isMethodTable) + { + // Only lookup the type if we have a MethodTable. + ClrType type = Runtime.GetTypeByMethodTable(m_handle); + typeName = type?.Name ?? $"methodtable: {m_handle:x}"; + domain = type?.Module?.AppDomain; + } + else + { + typeName = $"typehandle: {m_handle:x} (SOS does not support resolving typehandle names.)"; + } + + if (output is null) + { + output = new(Console, (16, "x12"), (16, "x12"), (16, "x12")); + output.WriteRow("Address", "Domain", "MT", "Type Name"); + } + + output.WriteRow(new DmlDumpObj(runtimeType.Address), + domain is not null ? new DmlDumpDomain(domain.Address) : null, + isMethodTable ? new DmlDumpMT(m_handle) : m_handle, + typeName); + } + + if (output is null) + { + Console.WriteLine("No System.RuntimeType objects found."); + } + } + } +} diff --git a/src/Microsoft.Diagnostics.ExtensionCommands/ExtensionMethodHelpers.cs b/src/Microsoft.Diagnostics.ExtensionCommands/ExtensionMethodHelpers.cs index 5f35b39381..348a23eb84 100644 --- a/src/Microsoft.Diagnostics.ExtensionCommands/ExtensionMethodHelpers.cs +++ b/src/Microsoft.Diagnostics.ExtensionCommands/ExtensionMethodHelpers.cs @@ -1,6 +1,7 @@ // 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.Collections.Generic; using System.Linq; using Microsoft.Diagnostics.Runtime; @@ -32,6 +33,8 @@ public static string ConvertToHumanReadable(this double totalBytes) return $"{updated:0.00}gb"; } + public static string ToSignedHexString(this int offset) => offset < 0 ? $"-{Math.Abs(offset):x2}" : offset.ToString("x2"); + internal static ulong FindMostCommonPointer(this IEnumerable enumerable) => (from ptr in enumerable group ptr by ptr into g diff --git a/src/Microsoft.Diagnostics.ExtensionCommands/TableOutput.cs b/src/Microsoft.Diagnostics.ExtensionCommands/TableOutput.cs index c6b91c65ad..3037306841 100644 --- a/src/Microsoft.Diagnostics.ExtensionCommands/TableOutput.cs +++ b/src/Microsoft.Diagnostics.ExtensionCommands/TableOutput.cs @@ -219,6 +219,7 @@ private static string Format(object obj, string format) long l => l.ToString(format), uint ui => ui.ToString(format), int i => i.ToString(format), + nuint uni => ((ulong)uni).ToString(format), StringBuilder sb => sb.ToString(), IEnumerable bytes => string.Join("", bytes.Select(b => b.ToString("x2"))), string s => s, @@ -246,6 +247,22 @@ public DmlDumpObj(ulong address) } } + public sealed class DmlDumpMT : DmlExec + { + public DmlDumpMT(ulong address) + : base(address, address != 0 ? $"!dumpmt /d {address:x}" : "") + { + } + } + + public sealed class DmlDumpDomain : DmlExec + { + public DmlDumpDomain(ulong address) + : base(address, address != 0 ? $"!dumpdomain /d {address:x}" : "") + { + } + } + public sealed class DmlListNearObj : DmlExec { public DmlListNearObj(ulong address) diff --git a/src/Microsoft.Diagnostics.ExtensionCommands/VerifyHeapCommand.cs b/src/Microsoft.Diagnostics.ExtensionCommands/VerifyHeapCommand.cs index f204d69124..e866709598 100644 --- a/src/Microsoft.Diagnostics.ExtensionCommands/VerifyHeapCommand.cs +++ b/src/Microsoft.Diagnostics.ExtensionCommands/VerifyHeapCommand.cs @@ -152,7 +152,7 @@ internal static string GetObjectCorruptionMessage(IMemoryService memory, ClrHeap ObjectCorruptionKind.SyncBlockZero => GetSyncBlockFailureMessage(corruption), // Object reference failures - ObjectCorruptionKind.ObjectReferenceNotPointerAligned => $"Object {obj.Address:x} has an unaligned member at {corruption.Offset:x}: is not pointer aligned", + ObjectCorruptionKind.ObjectReferenceNotPointerAligned => $"Object {obj.Address:x} has an unaligned member at offset {corruption.Offset:x}: is not pointer aligned", ObjectCorruptionKind.InvalidObjectReference => $"Object {obj.Address:x} has a bad member at offset {corruption.Offset:x}: {ReadPointerWithError(memory, obj + (uint)corruption.Offset)}", ObjectCorruptionKind.FreeObjectReference => $"Object {obj.Address:x} contains free object at offset {corruption.Offset:x}: {ReadPointerWithError(memory, obj + (uint)corruption.Offset)}", diff --git a/src/Microsoft.Diagnostics.ExtensionCommands/VerifyObjectCommand.cs b/src/Microsoft.Diagnostics.ExtensionCommands/VerifyObjectCommand.cs new file mode 100644 index 0000000000..818532cef1 --- /dev/null +++ b/src/Microsoft.Diagnostics.ExtensionCommands/VerifyObjectCommand.cs @@ -0,0 +1,57 @@ +// 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.Collections.Generic; +using System.Linq; +using Microsoft.Diagnostics.DebugServices; +using Microsoft.Diagnostics.Runtime; + +namespace Microsoft.Diagnostics.ExtensionCommands +{ + [Command(Name = "verifyobj", Help = "Checks the given object for signs of corruption.")] + public sealed class VerifyObjectCommand : CommandBase + { + [ServiceImport] + public ClrRuntime Runtime { get; set; } + + [ServiceImport] + public IMemoryService Memory { get; set; } + + [Argument(Name = "ObjectAddress", Help = "The object to verify.")] + public string ObjectAddress { get; set; } + + public override void Invoke() + { + if (!TryParseAddress(ObjectAddress, out ulong objAddress)) + { + throw new ArgumentException($"Invalid object address: '{ObjectAddress}'", nameof(ObjectAddress)); + } + + bool isNotCorrupt = Runtime.Heap.FullyVerifyObject(objAddress, out IEnumerable corruptionEnum); + if (isNotCorrupt) + { + Console.WriteLine($"object 0x{objAddress:x} is a valid object"); + return; + } + + ObjectCorruption[] corruption = corruptionEnum.OrderBy(r => r.Offset).ToArray(); + int offsetColWidth = Math.Max(6, corruption.Max(r => r.Offset.ToSignedHexString().Length)); + int kindColWidth = Math.Max(5, corruption.Max(ce => ce.Kind.ToString().Length)); + + TableOutput output = new(Console, (offsetColWidth, ""), (kindColWidth, "")) + { + AlignLeft = true, + }; + + output.WriteRow("Offset", "Issue", "Description"); + foreach (ObjectCorruption oc in corruption) + { + output.WriteRow(oc.Offset.ToSignedHexString(), oc.Kind, VerifyHeapCommand.GetObjectCorruptionMessage(Memory, Runtime.Heap, oc)); + } + + Console.WriteLine(); + Console.WriteLine($"{corruption.Length:n0} error{(corruption.Length == 1 ? "" : "s")} detected."); + } + } +} diff --git a/src/SOS/SOS.Hosting/Commands/SOSCommand.cs b/src/SOS/SOS.Hosting/Commands/SOSCommand.cs index 355ccc3116..7f740a181d 100644 --- a/src/SOS/SOS.Hosting/Commands/SOSCommand.cs +++ b/src/SOS/SOS.Hosting/Commands/SOSCommand.cs @@ -25,7 +25,6 @@ namespace SOS.Hosting [Command(Name = "dumpmodule", DefaultOptions = "DumpModule", Help = "Displays information about a EE module structure at the specified address.")] [Command(Name = "dumpmt", DefaultOptions = "DumpMT", Help = "Displays information about a method table at the specified address.")] [Command(Name = "dumpobj", DefaultOptions = "DumpObj", Aliases = new string[] { "do" }, Help = "Displays info about an object at the specified address.")] - [Command(Name = "dumpruntimetypes", DefaultOptions = "DumpRuntimeTypes", Help = "Finds all System.RuntimeType objects in the GC heap and prints the type name and MethodTable they refer too.")] [Command(Name = "dumpsig", DefaultOptions = "DumpSig", Help = "Dumps the signature of a method or field specified by .")] [Command(Name = "dumpsigelem", DefaultOptions = "DumpSigElem", Help = "Dumps a single element of a signature object.")] [Command(Name = "dumpstackobjects", DefaultOptions = "DumpStackObjects", Aliases = new string[] { "dso" }, Help = "Displays all managed objects found within the bounds of the current stack.")] @@ -50,7 +49,6 @@ namespace SOS.Hosting [Command(Name = "syncblk", DefaultOptions = "SyncBlk", Help = "Displays the SyncBlock holder info.")] [Command(Name = "threadpool", DefaultOptions = "ThreadPool", Help = "Lists basic information about the thread pool.")] [Command(Name = "threadstate", DefaultOptions = "ThreadState", Help = "Pretty prints the meaning of a threads state.")] - [Command(Name = "verifyobj", DefaultOptions = "VerifyObj", Help = "Checks the object for signs of corruption.")] [Command(Name = "comstate", DefaultOptions = "COMState", Flags = CommandFlags.Windows, Help = "Lists the COM apartment model for each thread.")] [Command(Name = "dumprcw", DefaultOptions = "DumpRCW", Flags = CommandFlags.Windows, Help = "Displays information about a Runtime Callable Wrapper.")] [Command(Name = "dumpccw", DefaultOptions = "DumpCCW", Flags = CommandFlags.Windows, Help = "Displays information about a COM Callable Wrapper.")] diff --git a/src/SOS/SOS.UnitTests/Scripts/GCTests.script b/src/SOS/SOS.UnitTests/Scripts/GCTests.script index f65630b0cf..96f558f780 100644 --- a/src/SOS/SOS.UnitTests/Scripts/GCTests.script +++ b/src/SOS/SOS.UnitTests/Scripts/GCTests.script @@ -71,8 +71,8 @@ VERIFY:\s+Fields:\s+ VERIFY:\s+\s+\s+\s+System\.String.*_string\s+ VERIFY:\s+\s+\s+\s+System\.UInt64.*52704621242434 _static\s+ VERIFY:\s+GC Refs:\s+ -VERIFY:\s+offset\s+object\s+ -VERIFY:\s+\s+\s+ +VERIFY:\s+Field\s+Offset\s+Object\s+Type\s+ +VERIFY:.*\s+\s+.* SOSCOMMAND:DumpHeap VERIFY:\s+\s+\s+\s+ @@ -141,8 +141,8 @@ VERIFY:\s+Fields:\s+ VERIFY:\s+\s+\s+\s+System\.String.*_string\s+ VERIFY:\s+\s+\s+\s+System\.UInt64.*52704621242434 _static\s+ VERIFY:\s+GC Refs:\s+ -VERIFY:\s+offset\s+object\s+ -VERIFY:\s+\s+\s+ +VERIFY:\s+Field\s+Offset\s+Object\s+Type\s+ +VERIFY:.*\s+\s+.* # Continue to the next DebugBreak CONTINUE diff --git a/src/SOS/Strike/eeheap.cpp b/src/SOS/Strike/eeheap.cpp index be7c39aa00..3b89f7023d 100644 --- a/src/SOS/Strike/eeheap.cpp +++ b/src/SOS/Strike/eeheap.cpp @@ -612,443 +612,6 @@ void GatherOneHeapFinalization(DacpGcHeapDetails& heapDetails, HeapStat *stat, B } } -BOOL GCHeapTraverse(const GCHeapDetails &heap, AllocInfo* pallocInfo, VISITGCHEAPFUNC pFunc, LPVOID token, BOOL verify) -{ - DWORD_PTR dwAddrSeg = 0; - DWORD_PTR dwAddr = 0; - DWORD_PTR dwAddrCurrObj = 0; - DWORD_PTR dwAddrPrevObj = 0; - size_t s, sPrev = 0; - - DacpHeapSegmentData segment; - if (heap.has_regions) - { - BOOL bPrevFree = FALSE; - for (UINT n = 0; n <= GetMaxGeneration(); n++) - { - dwAddrSeg = (DWORD_PTR)heap.generation_table[n].start_segment; - while (dwAddrSeg != 0) - { - if (IsInterrupt()) - { - ExtOut("\n"); - return FALSE; - } - if (segment.Request(g_sos, dwAddrSeg, heap.original_heap_details) != S_OK) - { - ExtOut("Error requesting heap segment %p\n", SOS_PTR(dwAddrSeg)); - return FALSE; - } - dwAddrCurrObj = (DWORD_PTR)segment.mem; - DWORD_PTR end_of_segment = (DWORD_PTR)segment.highAllocMark; - - while (true) - { - if (dwAddrCurrObj - SIZEOF_OBJHEADER == end_of_segment - Align(min_obj_size)) - break; - - if (dwAddrCurrObj >= (DWORD_PTR)end_of_segment) - { - if (dwAddrCurrObj > (DWORD_PTR)end_of_segment) - { - ExtOut("curr_object: %p > heap_segment_allocated (seg: %p)\n", - SOS_PTR(dwAddrCurrObj), SOS_PTR(dwAddrSeg)); - if (dwAddrPrevObj) - { - ExtOut("Last good object: %p\n", SOS_PTR(dwAddrPrevObj)); - } - return FALSE; - } - // done with this segment - break; - } - - if (dwAddrSeg == (DWORD_PTR)heap.ephemeral_heap_segment - && dwAddrCurrObj >= end_of_segment) - { - if (dwAddrCurrObj > end_of_segment) - { - // prev_object length is too long - ExtOut("curr_object: %p > end_of_segment: %p\n", - SOS_PTR(dwAddrCurrObj), SOS_PTR(end_of_segment)); - if (dwAddrPrevObj) - { - DMLOut("Last good object: %s\n", DMLObject(dwAddrPrevObj)); - } - return FALSE; - } - return FALSE; - } - - DWORD_PTR dwAddrMethTable = 0; - if (FAILED(GetMTOfObject(dwAddrCurrObj, &dwAddrMethTable))) - { - return FALSE; - } - - dwAddrMethTable = dwAddrMethTable & ~sos::Object::METHODTABLE_PTR_LOW_BITMASK; - if (dwAddrMethTable == 0) - { - // Is this the beginning of an allocation context? - int i; - for (i = 0; i < pallocInfo->num; i++) - { - if (dwAddrCurrObj == (DWORD_PTR)pallocInfo->array[i].alloc_ptr) - { - dwAddrCurrObj = - (DWORD_PTR)pallocInfo->array[i].alloc_limit + Align(min_obj_size); - break; - } - } - if (i < pallocInfo->num) - continue; - - // We also need to look at the gen0 alloc context. - if (dwAddrCurrObj == (DWORD_PTR)heap.generation_table[0].allocContextPtr) - { - dwAddrCurrObj = (DWORD_PTR)heap.generation_table[0].allocContextLimit + Align(min_obj_size); - continue; - } - } - - BOOL bContainsPointers; - size_t s; - BOOL bMTOk = GetSizeEfficient(dwAddrCurrObj, dwAddrMethTable, FALSE, s, bContainsPointers); - if (verify && bMTOk) - bMTOk = VerifyObject(heap, dwAddrCurrObj, dwAddrMethTable, s, TRUE); - if (!bMTOk) - { - DMLOut("curr_object: %s\n", DMLListNearObj(dwAddrCurrObj)); - if (dwAddrPrevObj) - DMLOut("Last good object: %s\n", DMLObject(dwAddrPrevObj)); - - ExtOut("----------------\n"); - return FALSE; - } - - pFunc(dwAddrCurrObj, s, dwAddrMethTable, token); - - // We believe we did this alignment in ObjectSize above. - assert((s & ALIGNCONST) == 0); - dwAddrPrevObj = dwAddrCurrObj; - sPrev = s; - bPrevFree = IsMTForFreeObj(dwAddrMethTable); - - dwAddrCurrObj += s; - } - dwAddrSeg = (DWORD_PTR)segment.next; - } - } - } - else - { - DWORD_PTR begin_youngest; - DWORD_PTR end_youngest; - - begin_youngest = (DWORD_PTR)heap.generation_table[0].allocation_start; - dwAddr = (DWORD_PTR)heap.ephemeral_heap_segment; - - end_youngest = (DWORD_PTR)heap.alloc_allocated; - - dwAddrSeg = (DWORD_PTR)heap.generation_table[GetMaxGeneration()].start_segment; - dwAddr = dwAddrSeg; - - if (segment.Request(g_sos, dwAddr, heap.original_heap_details) != S_OK) - { - ExtOut("Error requesting heap segment %p\n", SOS_PTR(dwAddr)); - return FALSE; - } - - // DWORD_PTR dwAddrCurrObj = (DWORD_PTR)heap.generation_table[GetMaxGeneration()].allocation_start; - dwAddrCurrObj = (DWORD_PTR)segment.mem; - - BOOL bPrevFree = FALSE; - - while (1) - { - if (IsInterrupt()) - { - ExtOut("\n"); - return FALSE; - } - DWORD_PTR end_of_segment = (DWORD_PTR)segment.allocated; - if (dwAddrSeg == (DWORD_PTR)heap.ephemeral_heap_segment) - { - end_of_segment = end_youngest; - if (dwAddrCurrObj - SIZEOF_OBJHEADER == end_youngest - Align(min_obj_size)) - break; - } - if (dwAddrCurrObj >= (DWORD_PTR)end_of_segment) - { - if (dwAddrCurrObj > (DWORD_PTR)end_of_segment) - { - ExtOut ("curr_object: %p > heap_segment_allocated (seg: %p)\n", - SOS_PTR(dwAddrCurrObj), SOS_PTR(dwAddrSeg)); - if (dwAddrPrevObj) { - ExtOut ("Last good object: %p\n", SOS_PTR(dwAddrPrevObj)); - } - return FALSE; - } - dwAddrSeg = (DWORD_PTR)segment.next; - if (dwAddrSeg) - { - dwAddr = dwAddrSeg; - if (segment.Request(g_sos, dwAddr, heap.original_heap_details) != S_OK) - { - ExtOut("Error requesting heap segment %p\n", SOS_PTR(dwAddr)); - return FALSE; - } - dwAddrCurrObj = (DWORD_PTR)segment.mem; - continue; - } - else - { - break; // Done Verifying Heap - } - } - - if (dwAddrSeg == (DWORD_PTR)heap.ephemeral_heap_segment - && dwAddrCurrObj >= end_youngest) - { - if (dwAddrCurrObj > end_youngest) - { - // prev_object length is too long - ExtOut("curr_object: %p > end_youngest: %p\n", - SOS_PTR(dwAddrCurrObj), SOS_PTR(end_youngest)); - if (dwAddrPrevObj) { - DMLOut("Last good object: %s\n", DMLObject(dwAddrPrevObj)); - } - return FALSE; - } - return FALSE; - } - - DWORD_PTR dwAddrMethTable = 0; - if (FAILED(GetMTOfObject(dwAddrCurrObj, &dwAddrMethTable))) - { - return FALSE; - } - - dwAddrMethTable = dwAddrMethTable & ~sos::Object::METHODTABLE_PTR_LOW_BITMASK; - if (dwAddrMethTable == 0) - { - // Is this the beginning of an allocation context? - int i; - for (i = 0; i < pallocInfo->num; i ++) - { - if (dwAddrCurrObj == (DWORD_PTR)pallocInfo->array[i].alloc_ptr) - { - dwAddrCurrObj = - (DWORD_PTR)pallocInfo->array[i].alloc_limit + Align(min_obj_size); - break; - } - } - if (i < pallocInfo->num) - continue; - - // We also need to look at the gen0 alloc context. - if (dwAddrCurrObj == (DWORD_PTR) heap.generation_table[0].allocContextPtr) - { - dwAddrCurrObj = (DWORD_PTR) heap.generation_table[0].allocContextLimit + Align(min_obj_size); - continue; - } - } - - BOOL bContainsPointers; - BOOL bMTOk = GetSizeEfficient(dwAddrCurrObj, dwAddrMethTable, FALSE, s, bContainsPointers); - if (verify && bMTOk) - bMTOk = VerifyObject (heap, dwAddrCurrObj, dwAddrMethTable, s, TRUE); - if (!bMTOk) - { - DMLOut("curr_object: %s\n", DMLListNearObj(dwAddrCurrObj)); - if (dwAddrPrevObj) - DMLOut("Last good object: %s\n", DMLObject(dwAddrPrevObj)); - - ExtOut ("----------------\n"); - return FALSE; - } - - pFunc (dwAddrCurrObj, s, dwAddrMethTable, token); - - // We believe we did this alignment in ObjectSize above. - assert((s & ALIGNCONST) == 0); - dwAddrPrevObj = dwAddrCurrObj; - sPrev = s; - bPrevFree = IsMTForFreeObj(dwAddrMethTable); - - dwAddrCurrObj += s; - } - } - - // Now for the large object and pinned object generations: - - BOOL bPinnedDone = FALSE; - - dwAddrSeg = (DWORD_PTR)heap.generation_table[GetMaxGeneration()+1].start_segment; - dwAddr = dwAddrSeg; - - if (segment.Request(g_sos, dwAddr, heap.original_heap_details) != S_OK) - { - ExtOut("Error requesting heap segment %p\n", SOS_PTR(dwAddr)); - return FALSE; - } - - // dwAddrCurrObj = (DWORD_PTR)heap.generation_table[GetMaxGeneration()+1].allocation_start; - dwAddrCurrObj = (DWORD_PTR)segment.mem; - - dwAddrPrevObj=0; - - while(1) - { - if (IsInterrupt()) - { - ExtOut("\n"); - return FALSE; - } - - DWORD_PTR end_of_segment = (DWORD_PTR)segment.allocated; - - if (dwAddrCurrObj >= (DWORD_PTR)end_of_segment) - { - if (dwAddrCurrObj > (DWORD_PTR)end_of_segment) - { - ExtOut("curr_object: %p > heap_segment_allocated (seg: %p)\n", - SOS_PTR(dwAddrCurrObj), SOS_PTR(dwAddrSeg)); - if (dwAddrPrevObj) { - ExtOut("Last good object: %p\n", SOS_PTR(dwAddrPrevObj)); - } - return FALSE; - } - - dwAddrSeg = (DWORD_PTR)segment.next; - if (dwAddrSeg) - { - dwAddr = dwAddrSeg; - if (segment.Request(g_sos, dwAddr, heap.original_heap_details) != S_OK) - { - ExtOut("Error requesting heap segment %p\n", SOS_PTR(dwAddr)); - return FALSE; - } - dwAddrCurrObj = (DWORD_PTR)segment.mem; - continue; - } - else if (heap.has_poh && !bPinnedDone) - { - bPinnedDone = TRUE; - dwAddrSeg = (DWORD_PTR)heap.generation_table[GetMaxGeneration() + 2].start_segment; - dwAddr = dwAddrSeg; - - if (segment.Request(g_sos, dwAddr, heap.original_heap_details) != S_OK) - { - ExtOut("Error requesting heap segment %p\n", SOS_PTR(dwAddr)); - return FALSE; - } - - dwAddrCurrObj = (DWORD_PTR)segment.mem; - continue; - } - else - { - break; // Done Verifying Heap - } - } - - DWORD_PTR dwAddrMethTable = 0; - if (FAILED(GetMTOfObject(dwAddrCurrObj, &dwAddrMethTable))) - { - return FALSE; - } - - dwAddrMethTable = dwAddrMethTable & ~sos::Object::METHODTABLE_PTR_LOW_BITMASK; - BOOL bContainsPointers; - BOOL bMTOk = GetSizeEfficient(dwAddrCurrObj, dwAddrMethTable, TRUE, s, bContainsPointers); - if (verify && bMTOk) - bMTOk = VerifyObject (heap, dwAddrCurrObj, dwAddrMethTable, s, TRUE); - if (!bMTOk) - { - DMLOut("curr_object: %s\n", DMLListNearObj(dwAddrCurrObj)); - - if (dwAddrPrevObj) - DMLOut("Last good object: %s\n", dwAddrPrevObj); - - ExtOut ("----------------\n"); - return FALSE; - } - - pFunc (dwAddrCurrObj, s, dwAddrMethTable, token); - - // We believe we did this alignment in ObjectSize above. - assert((s & ALIGNCONSTLARGE) == 0); - dwAddrPrevObj = dwAddrCurrObj; - dwAddrCurrObj += s; - } - - return TRUE; -} - -BOOL GCHeapsTraverse(VISITGCHEAPFUNC pFunc, LPVOID token, BOOL verify) -{ - // Obtain allocation context for each managed thread. - AllocInfo allocInfo; - allocInfo.Init(); - - if (!IsServerBuild()) - { - DacpGcHeapDetails dacHeapDetails; - if (dacHeapDetails.Request(g_sos) != S_OK) - { - ExtOut("Error requesting gc heap details\n"); - return FALSE; - } - - GCHeapDetails heapDetails(dacHeapDetails); - return GCHeapTraverse (heapDetails, &allocInfo, pFunc, token, verify); - } - else - { - DacpGcHeapData gcheap; - if (gcheap.Request(g_sos) != S_OK) - { - ExtOut("Error requesting GC Heap data\n"); - return FALSE; - } - - DWORD dwAllocSize; - DWORD dwNHeaps = gcheap.HeapCount; - if (!ClrSafeInt::multiply(sizeof(CLRDATA_ADDRESS), dwNHeaps, dwAllocSize)) - { - ExtOut("Failed to get GCHeaps: integer overflow error\n"); - return FALSE; - } - CLRDATA_ADDRESS *heapAddrs = (CLRDATA_ADDRESS*)alloca(dwAllocSize); - if (g_sos->GetGCHeapList(dwNHeaps, heapAddrs, NULL) != S_OK) - { - ExtOut("Failed to get GCHeaps\n"); - return FALSE; - } - - DWORD n; - for (n = 0; n < dwNHeaps; n ++) - { - DacpGcHeapDetails dacHeapDetails; - if (dacHeapDetails.Request(g_sos, heapAddrs[n]) != S_OK) - { - ExtOut("Error requesting details\n"); - return FALSE; - } - - GCHeapDetails heapDetails(dacHeapDetails, heapAddrs[n]); - if (!GCHeapTraverse (heapDetails, &allocInfo, pFunc, token, verify)) - { - ExtOut("Traversing a gc heap failed\n"); - return FALSE; - } - } - } - - return TRUE; -} - GCHeapSnapshot::GCHeapSnapshot() { m_isBuilt = FALSE; diff --git a/src/SOS/Strike/gcroot.cpp b/src/SOS/Strike/gcroot.cpp index 34df3bc577..8a426ca7c3 100644 --- a/src/SOS/Strike/gcroot.cpp +++ b/src/SOS/Strike/gcroot.cpp @@ -143,686 +143,3 @@ UINT FindAllPinnedAndStrong(DWORD_PTR handlearray[], UINT arraySize) return pos; } - - -//////////////////////////////////////////////////////////////////////////////// -// -// Some defines for cards taken from gc code -// -#define card_word_width ((size_t)32) - -// -// The value of card_size is determined empirically according to the average size of an object -// In the code we also rely on the assumption that one card_table entry (DWORD) covers an entire os page -// -#if defined (_TARGET_WIN64_) -#define card_size ((size_t)(2*DT_GC_PAGE_SIZE/card_word_width)) -#else -#define card_size ((size_t)(DT_GC_PAGE_SIZE/card_word_width)) -#endif //_TARGET_WIN64_ - -// so card_size = 128 on x86, 256 on x64 - -inline -size_t card_word (size_t card) -{ - return card / card_word_width; -} - -inline -unsigned card_bit (size_t card) -{ - return (unsigned)(card % card_word_width); -} - -inline -size_t card_of ( BYTE* object) -{ - return (size_t)(object) / card_size; -} - -BOOL CardIsSet(const GCHeapDetails &heap, TADDR objAddr) -{ - // The card table has to be translated to look at the refcount, etc. - // g_card_table[card_word(card_of(g_lowest_address))]. - - TADDR card_table = TO_TADDR(heap.card_table); - card_table = card_table + card_word(card_of((BYTE *)heap.lowest_address))*sizeof(DWORD); - - do - { - TADDR card_table_lowest_addr; - TADDR card_table_next; - - if (MOVE(card_table_lowest_addr, ALIGN_DOWN(card_table, 0x1000) + sizeof(PVOID)) != S_OK) - { - ExtErr("Error getting card table lowest address\n"); - return FALSE; - } - - if (MOVE(card_table_next, card_table - sizeof(PVOID)) != S_OK) - { - ExtErr("Error getting next card table\n"); - return FALSE; - } - - size_t card = (objAddr - card_table_lowest_addr) / card_size; - TADDR card_addr = card_table + (card_word(card) * sizeof(DWORD)); - DWORD value; - if (MOVE(value, card_addr) != S_OK) - { - ExtErr("Error reading card bits - obj %p card %08x card_addr %p card_table %p\n", objAddr, card, card_addr, card_table); - return FALSE; - } - - if (value & 1<= heap.background_saved_lowest_address) && (o < heap.background_saved_highest_address)) - m = mark_array_marked(heap, o); - - return m; -} - -BOOL fgc_should_consider_object(const GCHeapDetails &heap, - CLRDATA_ADDRESS o, - const DacpHeapSegmentData &seg, - BOOL consider_bgc_mark_p, - BOOL check_current_sweep_p, - BOOL check_saved_sweep_p) -{ - // the logic for this function must be kept in sync with the analogous function in gc.cpp - BOOL no_bgc_mark_p = FALSE; - - if (consider_bgc_mark_p) - { - if (check_current_sweep_p && (o < heap.next_sweep_obj)) - { - no_bgc_mark_p = TRUE; - } - - if (!no_bgc_mark_p) - { - if(check_saved_sweep_p && (o >= heap.saved_sweep_ephemeral_start)) - { - no_bgc_mark_p = TRUE; - } - - if (!check_saved_sweep_p) - { - CLRDATA_ADDRESS background_allocated = seg.background_allocated; - if (o >= background_allocated) - { - no_bgc_mark_p = TRUE; - } - } - } - } - else - { - no_bgc_mark_p = TRUE; - } - - return no_bgc_mark_p ? TRUE : background_object_marked(heap, o); -} - -enum c_gc_state -{ - c_gc_state_marking, - c_gc_state_planning, - c_gc_state_free -}; - -inline BOOL in_range_for_segment(const DacpHeapSegmentData &seg, CLRDATA_ADDRESS addr) -{ - return (addr >= seg.mem) && (addr < seg.reserved); -} - -void should_check_bgc_mark(const GCHeapDetails &heap, - const DacpHeapSegmentData &seg, - BOOL* consider_bgc_mark_p, - BOOL* check_current_sweep_p, - BOOL* check_saved_sweep_p) -{ - // the logic for this function must be kept in sync with the analogous function in gc.cpp - *consider_bgc_mark_p = FALSE; - *check_current_sweep_p = FALSE; - *check_saved_sweep_p = FALSE; - - if (heap.current_c_gc_state == c_gc_state_planning) - { - // We are doing the next_sweep_obj comparison here because we have yet to - // turn on the swept flag for the segment but in_range_for_segment will return - // FALSE if the address is the same as reserved. - if ((seg.flags & heap_segment_flags_swept) || (heap.next_sweep_obj == seg.reserved)) - { - // this seg was already swept. - } - else - { - *consider_bgc_mark_p = TRUE; - - if ((heap.saved_sweep_ephemeral_seg != -1) && (seg.segmentAddr == heap.saved_sweep_ephemeral_seg)) - { - *check_saved_sweep_p = TRUE; - } - - if (in_range_for_segment(seg, heap.next_sweep_obj)) - { - *check_current_sweep_p = TRUE; - } - } - } -} - -// TODO: FACTOR TOGETHER THE OBJECT MEMBER WALKING CODE FROM -// TODO: VerifyObjectMember(), GetListOfRefs(), HeapTraverser::PrintRefs() -BOOL VerifyObjectMember(const GCHeapDetails &heap, DWORD_PTR objAddr) -{ - BOOL ret = TRUE; - BOOL bCheckCard = TRUE; - size_t size = 0; - { - DWORD_PTR dwAddrCard = objAddr; - while (dwAddrCard < objAddr + size) - { - if (CardIsSet(heap, dwAddrCard)) - { - bCheckCard = FALSE; - break; - } - dwAddrCard += card_size; - } - - if (bCheckCard) - { - dwAddrCard = objAddr + size - 2*sizeof(PVOID); - if (CardIsSet(heap, dwAddrCard)) - { - bCheckCard = FALSE; - } - } - } - - for (sos::RefIterator itr(TO_TADDR(objAddr)); itr; ++itr) - { - TADDR dwAddr1 = (DWORD_PTR)*itr; - if (dwAddr1) - { - TADDR dwChild = dwAddr1; - // Try something more efficient than IsObject here. Is the methodtable valid? - size_t s; - BOOL bPointers; - TADDR dwAddrMethTable; - if (FAILED(GetMTOfObject(dwAddr1, &dwAddrMethTable)) || - (GetSizeEfficient(dwAddr1, dwAddrMethTable, FALSE, s, bPointers) == FALSE)) - { - DMLOut("object %s: bad member %p at %p\n", DMLObject(objAddr), SOS_PTR(dwAddr1), SOS_PTR(itr.GetOffset())); - ret = FALSE; - } - - if (IsMTForFreeObj(dwAddrMethTable)) - { - DMLOut("object %s contains free object %p at %p\n", DMLObject(objAddr), - SOS_PTR(dwAddr1), SOS_PTR(objAddr+itr.GetOffset())); - ret = FALSE; - } - - // verify card table - if (bCheckCard && NeedCard(objAddr+itr.GetOffset(), dwAddr1)) - { - DMLOut("object %s:%s missing card_table entry for %p\n", - DMLObject(objAddr), (dwChild == dwAddr1) ? "" : " maybe", - SOS_PTR(objAddr+itr.GetOffset())); - ret = FALSE; - } - } - } - - return ret; -} - -// search for can_verify_deep in gc.cpp for examples of how these functions are used. -BOOL VerifyObject(const GCHeapDetails &heap, const DacpHeapSegmentData &seg, DWORD_PTR objAddr, DWORD_PTR MTAddr, size_t objSize, - BOOL bVerifyMember) -{ - if (IsMTForFreeObj(MTAddr)) - { - return TRUE; - } - - if (objSize < min_obj_size) - { - DMLOut("object %s: size %d too small\n", DMLObject(objAddr), objSize); - return FALSE; - } - - // If we requested to verify the object's members, the GC may be in a state where that's not possible. - // Here we check to see if the object in question needs to have its members updated. If so, we turn off - // verification for the object. - if (bVerifyMember) - { - BOOL consider_bgc_mark = FALSE, check_current_sweep = FALSE, check_saved_sweep = FALSE; - should_check_bgc_mark(heap, seg, &consider_bgc_mark, &check_current_sweep, &check_saved_sweep); - bVerifyMember = fgc_should_consider_object(heap, objAddr, seg, consider_bgc_mark, check_current_sweep, check_saved_sweep); - } - - return bVerifyMember ? VerifyObjectMember(heap, objAddr) : TRUE; -} - - -BOOL FindSegment(const GCHeapDetails &heap, DacpHeapSegmentData &seg, CLRDATA_ADDRESS addr) -{ - if (heap.has_regions) - { - CLRDATA_ADDRESS dwAddrSeg; - for (UINT n = 0; n <= GetMaxGeneration(); n++) - { - dwAddrSeg = (DWORD_PTR)heap.generation_table[n].start_segment; - while (dwAddrSeg != 0) - { - if (IsInterrupt()) - return FALSE; - if (seg.Request(g_sos, dwAddrSeg, heap.original_heap_details) != S_OK) - { - ExtOut("Error requesting heap segment %p\n", SOS_PTR(dwAddrSeg)); - return FALSE; - } - if (addr >= TO_TADDR(seg.mem) && addr < seg.highAllocMark) - { - return TRUE; - } - dwAddrSeg = (DWORD_PTR)seg.next; - } - } - return FALSE; - } - else - { - CLRDATA_ADDRESS dwAddrSeg = heap.generation_table[GetMaxGeneration()].start_segment; - - // Request the initial segment. - if (seg.Request(g_sos, dwAddrSeg, heap.original_heap_details) != S_OK) - { - ExtOut("Error requesting heap segment %p.\n", SOS_PTR(dwAddrSeg)); - return FALSE; - } - - // Loop while the object is not in range of the segment. - while (addr < TO_TADDR(seg.mem) || - addr >= (dwAddrSeg == heap.ephemeral_heap_segment ? heap.alloc_allocated : TO_TADDR(seg.allocated))) - { - // get the next segment - dwAddrSeg = seg.next; - - // We reached the last segment without finding the object. - if (dwAddrSeg == NULL) - return FALSE; - - if (seg.Request(g_sos, dwAddrSeg, heap.original_heap_details) != S_OK) - { - ExtOut("Error requesting heap segment %p.\n", SOS_PTR(dwAddrSeg)); - return FALSE; - } - } - } - - return TRUE; -} - -BOOL VerifyObject(const GCHeapDetails &heap, DWORD_PTR objAddr, DWORD_PTR MTAddr, size_t objSize, BOOL bVerifyMember) -{ - // This is only used by the other VerifyObject function if bVerifyMember is true, - // so we only initialize it if we need it for verifying object members. - DacpHeapSegmentData seg; - - if (bVerifyMember) - { - // if we fail to find the segment, we cannot verify the object's members - bVerifyMember = FindSegment(heap, seg, objAddr); - } - - return VerifyObject(heap, seg, objAddr, MTAddr, objSize, bVerifyMember); -} - -void sos::ObjectIterator::BuildError(char *out, size_t count, const char *format, ...) const -{ - if (out == NULL || count == 0) - return; - - va_list args; - va_start(args, format); - - int written = vsprintf_s(out, count, format, args); - if (written > 0 && mLastObj) - sprintf_s(out+written, count-written, "\nLast good object: %p.\n", (int*)mLastObj); - - va_end(args); -} - -bool sos::ObjectIterator::VerifyObjectMembers(char *reason, size_t count) const -{ - if (!mCurrObj.HasPointers()) - return true; - - size_t size = mCurrObj.GetSize(); - size_t objAddr = (size_t)mCurrObj.GetAddress(); - TADDR mt = mCurrObj.GetMT(); - - INT_PTR nEntries; - MOVE(nEntries, mt-sizeof(PVOID)); - if (nEntries < 0) - nEntries = -nEntries; - - size_t nSlots = 1 + nEntries * sizeof(CGCDescSeries)/sizeof(DWORD_PTR); - ArrayHolder buffer = new DWORD_PTR[nSlots]; - - if (FAILED(g_ExtData->ReadVirtual(TO_CDADDR(mt - nSlots*sizeof(DWORD_PTR)), - buffer, (ULONG) (nSlots*sizeof(DWORD_PTR)), NULL))) - { - BuildError(reason, count, "Object %s has a bad GCDesc.", DMLObject(objAddr)); - return false; - } - - CGCDesc *map = (CGCDesc *)(buffer+nSlots); - CGCDescSeries* cur = map->GetHighestSeries(); - CGCDescSeries* last = map->GetLowestSeries(); - - const size_t bufferSize = sizeof(size_t)*128; - size_t objBuffer[bufferSize/sizeof(size_t)]; - size_t dwBeginAddr = (size_t)objAddr; - size_t bytesInBuffer = bufferSize; - if (size < bytesInBuffer) - bytesInBuffer = size; - - - if (FAILED(g_ExtData->ReadVirtual(TO_CDADDR(dwBeginAddr), objBuffer, (ULONG) bytesInBuffer,NULL))) - { - BuildError(reason, count, "Object %s: Failed to read members.", DMLObject(objAddr)); - return false; - } - - BOOL bCheckCard = TRUE; - { - DWORD_PTR dwAddrCard = (DWORD_PTR)objAddr; - while (dwAddrCard < objAddr + size) - { - if (CardIsSet (mHeaps[mCurrHeap], dwAddrCard)) - { - bCheckCard = FALSE; - break; - } - dwAddrCard += card_size; - } - if (bCheckCard) - { - dwAddrCard = objAddr + size - 2*sizeof(PVOID); - if (CardIsSet (mHeaps[mCurrHeap], dwAddrCard)) - { - bCheckCard = FALSE; - } - } - } - - if (cur >= last) - { - do - { - BYTE** parm = (BYTE**)((objAddr) + cur->GetSeriesOffset()); - BYTE** ppstop = - (BYTE**)((BYTE*)parm + cur->GetSeriesSize() + (size)); - while (parm < ppstop) - { - CheckInterrupt(); - size_t dwAddr1; - - // Do we run out of cache? - if ((size_t)parm >= dwBeginAddr+bytesInBuffer) - { - // dwBeginAddr += bytesInBuffer; - dwBeginAddr = (size_t)parm; - if (dwBeginAddr >= objAddr + size) - { - return true; - } - bytesInBuffer = bufferSize; - if (objAddr+size-dwBeginAddr < bytesInBuffer) - { - bytesInBuffer = objAddr+size-dwBeginAddr; - } - if (FAILED(g_ExtData->ReadVirtual(TO_CDADDR(dwBeginAddr), objBuffer, (ULONG) bytesInBuffer, NULL))) - { - BuildError(reason, count, "Object %s: Failed to read members.", DMLObject(objAddr)); - return false; - } - } - dwAddr1 = objBuffer[((size_t)parm-dwBeginAddr)/sizeof(size_t)]; - if (dwAddr1) { - DWORD_PTR dwChild = dwAddr1; - // Try something more efficient than IsObject here. Is the methodtable valid? - size_t s; - BOOL bPointers; - DWORD_PTR dwAddrMethTable; - if (FAILED(GetMTOfObject(dwAddr1, &dwAddrMethTable)) || - (GetSizeEfficient(dwAddr1, dwAddrMethTable, FALSE, s, bPointers) == FALSE)) - { - BuildError(reason, count, "object %s: bad member %p at %p", DMLObject(objAddr), - SOS_PTR(dwAddr1), SOS_PTR(objAddr+(size_t)parm-objAddr)); - - return false; - } - - if (IsMTForFreeObj(dwAddrMethTable)) - { - sos::Throw("object %s contains free object %p at %p", DMLObject(objAddr), - SOS_PTR(dwAddr1), SOS_PTR(objAddr+(size_t)parm-objAddr)); - } - - // verify card table - if (bCheckCard && - NeedCard(objAddr+(size_t)parm-objAddr,dwChild)) - { - BuildError(reason, count, "Object %s: %s missing card_table entry for %p", - DMLObject(objAddr), (dwChild == dwAddr1)? "" : " maybe", - SOS_PTR(objAddr+(size_t)parm-objAddr)); - - return false; - } - } - parm++; - } - cur--; - CheckInterrupt(); - - } while (cur >= last); - } - else - { - int cnt = (int) map->GetNumSeries(); - BYTE** parm = (BYTE**)((objAddr) + cur->startoffset); - while ((BYTE*)parm < (BYTE*)((objAddr)+(size)-plug_skew)) - { - for (int __i = 0; __i > cnt; __i--) - { - CheckInterrupt(); - - unsigned skip = cur->val_serie[__i].skip; - unsigned nptrs = cur->val_serie[__i].nptrs; - BYTE** ppstop = parm + nptrs; - do - { - size_t dwAddr1; - // Do we run out of cache? - if ((size_t)parm >= dwBeginAddr+bytesInBuffer) - { - // dwBeginAddr += bytesInBuffer; - dwBeginAddr = (size_t)parm; - if (dwBeginAddr >= objAddr + size) - return true; - - bytesInBuffer = bufferSize; - if (objAddr+size-dwBeginAddr < bytesInBuffer) - bytesInBuffer = objAddr+size-dwBeginAddr; - - if (FAILED(g_ExtData->ReadVirtual(TO_CDADDR(dwBeginAddr), objBuffer, (ULONG) bytesInBuffer, NULL))) - { - BuildError(reason, count, "Object %s: Failed to read members.", DMLObject(objAddr)); - return false; - } - } - dwAddr1 = objBuffer[((size_t)parm-dwBeginAddr)/sizeof(size_t)]; - { - if (dwAddr1) - { - DWORD_PTR dwChild = dwAddr1; - // Try something more efficient than IsObject here. Is the methodtable valid? - size_t s; - BOOL bPointers; - DWORD_PTR dwAddrMethTable; - if (FAILED(GetMTOfObject(dwAddr1, &dwAddrMethTable)) || - (GetSizeEfficient(dwAddr1, dwAddrMethTable, FALSE, s, bPointers) == FALSE)) - { - BuildError(reason, count, "Object %s: Bad member %p at %p.\n", DMLObject(objAddr), - SOS_PTR(dwAddr1), SOS_PTR(objAddr+(size_t)parm-objAddr)); - - return false; - } - - if (IsMTForFreeObj(dwAddrMethTable)) - { - BuildError(reason, count, "Object %s contains free object %p at %p.", DMLObject(objAddr), - SOS_PTR(dwAddr1), SOS_PTR(objAddr+(size_t)parm-objAddr)); - return false; - } - - // verify card table - if (bCheckCard && - NeedCard (objAddr+(size_t)parm-objAddr,dwAddr1)) - { - BuildError(reason, count, "Object %s:%s missing card_table entry for %p", - DMLObject(objAddr), (dwChild == dwAddr1) ? "" : " maybe", - SOS_PTR(objAddr+(size_t)parm-objAddr)); - - return false; - } - } - } - parm++; - CheckInterrupt(); - } while (parm < ppstop); - parm = (BYTE**)((BYTE*)parm + skip); - } - } - } - - return true; -} - -bool sos::ObjectIterator::Verify(char *reason, size_t count) const -{ - try - { - TADDR mt = mCurrObj.GetMT(); - - if (MethodTable::GetFreeMT() == mt) - { - return true; - } - - size_t size = mCurrObj.GetSize(); - if (size < min_obj_size) - { - BuildError(reason, count, "Object %s: Size %d is too small.", DMLObject(mCurrObj.GetAddress()), size); - return false; - } - - if (mCurrObj.GetAddress() + mCurrObj.GetSize() > mSegmentEnd) - { - BuildError(reason, count, "Object %s is too large. End of segment at %p.", DMLObject(mCurrObj), mSegmentEnd); - return false; - } - - BOOL bVerifyMember = TRUE; - - // If we requested to verify the object's members, the GC may be in a state where that's not possible. - // Here we check to see if the object in question needs to have its members updated. If so, we turn off - // verification for the object. - BOOL consider_bgc_mark = FALSE, check_current_sweep = FALSE, check_saved_sweep = FALSE; - should_check_bgc_mark(mHeaps[mCurrHeap], mSegment, &consider_bgc_mark, &check_current_sweep, &check_saved_sweep); - bVerifyMember = fgc_should_consider_object(mHeaps[mCurrHeap], mCurrObj.GetAddress(), mSegment, - consider_bgc_mark, check_current_sweep, check_saved_sweep); - - if (bVerifyMember) - return VerifyObjectMembers(reason, count); - } - catch(const sos::Exception &e) - { - BuildError(reason, count, e.GetMesssage()); - return false; - } - - return true; -} - -bool sos::ObjectIterator::Verify() const -{ - char *c = NULL; - return Verify(c, 0); -} diff --git a/src/SOS/Strike/sos.cpp b/src/SOS/Strike/sos.cpp index 33368fe60b..d637289253 100644 --- a/src/SOS/Strike/sos.cpp +++ b/src/SOS/Strike/sos.cpp @@ -376,187 +376,6 @@ namespace sos return (size_t)stInfo.m_StringLength; } - - RefIterator::RefIterator(TADDR obj, LinearReadCache *cache) - : mCache(cache), mGCDesc(0), mArrayOfVC(false), mDone(false), mBuffer(0), mCurrSeries(0), mLoaderAllocatorObjectHandle(0), - i(0), mCount(0), mCurr(0), mStop(0), mObject(obj), mObjSize(0) - { - Init(); - } - - RefIterator::RefIterator(TADDR obj, CGCDesc *desc, bool arrayOfVC, LinearReadCache *cache) - : mCache(cache), mGCDesc(desc), mArrayOfVC(arrayOfVC), mDone(false), mBuffer(0), mCurrSeries(0), mLoaderAllocatorObjectHandle(0), - i(0), mCount(0), mCurr(0), mStop(0), mObject(obj), mObjSize(0) - { - Init(); - } - - RefIterator::~RefIterator() - { - if (mBuffer) - delete [] mBuffer; - } - - const RefIterator &RefIterator::operator++() - { - if (mDone) - Throw("Attempt to move past the end of the iterator."); - - if (mCurr == mLoaderAllocatorObjectHandle) - { - // The mLoaderAllocatorObjectHandle is always the last reference returned - mDone = true; - return *this; - } - - if (!mArrayOfVC) - { - mCurr += sizeof(TADDR); - if (mCurr >= mStop) - { - mCurrSeries--; - if (mCurrSeries < mGCDesc->GetLowestSeries()) - { - mDone = true; - } - else - { - mCurr = mObject + mCurrSeries->GetSeriesOffset(); - mStop = mCurr + mCurrSeries->GetSeriesSize() + mObjSize; - } - } - } - else - { - mCurr += sizeof(TADDR); - if (mCurr >= mStop) - { - int i_last = i; - i--; - - if (i == mCount) - i = 0; - - mCurr += mCurrSeries->val_serie[i_last].skip; - mStop = mCurr + mCurrSeries->val_serie[i].nptrs * sizeof(TADDR); - } - - if (mCurr >= mObject + mObjSize - plug_skew) - mDone = true; - } - - if (mDone && mLoaderAllocatorObjectHandle != NULL) - { - // The iteration over all regular object references is done, but there is one more - // reference for collectible types - the LoaderAllocator for GC - mCurr = mLoaderAllocatorObjectHandle; - mDone = false; - } - - return *this; - } - - TADDR RefIterator::operator*() const - { - return ReadPointer(mCurr); - } - - TADDR RefIterator::GetOffset() const - { - return mCurr - mObject; - } - - void RefIterator::Init() - { - TADDR mt = ReadPointer(mObject); - BOOL bContainsPointers = FALSE; - BOOL bCollectible = FALSE; - TADDR loaderAllocatorObjectHandle; - - if (!GetSizeEfficient(mObject, mt, FALSE, mObjSize, bContainsPointers)) - Throw("Failed to get size of object."); - - if (!GetCollectibleDataEfficient(mt, bCollectible, loaderAllocatorObjectHandle)) - Throw("Failed to get collectible info of object."); - - if (!bContainsPointers && !bCollectible) - { - mDone = true; - return; - } - - if (bContainsPointers) - { - if (!mGCDesc) - { - int entries = 0; - - if (FAILED(MOVE(entries, mt-sizeof(TADDR)))) - Throw("Failed to request number of entries for %p MT %p", mObject, mt); - - // array of vc? - if (entries < 0) - { - entries = -entries; - mArrayOfVC = true; - } - else - { - mArrayOfVC = false; - } - - size_t slots = 1 + entries * sizeof(CGCDescSeries)/sizeof(TADDR); - - ArrayHolder buffer = new TADDR[slots]; - - ULONG fetched = 0; - CLRDATA_ADDRESS address = TO_CDADDR(mt - slots*sizeof(TADDR)); - if (FAILED(g_ExtData->ReadVirtual(address, buffer, (ULONG)(slots*sizeof(TADDR)), &fetched))) - Throw("Failed to request GCDesc."); - - mBuffer = buffer.Detach(); - mGCDesc = (CGCDesc*)(mBuffer + slots); - } - - mCurrSeries = mGCDesc->GetHighestSeries(); - - if (!mArrayOfVC) - { - mCurr = mObject + mCurrSeries->GetSeriesOffset(); - mStop = mCurr + mCurrSeries->GetSeriesSize() + mObjSize; - } - else - { - i = 0; - mCurr = mObject + mCurrSeries->startoffset; - mStop = mCurr + mCurrSeries->val_serie[i].nptrs * sizeof(TADDR); - mCount = (int)mGCDesc->GetNumSeries(); - } - - if (mCurr == mStop) - operator++(); - else if (mCurr >= mObject + mObjSize - plug_skew) - mDone = true; - } - else - { - mDone = true; - } - - if (bCollectible) - { - mLoaderAllocatorObjectHandle = loaderAllocatorObjectHandle; - if (mDone) - { - // There are no object references, but there is still a reference for - // collectible types - the LoaderAllocator for GC - mCurr = mLoaderAllocatorObjectHandle; - mDone = false; - } - } - } - - const TADDR GCHeap::HeapStart = 0; const TADDR GCHeap::HeapEnd = ~0; diff --git a/src/SOS/Strike/sos.h b/src/SOS/Strike/sos.h index b514244d95..c0fed3a3b2 100644 --- a/src/SOS/Strike/sos.h +++ b/src/SOS/Strike/sos.h @@ -452,77 +452,6 @@ namespace sos mutable WCHAR *mTypeName; }; - /* Enumerates all the GC references (objects) contained in an object. This uses the GCDesc - * map exactly as the GC does. - */ - class RefIterator - { - public: - RefIterator(TADDR obj, LinearReadCache *cache = NULL); - RefIterator(TADDR obj, CGCDesc *desc, bool arrayOfVC, LinearReadCache *cache = NULL); - ~RefIterator(); - - /* Moves to the next reference in the object. - */ - const RefIterator &operator++(); - - /* Returns the address of the current reference. - */ - TADDR operator*() const; - - /* Gets the offset into the object where the current reference comes from. - */ - TADDR GetOffset() const; - - /* Returns true if there are more objects in the iteration, false otherwise. - * Used as: - * if (itr) - * ... - */ - inline operator void *() const - { - return (void*)!mDone; - } - - bool IsLoaderAllocator() const - { - return mLoaderAllocatorObjectHandle == mCurr; - } - - private: - void Init(); - inline TADDR ReadPointer(TADDR addr) const - { - if (mCache) - { - if (!mCache->Read(addr, &addr, false)) - Throw("Could not read address %p.", addr); - } - else - { - MOVE(addr, addr); - } - - return addr; - } - - private: - LinearReadCache *mCache; - CGCDesc *mGCDesc; - bool mArrayOfVC, mDone; - - TADDR *mBuffer; - CGCDescSeries *mCurrSeries; - - TADDR mLoaderAllocatorObjectHandle; - - int i, mCount; - - TADDR mCurr, mStop, mObject; - size_t mObjSize; - }; - - /* The Iterator used to walk the managed objects on the GC heap. * The general usage pattern for this class is: * for (ObjectIterator itr = gcheap.WalkHeap(); itr; ++itr) @@ -580,27 +509,6 @@ namespace sos return bLarge; } - /* Verifies the current object. Returns true if the current object is valid. - * Returns false and fills 'buffer' with the reason the object is corrupted. - * This is a deeper validation than Object::IsValid as it checks the card - * table entires for the object in addition to the rest of the references. - * This function does not throw exceptions. - * Params: - * buffer - out buffer that is filled if and only if this function returns - * false. - * size - the total size of the buffer - * Returns: - * True if the object is valid, false otherwise. - */ - bool Verify(__out_ecount(size) char *buffer, size_t size) const; - - /* The same as Verify(char*, size_t), except it does not write out the failure - * reason to a provided buffer. - * See: - * ObjectIterator::Verify(char *, size_t) - */ - bool Verify() const; - /* Attempts to move to the next object (similar to ObjectIterator++), but * attempts to recover from any heap corruption by skipping to the next * segment. If Verify returns false, meaning it detected heap corruption @@ -622,9 +530,6 @@ namespace sos private: ObjectIterator(const GCHeapDetails *heap, int numHeaps, TADDR start, TADDR stop); - bool VerifyObjectMembers(__out_ecount(size) char *buffer, size_t size) const; - void BuildError(__out_ecount(count) char *out, size_t count, const char *format, ...) const; - void AssertSanity() const; /* diff --git a/src/SOS/Strike/strike.cpp b/src/SOS/Strike/strike.cpp index 08b39a1a23..410a8ea409 100644 --- a/src/SOS/Strike/strike.cpp +++ b/src/SOS/Strike/strike.cpp @@ -2192,11 +2192,9 @@ DECLARE_API(DumpObj) if (SUCCEEDED(Status) && bRefs) { - ExtOut("GC Refs:\n"); - TableOutput out(2, POINTERSIZE_HEX, AlignRight, 4); - out.WriteRow("offset", "object"); - for (sos::RefIterator itr(TO_TADDR(p_Object)); itr; ++itr) - out.WriteRow(Hex(itr.GetOffset()), ObjectPtr(*itr)); + std::stringstream argsBuilder; + argsBuilder << std::hex << p_Object << " "; + return ExecuteCommand("dumpobjgcrefs", argsBuilder.str().c_str()); } } catch(const sos::Exception &e) @@ -3652,114 +3650,11 @@ DECLARE_API(TraverseHeap) return ExecuteCommand("traverseheap", args); } -struct PrintRuntimeTypeArgs -{ - DWORD_PTR mtOfRuntimeType; - int handleFieldOffset; - DacpAppDomainStoreData adstore; -}; - -void PrintRuntimeTypes(DWORD_PTR objAddr,size_t Size,DWORD_PTR methodTable,LPVOID token) -{ - PrintRuntimeTypeArgs *pArgs = (PrintRuntimeTypeArgs *)token; - - if (pArgs->mtOfRuntimeType == NULL) - { - NameForMT_s(methodTable, g_mdName, mdNameLen); - - if (_wcscmp(g_mdName, W("System.RuntimeType")) == 0) - { - pArgs->mtOfRuntimeType = methodTable; - pArgs->handleFieldOffset = GetObjFieldOffset(TO_CDADDR(objAddr), TO_CDADDR(methodTable), W("m_handle")); - if (pArgs->handleFieldOffset <= 0) - ExtOut("Error getting System.RuntimeType.m_handle offset\n"); - - pArgs->adstore.Request(g_sos); - } - } - - if ((methodTable == pArgs->mtOfRuntimeType) && (pArgs->handleFieldOffset > 0)) - { - // Get the method table and display the information. - DWORD_PTR mtPtr; - if (MOVE(mtPtr, objAddr + pArgs->handleFieldOffset) == S_OK) - { - DMLOut(DMLObject(objAddr)); - - // Check if TypeDesc - if ((mtPtr & RUNTIMETYPE_HANDLE_IS_TYPEDESC) != 0) - { - ExtOut(" %p\n", mtPtr & ~RUNTIMETYPE_HANDLE_IS_TYPEDESC); - } - else - { - CLRDATA_ADDRESS appDomain = GetAppDomainForMT(mtPtr); - if (appDomain != NULL) - { - if (appDomain == pArgs->adstore.sharedDomain) - ExtOut(" %" POINTERSIZE "s", "Shared"); - - else if (appDomain == pArgs->adstore.systemDomain) - ExtOut(" %" POINTERSIZE "s", "System"); - else - DMLOut(" %s", DMLDomain(appDomain)); - } - else - { - ExtOut(" %" POINTERSIZE "s", "?"); - } - - if (NameForMT_s(mtPtr, g_mdName, mdNameLen)) - { - DMLOut(" %s %S\n", DMLMethodTable(mtPtr), g_mdName); - } - } - } - } -} - - DECLARE_API(DumpRuntimeTypes) { - INIT_API(); + INIT_API_EXT(); MINIDUMP_NOT_SUPPORTED(); - - BOOL dml = FALSE; - - CMDOption option[] = - { // name, vptr, type, hasValue - {"/d", &dml, COBOOL, FALSE}, - }; - - if (!GetCMDOption(args, option, ARRAY_SIZE(option), NULL, 0, NULL)) - return Status; - - EnableDMLHolder dmlHolder(dml); - - ExtOut("%" POINTERSIZE "s %" POINTERSIZE "s %" POINTERSIZE "s Type Name \n", - "Address", "Domain", "MT"); - ExtOut("------------------------------------------------------------------------------\n"); - - if (!g_snapshot.Build()) - { - ExtOut("Unable to build snapshot of the garbage collector state\n"); - return E_FAIL; - } - - PrintRuntimeTypeArgs pargs; - ZeroMemory(&pargs, sizeof(PrintRuntimeTypeArgs)); - - try - { - GCHeapsTraverse(PrintRuntimeTypes, (LPVOID)&pargs); - } - catch(const sos::Exception &e) - { - ExtOut("%s\n", e.what()); - return E_FAIL; - } - - return Status; + return ExecuteCommand("dumpruntimetypes", args); } namespace sos @@ -3823,65 +3718,10 @@ DECLARE_API(AnalyzeOOM) DECLARE_API(VerifyObj) { - INIT_API(); + INIT_API_EXT(); MINIDUMP_NOT_SUPPORTED(); - TADDR taddrObj = 0; - TADDR taddrMT; - size_t objSize; - - BOOL bValid = FALSE; - BOOL dml = FALSE; - - CMDOption option[] = - { // name, vptr, type, hasValue - {"/d", &dml, COBOOL, FALSE}, - }; - CMDValue arg[] = - { // vptr, type - {&taddrObj, COHEX} - }; - size_t nArg; - if (!GetCMDOption(args, option, ARRAY_SIZE(option), arg, ARRAY_SIZE(arg), &nArg)) - { - return Status; - } - - EnableDMLHolder dmlHolder(dml); - BOOL bContainsPointers; - - if (FAILED(GetMTOfObject(taddrObj, &taddrMT)) || - !GetSizeEfficient(taddrObj, taddrMT, FALSE, objSize, bContainsPointers)) - { - ExtOut("object %#p does not have valid method table\n", SOS_PTR(taddrObj)); - goto Exit; - } - - // we need to build g_snapshot as it is later used in GetGeneration - if (!g_snapshot.Build()) - { - ExtOut("Unable to build snapshot of the garbage collector state\n"); - goto Exit; - } - - try - { - GCHeapDetails *pheapDetails = g_snapshot.GetHeap(taddrObj); - bValid = VerifyObject(*pheapDetails, taddrObj, taddrMT, objSize, TRUE); - } - catch(const sos::Exception &e) - { - ExtOut("%s\n", e.what()); - return E_FAIL; - } - -Exit: - if (bValid) - { - ExtOut("object %#p is a valid object\n", SOS_PTR(taddrObj)); - } - - return Status; + return ExecuteCommand("verifyobj", args); } DECLARE_API(ListNearObj) diff --git a/src/SOS/Strike/util.h b/src/SOS/Strike/util.h index 6400aafa50..9fd90c7ba0 100644 --- a/src/SOS/Strike/util.h +++ b/src/SOS/Strike/util.h @@ -2043,10 +2043,6 @@ HRESULT GetModuleFromAddress(___in CLRDATA_ADDRESS peAddress, ___out IXCLRDataMo void GetInfoFromName(DWORD_PTR ModuleAddr, const char* name, mdTypeDef* retMdTypeDef=NULL); void GetInfoFromModule (DWORD_PTR ModuleAddr, ULONG token, DWORD_PTR *ret=NULL); - -typedef void (*VISITGCHEAPFUNC)(DWORD_PTR objAddr,size_t Size,DWORD_PTR methodTable,LPVOID token); -BOOL GCHeapsTraverse(VISITGCHEAPFUNC pFunc, LPVOID token, BOOL verify=true); - ///////////////////////////////////////////////////////////////////////////////////////////////////////// struct strobjInfo @@ -2080,11 +2076,6 @@ void GatherOneHeapFinalization(DacpGcHeapDetails& heapDetails, HeapStat *stat, B CLRDATA_ADDRESS GetAppDomainForMT(CLRDATA_ADDRESS mtPtr); CLRDATA_ADDRESS GetAppDomain(CLRDATA_ADDRESS objPtr); -BOOL VerifyObject(const GCHeapDetails &heap, const DacpHeapSegmentData &seg, DWORD_PTR objAddr, DWORD_PTR MTAddr, size_t objSize, - BOOL bVerifyMember); -BOOL VerifyObject(const GCHeapDetails &heap, DWORD_PTR objAddr, DWORD_PTR MTAddr, size_t objSize, - BOOL bVerifyMember); - BOOL IsMTForFreeObj(DWORD_PTR pMT); void DumpStackObjectsHelper (TADDR StackTop, TADDR StackBottom, BOOL verifyFields); diff --git a/src/SOS/lldbplugin/soscommand.cpp b/src/SOS/lldbplugin/soscommand.cpp index 24b5a6e654..a5dbbbefc5 100644 --- a/src/SOS/lldbplugin/soscommand.cpp +++ b/src/SOS/lldbplugin/soscommand.cpp @@ -177,7 +177,7 @@ sosCommandInitialize(lldb::SBDebugger debugger) g_services->AddCommand("dumpmodule", new sosCommand("DumpModule"), "Displays information about a EE module structure at the specified address."); g_services->AddCommand("dumpmt", new sosCommand("DumpMT"), "Displays information about a method table at the specified address."); g_services->AddCommand("dumpobj", new sosCommand("DumpObj"), "Displays info about an object at the specified address."); - g_services->AddCommand("dumpruntimetypes", new sosCommand("DumpRuntimeTypes"), "Finds all System.RuntimeType objects in the GC heap and prints the type name and MethodTable they refer too."); + g_services->AddManagedCommand("dumpruntimetypes", "Finds all System.RuntimeType objects in the GC heap and prints the type name and MethodTable they refer too."); g_services->AddCommand("dumpsig", new sosCommand("DumpSig"), "Dumps the signature of a method or field specified by ' '."); g_services->AddCommand("dumpsigelem", new sosCommand("DumpSigElem"), "Dumps a single element of a signature object."); g_services->AddCommand("dumpstack", new sosCommand("DumpStack"), "Displays a native and managed stack trace."); @@ -223,6 +223,6 @@ sosCommandInitialize(lldb::SBDebugger debugger) g_services->AddCommand("threadstate", new sosCommand("ThreadState"), "Pretty prints the meaning of a threads state."); g_services->AddCommand("token2ee", new sosCommand("token2ee"), "Displays the MethodTable structure and MethodDesc structure for the specified token and module."); g_services->AddManagedCommand("verifyheap", "Checks the GC heap for signs of corruption."); - g_services->AddCommand("verifyobj", new sosCommand("VerifyObj"), "Checks the object that is passed as an argument for signs of corruption."); + g_services->AddManagedCommand("verifyobj", "Checks the object that is passed as an argument for signs of corruption."); return true; } From ffe9a0f6ec189f675d3ba6d59bbd07beb60dfc21 Mon Sep 17 00:00:00 2001 From: Thays Grazia Date: Wed, 12 Apr 2023 18:37:05 -0300 Subject: [PATCH 016/111] Support debug connecting to a remote port (#3813) * support for connect to remote port * Fix compilation Add \n in the last line of dbgshim.h Remove sleep to attach debugger. Add exports. --- src/dbgshim/dbgshim.cpp | 43 +++++++++++++++++++++++++++++ src/dbgshim/dbgshim.h | 7 +++++ src/dbgshim/dbgshim.ntdef | 1 + src/dbgshim/dbgshim_unixexports.src | 1 + 4 files changed, 52 insertions(+) diff --git a/src/dbgshim/dbgshim.cpp b/src/dbgshim/dbgshim.cpp index 5b9ac973f3..a68d1ad650 100644 --- a/src/dbgshim/dbgshim.cpp +++ b/src/dbgshim/dbgshim.cpp @@ -157,6 +157,11 @@ typedef HRESULT (STDAPICALLTYPE *FPCoreCLRCreateCordbObject3)( HMODULE hmodTargetCLR, IUnknown **ppCordb); +typedef HRESULT (STDAPICALLTYPE *FPCreateRemoteCordbObject)( + DWORD port, + LPCSTR assemblyBasePath, + IUnknown **ppCordb); + HRESULT CreateCoreDbg( HMODULE hCLRModule, DWORD processId, @@ -2151,3 +2156,41 @@ CLRCreateInstance( return pDebuggingImpl->QueryInterface(riid, ppInterface); } + +HRESULT CreateCoreDbgRemotePort(HMODULE hDBIModule, DWORD portId, LPCSTR assemblyBasePath, IUnknown **ppCordb) +{ + HRESULT hr = S_OK; + + FPCreateRemoteCordbObject fpCreate = + (FPCreateRemoteCordbObject)GetProcAddress(hDBIModule, "CreateRemoteCordbObject"); + if (fpCreate == NULL) + { + return CORDBG_E_INCOMPATIBLE_PROTOCOL; + } + + return fpCreate(portId, assemblyBasePath, ppCordb); + + return hr; +} + +DLLEXPORT +HRESULT +RegisterForRuntimeStartupRemotePort( + _In_ DWORD dwRemotePortId, + _In_ LPCSTR mscordbiPath, + _In_ LPCSTR assemblyBasePath, + _Out_ IUnknown ** ppCordb) +{ + HRESULT hr = S_OK; + HMODULE hMod = NULL; + + hMod = LoadLibraryA(mscordbiPath); + if (hMod == NULL) + { + hr = CORDBG_E_DEBUG_COMPONENT_MISSING; + return hr; + } + + hr = CreateCoreDbgRemotePort(hMod, dwRemotePortId, assemblyBasePath, ppCordb); + return S_OK; +} diff --git a/src/dbgshim/dbgshim.h b/src/dbgshim/dbgshim.h index 34c71e5152..b186a5da8c 100644 --- a/src/dbgshim/dbgshim.h +++ b/src/dbgshim/dbgshim.h @@ -105,3 +105,10 @@ CreateDebuggingInterfaceFromVersion3( _In_ LPCWSTR szApplicationGroupId, _In_ ICLRDebuggingLibraryProvider3* pLibraryProvider, _Out_ IUnknown ** ppCordb); + +EXTERN_C HRESULT +RegisterForRuntimeStartupRemotePort( + _In_ DWORD dwRemotePortId, + _In_ LPCSTR mscordbiPath, + _In_ LPCSTR assemblyBasePath, + _Out_ IUnknown ** ppCordb); diff --git a/src/dbgshim/dbgshim.ntdef b/src/dbgshim/dbgshim.ntdef index 8b6572e1f0..c06fc5e399 100644 --- a/src/dbgshim/dbgshim.ntdef +++ b/src/dbgshim/dbgshim.ntdef @@ -18,3 +18,4 @@ EXPORTS CreateDebuggingInterfaceFromVersion2 CreateDebuggingInterfaceFromVersion3 CLRCreateInstance + RegisterForRuntimeStartupRemotePort diff --git a/src/dbgshim/dbgshim_unixexports.src b/src/dbgshim/dbgshim_unixexports.src index fae2869f38..709b33705f 100644 --- a/src/dbgshim/dbgshim_unixexports.src +++ b/src/dbgshim/dbgshim_unixexports.src @@ -17,3 +17,4 @@ CreateDebuggingInterfaceFromVersionEx CreateDebuggingInterfaceFromVersion2 CreateDebuggingInterfaceFromVersion3 CLRCreateInstance +RegisterForRuntimeStartupRemotePort From 549ded918e620df61b4dd30c4fe516bde8aad182 Mon Sep 17 00:00:00 2001 From: Lee Culver Date: Thu, 13 Apr 2023 08:18:29 -0700 Subject: [PATCH 017/111] Implement !threadpool in C# (#3824) * Add initial ThreadPoolCommand Only implemented dumping work items. * Remove -live * Fix issue with Marshal.SizeOf Marshal.SizeOf does not allow enums. Unsafe.SizeOf is what we want here. * Implement the remainder of ThreadPool * Use C# version of !threadpool * Remove ObjectIterator and GCHeap * Bump clrmd version * Fix issue with usingPortableCompletionPorts threadPool.Portable means that we found a PortableThreadPool in the BCL. We need to check that we found that portable threadpool and also that the PortableIOField is true (or missing), instead of if the portable threadpool exists at all. * Move cancellation to inside the loop --- eng/Version.Details.xml | 8 +- eng/Versions.props | 2 +- .../DataReader.cs | 2 +- .../ThreadPoolCommand.cs | 242 +++++++ src/SOS/SOS.Hosting/Commands/SOSCommand.cs | 1 - src/SOS/Strike/sos.cpp | 316 ---------- src/SOS/Strike/sos.h | 164 ----- src/SOS/Strike/strike.cpp | 589 +----------------- src/SOS/Strike/util.cpp | 178 ------ src/SOS/Strike/util.h | 1 - src/SOS/lldbplugin/soscommand.cpp | 2 +- 11 files changed, 251 insertions(+), 1254 deletions(-) create mode 100644 src/Microsoft.Diagnostics.ExtensionCommands/ThreadPoolCommand.cs diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 6dfbbd8a91..e6f3099c90 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -4,13 +4,13 @@ https://github.com/dotnet/symstore e09f81a0b38786cb20f66b589a8b88b6997a62da - + https://github.com/microsoft/clrmd - 677f1b9c6fa27b1d2988eac9d51c8a5ea8698fdd + d68eb893272971726b08473935d2c7d088d1db5c - + https://github.com/microsoft/clrmd - 677f1b9c6fa27b1d2988eac9d51c8a5ea8698fdd + d68eb893272971726b08473935d2c7d088d1db5c diff --git a/eng/Versions.props b/eng/Versions.props index cf0b959d03..cecc4b1342 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -45,7 +45,7 @@ 5.0.0 6.0.0 - 3.0.0-beta.23210.1 + 3.0.0-beta.23212.1 16.9.0-beta1.21055.5 3.0.7 6.0.0 diff --git a/src/Microsoft.Diagnostics.DebugServices.Implementation/DataReader.cs b/src/Microsoft.Diagnostics.DebugServices.Implementation/DataReader.cs index b32038d540..89716bf326 100644 --- a/src/Microsoft.Diagnostics.DebugServices.Implementation/DataReader.cs +++ b/src/Microsoft.Diagnostics.DebugServices.Implementation/DataReader.cs @@ -83,7 +83,7 @@ int IMemoryReader.Read(ulong address, Span buffer) bool IMemoryReader.Read(ulong address, out T value) { - Span buffer = stackalloc byte[Marshal.SizeOf()]; + Span buffer = stackalloc byte[Unsafe.SizeOf()]; if (((IMemoryReader)this).Read(address, buffer) == buffer.Length) { value = Unsafe.As(ref MemoryMarshal.GetReference(buffer)); diff --git a/src/Microsoft.Diagnostics.ExtensionCommands/ThreadPoolCommand.cs b/src/Microsoft.Diagnostics.ExtensionCommands/ThreadPoolCommand.cs new file mode 100644 index 0000000000..074bb5321d --- /dev/null +++ b/src/Microsoft.Diagnostics.ExtensionCommands/ThreadPoolCommand.cs @@ -0,0 +1,242 @@ +// 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.Collections.Generic; +using System.Linq; +using Microsoft.Diagnostics.DebugServices; +using Microsoft.Diagnostics.Runtime; +using static Microsoft.Diagnostics.ExtensionCommands.TableOutput; + +namespace Microsoft.Diagnostics.ExtensionCommands +{ + [Command(Name = "threadpool", Help = "Displays info about the runtime thread pool.")] + public sealed class ThreadPoolCommand : CommandBase + { + [ServiceImport] + public ClrRuntime Runtime { get; set; } + + [Option(Name = "-ti", Help = "Print the hill climbing log.", Aliases = new string[] { "-hc" })] + public bool PrintHillClimbingLog { get; set; } + + [Option(Name = "-wi", Help = "Print all work items that are queued.")] + public bool PrintWorkItems { get; set; } + + public override void Invoke() + { + // Runtime.ThreadPool shouldn't be null unless there was a problem with the dump. + ClrThreadPool threadPool = Runtime.ThreadPool; + if (threadPool is null) + { + Console.WriteLineError("Failed to obtain ThreadPool data."); + } + else + { + TableOutput output = new(Console, (17, "")); + output.WriteRow("CPU utilization:", $"{threadPool.CpuUtilization}%"); + output.WriteRow("Workers Total:", threadPool.ActiveWorkerThreads + threadPool.IdleWorkerThreads + threadPool.RetiredWorkerThreads); + output.WriteRow("Workers Running:", threadPool.ActiveWorkerThreads); + output.WriteRow("Workers Idle:", threadPool.IdleWorkerThreads); + output.WriteRow("Worker Min Limit:", threadPool.MinThreads); + output.WriteRow("Worker Max Limit:", threadPool.MaxThreads); + Console.WriteLine(); + + ClrType threadPoolType = Runtime.BaseClassLibrary.GetTypeByName("System.Threading.ThreadPool"); + ClrStaticField usePortableIOField = threadPoolType?.GetStaticFieldByName("UsePortableThreadPoolForIO"); + + // Desktop CLR work items. + if (PrintWorkItems) + { + LegacyThreadPoolWorkRequest[] requests = threadPool.EnumerateLegacyWorkRequests().ToArray(); + if (requests.Length > 0) + { + Console.WriteLine($"Work Request in Queue: {requests.Length:n0}"); + foreach (LegacyThreadPoolWorkRequest request in requests) + { + Console.CancellationToken.ThrowIfCancellationRequested(); + + if (request.IsAsyncTimerCallback) + { + Console.WriteLine($" AsyncTimerCallbackCompletion TimerInfo@{request.Context:x}"); + } + else + { + Console.WriteLine($" Unknown Function: {request.Function:x} Context: {request.Context:x}"); + } + } + } + } + + // We will assume that if UsePortableThreadPoolForIO field is deleted from ThreadPool then we are always + // using C# version. + bool usingPortableCompletionPorts = threadPool.Portable && (usePortableIOField is null || usePortableIOField.Read(usePortableIOField.Type.Module.AppDomain)); + if (!usingPortableCompletionPorts) + { + output = new(Console, (17, "")); + output.WriteRow("Completion Total:", threadPool.TotalCompletionPorts); + output.WriteRow("Completion Free:", threadPool.FreeCompletionPorts); + output.WriteRow("Completion MaxFree:", threadPool.MaxFreeCompletionPorts); + output.WriteRow("Completion Current Limit:", threadPool.CompletionPortCurrentLimit); + output.WriteRow("Completion Min Limit:", threadPool.MinCompletionPorts); + output.WriteRow("Completion Max Limit:", threadPool.MaxCompletionPorts); + Console.WriteLine(); + } + + if (PrintHillClimbingLog) + { + HillClimbingLogEntry[] hcl = threadPool.EnumerateHillClimbingLog().ToArray(); + if (hcl.Length > 0) + { + output = new(Console, (10, ""), (19, ""), (12, "n0"), (12, "n0")); + + Console.WriteLine("Hill Climbing Log:"); + output.WriteRow("Time", "Transition", "#New Threads", "#Samples", "Throughput"); + + int end = hcl.Last().TickCount; + foreach (HillClimbingLogEntry entry in hcl) + { + Console.CancellationToken.ThrowIfCancellationRequested(); + output.WriteRow($"{(entry.TickCount - end)/1000.0:0.00}", entry.StateOrTransition, entry.NewControlSetting, entry.LastHistoryCount, $"{entry.LastHistoryMean:0.00}"); + } + + Console.WriteLine(); + } + } + } + + // We can print managed work items even if we failed to request the ThreadPool. + if (PrintWorkItems && (threadPool is null || threadPool.Portable)) + { + DumpWorkItems(); + } + } + + private void DumpWorkItems() + { + TableOutput output = null; + + ClrType workQueueType = Runtime.BaseClassLibrary.GetTypeByName("System.Threading.ThreadPoolWorkQueue"); + ClrType workStealingQueueType = Runtime.BaseClassLibrary.GetTypeByName("System.Threading.ThreadPoolWorkQueue+WorkStealingQueue"); + + foreach (ClrObject obj in Runtime.Heap.EnumerateObjects()) + { + Console.CancellationToken.ThrowIfCancellationRequested(); + + if (obj.Type == workQueueType) + { + if (obj.TryReadObjectField("highPriorityWorkItems", out ClrObject workItems)) + { + foreach (ClrObject entry in EnumerateConcurrentQueue(workItems)) + { + WriteEntry(ref output, entry, isHighPri: true); + } + } + + if (obj.TryReadObjectField("workItems", out workItems)) + { + foreach (ClrObject entry in EnumerateConcurrentQueue(workItems)) + { + WriteEntry(ref output, entry, isHighPri: false); + } + } + + if (obj.Type.Fields.Any(r => r.Name == "_assignableWorkItems")) + { + if (obj.TryReadObjectField("_assignableWorkItems", out workItems)) + { + foreach (ClrObject entry in EnumerateConcurrentQueue(workItems)) + { + WriteEntry(ref output, entry, isHighPri: false); + } + } + } + } + else if (obj.Type == workStealingQueueType) + { + if (obj.TryReadObjectField("m_array", out ClrObject m_array) && m_array.IsValid && !m_array.IsNull) + { + ClrArray arrayView = m_array.AsArray(); + int len = Math.Min(8192, arrayView.Length); // ensure a sensible max in case we have heap corruption + + nuint[] buffer = arrayView.ReadValues(0, len); + if (buffer != null) + { + for (int i = 0; i < len; i++) + { + if (buffer[i] != 0) + { + ClrObject entry = Runtime.Heap.GetObject(buffer[i]); + if (entry.IsValid && !entry.IsNull) + { + WriteEntry(ref output, entry, isHighPri: false); + } + } + } + } + } + } + } + } + + private void WriteEntry(ref TableOutput output, ClrObject entry, bool isHighPri) + { + if (output is null) + { + output = new(Console, (17, ""), (16, "x12")) + { + AlignLeft = true, + }; + + output.WriteRow("Queue", "Object", "Type"); + } + + output.WriteRow(isHighPri ? "[Global high-pri]" : "[Global]", new DmlDumpObj(entry), entry.Type?.Name); + if (entry.IsDelegate) + { + ClrDelegate del = entry.AsDelegate(); + ClrDelegateTarget target = del.GetDelegateTarget(); + if (target is not null) + { + Console.WriteLine($" => {target.TargetObject.Address:x} {target.Method.Name}"); + } + } + } + + private IEnumerable EnumerateConcurrentQueue(ClrObject concurrentQueue) + { + if (!concurrentQueue.IsValid || concurrentQueue.IsNull) + { + yield break; + } + + if (concurrentQueue.TryReadObjectField("_head", out ClrObject curr)) + { + while (curr.IsValid && !curr.IsNull) + { + Console.CancellationToken.ThrowIfCancellationRequested(); + + if (curr.TryReadObjectField("_slots", out ClrObject slots) && slots.IsValid && slots.IsArray) + { + ClrArray slotsArray = slots.AsArray(); + for (int i = 0; i < slotsArray.Length; i++) + { + Console.CancellationToken.ThrowIfCancellationRequested(); + + ClrObject item = slotsArray.GetStructValue(i).ReadObjectField("Item"); + if (item.IsValid && !item.IsNull) + { + yield return item; + } + } + } + + if (!curr.TryReadObjectField("_nextSegment", out curr)) + { + Console.WriteLineError($"Error: Type '{slots.Type?.Name}' does not contain a '_nextSegment' field."); + break; + } + } + } + } + } +} diff --git a/src/SOS/SOS.Hosting/Commands/SOSCommand.cs b/src/SOS/SOS.Hosting/Commands/SOSCommand.cs index 7f740a181d..d398b19459 100644 --- a/src/SOS/SOS.Hosting/Commands/SOSCommand.cs +++ b/src/SOS/SOS.Hosting/Commands/SOSCommand.cs @@ -47,7 +47,6 @@ namespace SOS.Hosting [Command(Name = "printexception", DefaultOptions = "PrintException", Aliases = new string[] { "pe" }, Help = "Displays and formats fields of any object derived from the Exception class at the specified address.")] [Command(Name = "soshelp", DefaultOptions = "Help", Help = "Displays help for a specific SOS command.")] [Command(Name = "syncblk", DefaultOptions = "SyncBlk", Help = "Displays the SyncBlock holder info.")] - [Command(Name = "threadpool", DefaultOptions = "ThreadPool", Help = "Lists basic information about the thread pool.")] [Command(Name = "threadstate", DefaultOptions = "ThreadState", Help = "Pretty prints the meaning of a threads state.")] [Command(Name = "comstate", DefaultOptions = "COMState", Flags = CommandFlags.Windows, Help = "Lists the COM apartment model for each thread.")] [Command(Name = "dumprcw", DefaultOptions = "DumpRCW", Flags = CommandFlags.Windows, Help = "Displays information about a Runtime Callable Wrapper.")] diff --git a/src/SOS/Strike/sos.cpp b/src/SOS/Strike/sos.cpp index d637289253..3a9e528eec 100644 --- a/src/SOS/Strike/sos.cpp +++ b/src/SOS/Strike/sos.cpp @@ -376,322 +376,6 @@ namespace sos return (size_t)stInfo.m_StringLength; } - const TADDR GCHeap::HeapStart = 0; - const TADDR GCHeap::HeapEnd = ~0; - - ObjectIterator::ObjectIterator(const GCHeapDetails *heap, int numHeaps, TADDR start, TADDR stop) - : bLarge(false), bPinned(false), mCurrObj(0), mLastObj(0), mStart(start), mEnd(stop), mSegmentEnd(0), mHeaps(heap), - mNumHeaps(numHeaps), mCurrHeap(0), mCurrRegionGen(0) - { - mAllocInfo.Init(); - SOS_Assert(numHeaps > 0); - - TADDR segStart; - if (heap->has_regions) - { - // with regions, we have a null terminated list for each generation - segStart = TO_TADDR(mHeaps[0].generation_table[mCurrRegionGen].start_segment); - } - else - { - segStart = TO_TADDR(mHeaps[0].generation_table[GetMaxGeneration()].start_segment); - } - if (FAILED(mSegment.Request(g_sos, segStart, mHeaps[0].original_heap_details))) - { - sos::Throw("Could not request segment data at %p.", segStart); - } - - mCurrObj = mStart < TO_TADDR(mSegment.mem) ? TO_TADDR(mSegment.mem) : mStart; - mSegmentEnd = TO_TADDR(mSegment.highAllocMark); - - TryAlignToObjectInRange(); - } - - bool ObjectIterator::TryMoveNextSegment() - { - CheckInterrupt(); - - if (mCurrHeap >= mNumHeaps) - { - return false; - } - - TADDR next = TO_TADDR(mSegment.next); - if (next == NULL) - { - if (mHeaps[mCurrHeap].has_regions) - { - mCurrRegionGen++; - if ((mCurrRegionGen > GetMaxGeneration() + 2) || - (mCurrRegionGen > GetMaxGeneration() + 1 && !mHeaps[mCurrHeap].has_poh)) - { - mCurrHeap++; - if (mCurrHeap == mNumHeaps) - { - return false; - } - mCurrRegionGen = 0; - } - next = TO_TADDR(mHeaps[mCurrHeap].generation_table[mCurrRegionGen].start_segment); - } - else if (bPinned || (bLarge && !mHeaps[mCurrHeap].has_poh)) - { - mCurrHeap++; - if (mCurrHeap == mNumHeaps) - { - return false; - } - - bPinned = false; - bLarge = false; - next = TO_TADDR(mHeaps[mCurrHeap].generation_table[GetMaxGeneration()].start_segment); - } - else if (bLarge) - { - bLarge = false; - bPinned = true; - next = TO_TADDR(mHeaps[mCurrHeap].generation_table[GetMaxGeneration() + 2].start_segment); - } - else - { - bLarge = true; - next = TO_TADDR(mHeaps[mCurrHeap].generation_table[GetMaxGeneration() + 1].start_segment); - } - } - - SOS_Assert(next != NULL); - if (FAILED(mSegment.Request(g_sos, next, mHeaps[mCurrHeap].original_heap_details))) - { - sos::Throw("Failed to request segment data at %p.", next); - } - - mLastObj = 0; - mCurrObj = mStart < TO_TADDR(mSegment.mem) ? TO_TADDR(mSegment.mem) : mStart; - mSegmentEnd = TO_TADDR(mSegment.highAllocMark); - return true; - } - - bool ObjectIterator::TryMoveToObjectInNextSegmentInRange() - { - if (TryMoveNextSegment()) - { - return TryAlignToObjectInRange(); - } - - return false; - } - - bool ObjectIterator::TryAlignToObjectInRange() - { - CheckInterrupt(); - while (!MemOverlap(mStart, mEnd, TO_TADDR(mSegment.mem), mSegmentEnd)) - { - CheckInterrupt(); - if (!TryMoveNextSegment()) - { - return false; - } - } - - // At this point we know that the current segment contains objects in - // the correct range. However, there's no telling if the user gave us - // a starting address that corresponds to an object. If mStart is a - // valid object, then we'll just start there. If it's not we'll need - // to walk the segment from the beginning to find the first aligned - // object on or after mStart. - if (mCurrObj == mStart && !Object::IsValid(mStart)) - { - // It's possible mCurrObj will equal mStart after this. That's fine. - // It means that the starting object is corrupt (and we'll figure - // that when the user calls GetNext), or IsValid was wrong. - mLastObj = 0; - mCurrObj = TO_TADDR(mSegment.mem); - while (mCurrObj < mStart) - MoveToNextObject(); - } - - return true; - } - - - - const Object &ObjectIterator::operator*() const - { - AssertSanity(); - return mCurrObj; - } - - - const Object *ObjectIterator::operator->() const - { - AssertSanity(); - return &mCurrObj; - } - - //Object ObjectIterator::GetNext() - const ObjectIterator &ObjectIterator::operator++() - { - CheckInterrupt(); - - // Assert we aren't done walking the heap. - SOS_Assert(*this); - AssertSanity(); - - MoveToNextObject(); - return *this; - } - - void ObjectIterator::MoveToNextObjectCarefully() - { - CheckInterrupt(); - - SOS_Assert(*this); - AssertSanity(); - - // Move to NextObject won't generally throw unless it fails to request the - // MethodTable of the object. At which point we won't know how large the - // current object is, nor how to move past it. In this case we'll simply - // move to the next segment if possible to continue iterating from there. - try - { - MoveToNextObject(); - } - catch(const sos::Exception &) - { - TryMoveToObjectInNextSegmentInRange(); - } - } - - void ObjectIterator::AssertSanity() const - { - // Assert that we are in a sane state. Function which call this assume two things: - // 1. That the current object is within the segment bounds. - // 2. That the current object is within the requested memory range. - SOS_Assert(mCurrObj >= TO_TADDR(mSegment.mem)); - SOS_Assert(mCurrObj <= TO_TADDR(mSegmentEnd - Align(min_obj_size))); - - SOS_Assert(mCurrObj >= mStart); - SOS_Assert(mCurrObj <= mEnd); - } - - void ObjectIterator::MoveToNextObject() - { - CheckInterrupt(); - - // Object::GetSize can be unaligned, so we must align it ourselves. - size_t size = (bLarge || bPinned) ? AlignLarge(mCurrObj.GetSize()) : Align(mCurrObj.GetSize()); - - mLastObj = mCurrObj; - mCurrObj = mCurrObj.GetAddress() + size; - - if (!bLarge) - { - // Is this the end of an allocation context? We need to know this because there can be - // allocated memory at the end of an allocation context that doesn't yet contain any objects. - // This happens because we actually allocate a minimum amount of memory (the allocation quantum) - // whenever we need to get more memory. Typically, a single allocation request won't fill this - // block, so we'll fulfill subsequent requests out of the remainder of the block until it's - // depleted. - int i; - for (i = 0; i < mAllocInfo.num; i ++) - { - if (mCurrObj == TO_TADDR(mAllocInfo.array[i].alloc_ptr)) // end of objects in this context - { - // Set mCurrObj to point after the context (alloc_limit is the end of the allocation context). - mCurrObj = TO_TADDR(mAllocInfo.array[i].alloc_limit) + Align(min_obj_size); - break; - } - } - - // We also need to look at the gen0 alloc context. - if (mCurrObj == TO_TADDR(mHeaps[mCurrHeap].generation_table[0].allocContextPtr)) - mCurrObj = TO_TADDR(mHeaps[mCurrHeap].generation_table[0].allocContextLimit) + Align(min_obj_size); - } - - if (mCurrObj > mEnd || mCurrObj >= mSegmentEnd) - { - TryMoveToObjectInNextSegmentInRange(); - } - } - - SyncBlkIterator::SyncBlkIterator() - : mCurr(1), mTotal(0) - { - // If DacpSyncBlockData::Request fails with the call "1", then it means - // there are no SyncBlocks in the process. - DacpSyncBlockData syncBlockData; - if (SUCCEEDED(syncBlockData.Request(g_sos, 1))) - { - mTotal = syncBlockData.SyncBlockCount; - mSyncBlk = mCurr; - } - } - - GCHeap::GCHeap() - { - if (FAILED(mHeapData.Request(g_sos))) - { - sos::Throw("Failed to request GC heap data."); - } - - if (mHeapData.bServerMode) - { - mNumHeaps = mHeapData.HeapCount; - DWORD dwAllocSize = 0; - if (!ClrSafeInt::multiply(sizeof(CLRDATA_ADDRESS), mNumHeaps, dwAllocSize)) - { - sos::Throw("Failed to get GCHeaps: Integer overflow."); - } - - CLRDATA_ADDRESS *heapAddrs = (CLRDATA_ADDRESS*)alloca(dwAllocSize); - if (FAILED(g_sos->GetGCHeapList(mNumHeaps, heapAddrs, NULL))) - { - sos::Throw("Failed to get GCHeaps."); - } - - mHeaps = new GCHeapDetails[mNumHeaps]; - - for (int i = 0; i < mNumHeaps; i++) - { - DacpGcHeapDetails dacHeapDetails; - if (FAILED(dacHeapDetails.Request(g_sos, heapAddrs[i]))) - { - sos::Throw("Failed to get GC heap details at %p.", heapAddrs[i]); - } - - mHeaps[i].Set(dacHeapDetails, heapAddrs[i]); - } - } - else - { - mHeaps = new GCHeapDetails[1]; - mNumHeaps = 1; - - DacpGcHeapDetails dacGCDetails; - if (FAILED(dacGCDetails.Request(g_sos))) - { - sos::Throw("Failed to request GC details data."); - } - - mHeaps[0].Set(dacGCDetails); - } - } - - GCHeap::~GCHeap() - { - delete [] mHeaps; - } - - ObjectIterator GCHeap::WalkHeap(TADDR start, TADDR stop) const - { - return ObjectIterator(mHeaps, mNumHeaps, start, stop); - } - - bool GCHeap::AreGCStructuresValid() const - { - return mHeapData.bGcStructuresValid != FALSE; - } - // SyncBlk class SyncBlk::SyncBlk() : mIndex(0) diff --git a/src/SOS/Strike/sos.h b/src/SOS/Strike/sos.h index c0fed3a3b2..170722378a 100644 --- a/src/SOS/Strike/sos.h +++ b/src/SOS/Strike/sos.h @@ -32,8 +32,6 @@ class CGCDescSeries; namespace sos { - class GCHeap; - /* The base SOS Exception. Note that most commands should not attempt to be * resilient to exceptions thrown by most functions here. Instead a top level * try/catch at the beginning of the command which prints out the exception's @@ -452,121 +450,6 @@ namespace sos mutable WCHAR *mTypeName; }; - /* The Iterator used to walk the managed objects on the GC heap. - * The general usage pattern for this class is: - * for (ObjectIterator itr = gcheap.WalkHeap(); itr; ++itr) - * itr->SomeObjectMethod(); - */ - class ObjectIterator - { - friend class GCHeap; - public: - - /* Returns the next object in the GCHeap. Note that you must ensure - * that there are more objects to walk before calling this function by - * checking "if (iterator)". If this function throws an exception, - * the the iterator is invalid, and should no longer be used to walk - * the heap. This should generally only happen if we cannot read the - * MethodTable of the object to move to the next object. - * Throws: - * DataRead - */ - const ObjectIterator &operator++(); - - /* Dereference operator. This allows you to take a reference to the - * current object. Note the lifetime of this reference is valid for - * either the lifetime of the iterator or until you call operator++, - * whichever is shorter. For example. - * void Foo(const Object ¶m); - * void Bar(const ObjectIterator &itr) - * { - * Foo(*itr); - * } - */ - const Object &operator*() const; - - /* Returns a pointer to the current Object to call members on it. - * The usage pattern for the iterator is to simply use operator-> - * to call methods on the Object it points to without taking a - * direct reference to the underlying Object if at all possible. - */ - const Object *operator->() const; - - /* Returns false when the iterator has reached the end of the managed - * heap. - */ - inline operator void *() const - { - return (void*)(SIZE_T)(mCurrHeap == mNumHeaps ? 0 : 1); - } - - /* Do not use. - * TODO: Replace this functionality with int Object::GetGeneration(). - */ - bool IsCurrObjectOnLOH() const - { - SOS_Assert(*this); - return bLarge; - } - - /* Attempts to move to the next object (similar to ObjectIterator++), but - * attempts to recover from any heap corruption by skipping to the next - * segment. If Verify returns false, meaning it detected heap corruption - * at the current object, you can use MoveToNextObjectCarefully instead of - * ObjectIterator++ to attempt to keep reading from the heap. If possible, - * this function attempts to move to the next object in the same segment, - * but if that's not possible then it skips to the next segment and - * continues from there. - * Note: - * This function can throw, and if it does then the iterator is no longer - * in a valid state. No further attempts to move to the next object will - * be possible. - * Throws: - * DataRead - if the heap is corrupted and it's not possible to continue - * walking the heap - */ - void MoveToNextObjectCarefully(); - - private: - ObjectIterator(const GCHeapDetails *heap, int numHeaps, TADDR start, TADDR stop); - - void AssertSanity() const; - - /* - This function moves to the next segment/region without checking any restrictions - on the range. Returns true if it was able to move to a new segment/region. - */ - bool TryMoveNextSegment(); - - /* - Aligns the iterator to the object that falls in the requested range, moving to - the next segment/region as necessary. The iterator state doesn't change if the - current object already lies in the requested range. Returns true if aligning - to such an object was possible. - */ - bool TryAlignToObjectInRange(); - - /* - Moves to the next segment/region that contains an object in the requested - range and align it to such object. This operation always moves the iterator. - Returns false if no such move was possible. - */ - bool TryMoveToObjectInNextSegmentInRange(); - void MoveToNextObject(); - - private: - DacpHeapSegmentData mSegment; - bool bLarge; - bool bPinned; - Object mCurrObj; - TADDR mLastObj, mStart, mEnd, mSegmentEnd; - AllocInfo mAllocInfo; - const GCHeapDetails *mHeaps; - int mNumHeaps; - int mCurrHeap; - unsigned mCurrRegionGen; - }; - /* Reprensents an entry in the sync block table. */ class SyncBlk @@ -671,53 +554,6 @@ namespace sos SyncBlk mSyncBlk; }; - /* An class which contains information about the GCHeap. - */ - class GCHeap - { - public: - static const TADDR HeapStart; // A constant signifying the start of the GC heap. - static const TADDR HeapEnd; // A constant signifying the end of the GC heap. - - public: - /* Constructor. - * Throws: - * DataRead - */ - GCHeap(); - - ~GCHeap(); - - /* Returns an ObjectIterator which allows you to walk the objects on the managed heap. - * This ObjectIterator is valid for the duration of the GCHeap's lifetime. Note that - * if you specify an address at which you wish to start walking the heap it need - * not point directly to a managed object. However, if it does not, WalkHeap - * will need to walk the segment that address resides in to find the first object - * after that address, and if it encounters any heap corruption along the way, - * it may be impossible to walk the heap from the address specified. - * - * Params: - * start - The starting address at which you want to start walking the heap. - * This need not point directly to an object on the heap. - * end - The ending address at which you want to stop walking the heap. This - * need not point directly to an object on the heap. - * validate - Whether or not you wish to validate the GC heap as you walk it. - * Throws: - * DataRead - */ - ObjectIterator WalkHeap(TADDR start = HeapStart, TADDR stop = HeapEnd) const; - - /* Returns true if the GC Heap structures are in a valid state for traversal. - * Returns false if not (e.g. if we are in the middle of a relocation). - */ - bool AreGCStructuresValid() const; - - private: - GCHeapDetails *mHeaps; - DacpGcHeapData mHeapData; - int mNumHeaps; - }; - // convenience functions /* A temporary wrapper function for Object::IsValid. There are too many locations * in SOS which need to use IsObject but have a wide variety of internal diff --git a/src/SOS/Strike/strike.cpp b/src/SOS/Strike/strike.cpp index 410a8ea409..f0efe93e8c 100644 --- a/src/SOS/Strike/strike.cpp +++ b/src/SOS/Strike/strike.cpp @@ -6597,595 +6597,10 @@ DECLARE_API(bpmd) \**********************************************************************/ DECLARE_API(ThreadPool) { - INIT_API(); + INIT_API_EXT(); MINIDUMP_NOT_SUPPORTED(); - BOOL doHCDump = FALSE, doWorkItemDump = FALSE, dml = FALSE; - BOOL mustBePortableThreadPool = FALSE; - - CMDOption option[] = - { // name, vptr, type, hasValue - {"-ti", &doHCDump, COBOOL, FALSE}, - {"-wi", &doWorkItemDump, COBOOL, FALSE}, - {"/d", &dml, COBOOL, FALSE}, - }; - - if (!GetCMDOption(args, option, ARRAY_SIZE(option), NULL, 0, NULL)) - { - return E_FAIL; - } - - EnableDMLHolder dmlHolder(dml); - - DacpThreadpoolData threadpool; - Status = threadpool.Request(g_sos); - if (Status == E_NOTIMPL) - { - mustBePortableThreadPool = TRUE; - } - else if (Status != S_OK) - { - ExtOut(" %s\n", "Failed to request ThreadpoolMgr information"); - return FAILED(Status) ? Status : E_FAIL; - } - - DWORD_PTR corelibModule; - { - int numModule; - ArrayHolder moduleList = ModuleFromName(const_cast("System.Private.CoreLib.dll"), &numModule); - if (moduleList == NULL || numModule != 1) - { - ExtOut(" %s\n", "Failed to find System.Private.CoreLib.dll"); - return E_FAIL; - } - corelibModule = moduleList[0]; - } - - //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // Check whether the portable thread pool is being used and fill in the thread pool data - - UINT64 ui64Value = 0; - DacpObjectData vPortableTpHcLogArray; - int portableTpHcLogEntry_tickCountOffset = 0; - int portableTpHcLogEntry_stateOrTransitionOffset = 0; - int portableTpHcLogEntry_newControlSettingOffset = 0; - int portableTpHcLogEntry_lastHistoryCountOffset = 0; - int portableTpHcLogEntry_lastHistoryMeanOffset = 0; - do // while (false) - { - if (!mustBePortableThreadPool) - { - // Determine if the portable thread pool is enabled - if (FAILED( - GetNonSharedStaticFieldValueFromName( - &ui64Value, - corelibModule, - "System.Threading.ThreadPool", - W("UsePortableThreadPool"), - ELEMENT_TYPE_BOOLEAN)) || - ui64Value == 0) - { - // The type was not loaded yet, or the static field was not found, etc. For now assume that the portable thread pool - // is not being used. - break; - } - } - - // Get the thread pool instance - if (FAILED( - GetNonSharedStaticFieldValueFromName( - &ui64Value, - corelibModule, - "System.Threading.PortableThreadPool", - W("ThreadPoolInstance"), - ELEMENT_TYPE_CLASS)) || - ui64Value == 0) - { - // The type was not loaded yet, or the static field was not found, etc. For now assume that the portable thread pool - // is not being used. - break; - } - CLRDATA_ADDRESS cdaTpInstance = TO_CDADDR(ui64Value); - - // Get the thread pool method table - CLRDATA_ADDRESS cdaTpMethodTable; - { - TADDR tpMethodTableAddr = NULL; - if (FAILED(GetMTOfObject(TO_TADDR(cdaTpInstance), &tpMethodTableAddr))) - { - break; - } - cdaTpMethodTable = TO_CDADDR(tpMethodTableAddr); - } - - DWORD_PTR ptrValue = 0; - INT32 i32Value = 0; - INT16 i16Value = 0; - int offset = 0; - - // Populate fields of the thread pool with simple types - { - offset = GetObjFieldOffset(cdaTpInstance, cdaTpMethodTable, W("_cpuUtilization")); - if (offset <= 0 || FAILED(MOVE(i32Value, cdaTpInstance + offset))) - { - ExtOut(" %s\n", "Failed to read PortableThreadPool._cpuUtilization"); - break; - } - threadpool.cpuUtilization = i32Value; - - offset = GetObjFieldOffset(cdaTpInstance, cdaTpMethodTable, W("_minThreads")); - if (offset <= 0 || FAILED(MOVE(i16Value, cdaTpInstance + offset))) - { - ExtOut(" %s\n", "Failed to read PortableThreadPool._minThreads"); - break; - } - threadpool.MinLimitTotalWorkerThreads = i16Value; - - offset = GetObjFieldOffset(cdaTpInstance, cdaTpMethodTable, W("_maxThreads")); - if (offset <= 0 || FAILED(MOVE(i16Value, cdaTpInstance + offset))) - { - ExtOut(" %s\n", "Failed to read PortableThreadPool._maxThreads"); - break; - } - threadpool.MaxLimitTotalWorkerThreads = i16Value; - } - - // Populate thread counts - { - DacpFieldDescData vSeparatedField; - offset = GetObjFieldOffset(cdaTpInstance, cdaTpMethodTable, W("_separated"), TRUE, &vSeparatedField); - if (offset <= 0) - { - ExtOut(" %s\n", "Failed to read PortableThreadPool._separated"); - break; - } - int accumulatedOffset = offset; - - DacpFieldDescData vCountsField; - offset = GetValueFieldOffset(vSeparatedField.MTOfType, W("counts"), &vCountsField); - if (offset < 0) - { - ExtOut(" %s\n", "Failed to read PortableThreadPool._separated.counts"); - break; - } - accumulatedOffset += offset; - - offset = GetValueFieldOffset(vCountsField.MTOfType, W("_data")); - if (offset < 0 || FAILED(MOVE(ui64Value, cdaTpInstance + accumulatedOffset + offset))) - { - ExtOut(" %s\n", "Failed to read PortableThreadPool._separated.counts._data"); - break; - } - UINT64 data = ui64Value; - - const UINT8 NumProcessingWorkShift = 0; - const UINT8 NumExistingThreadsShift = 16; - - INT16 numProcessingWork = (INT16)(data >> NumProcessingWorkShift); - INT16 numExistingThreads = (INT16)(data >> NumExistingThreadsShift); - - threadpool.NumIdleWorkerThreads = numExistingThreads - numProcessingWork; - threadpool.NumWorkingWorkerThreads = numProcessingWork; - threadpool.NumRetiredWorkerThreads = 0; - } - - // Populate hill climbing log info - { - threadpool.HillClimbingLog = 0; // this indicates that the portable thread pool's hill climbing data should be used - threadpool.HillClimbingLogFirstIndex = 0; - threadpool.HillClimbingLogSize = 0; - - // Get the hill climbing instance - if (FAILED( - GetNonSharedStaticFieldValueFromName( - &ui64Value, - corelibModule, - "System.Threading.PortableThreadPool+HillClimbing", - W("ThreadPoolHillClimber"), - ELEMENT_TYPE_CLASS)) || - ui64Value == 0) - { - // The type was not loaded yet, or the static field was not found, etc. For now assume that the hill climber has - // not been used yet. - break; - } - CLRDATA_ADDRESS cdaTpHcInstance = TO_CDADDR(ui64Value); - - // Get the thread pool method table - CLRDATA_ADDRESS cdaTpHcMethodTable; - { - TADDR tpHcMethodTableAddr = NULL; - if (FAILED(GetMTOfObject(TO_TADDR(cdaTpHcInstance), &tpHcMethodTableAddr))) - { - ExtOut(" %s\n", "Failed to get method table for PortableThreadPool.HillClimbing"); - break; - } - cdaTpHcMethodTable = TO_CDADDR(tpHcMethodTableAddr); - } - - offset = GetObjFieldOffset(cdaTpHcInstance, cdaTpHcMethodTable, W("_logStart")); - if (offset <= 0 || FAILED(MOVE(i32Value, cdaTpHcInstance + offset))) - { - ExtOut(" %s\n", "Failed to read PortableThreadPool.HillClimbing._logStart"); - break; - } - int logStart = i32Value; - - offset = GetObjFieldOffset(cdaTpHcInstance, cdaTpHcMethodTable, W("_logSize")); - if (offset <= 0 || FAILED(MOVE(i32Value, cdaTpHcInstance + offset))) - { - ExtOut(" %s\n", "Failed to read PortableThreadPool.HillClimbing._logSize"); - break; - } - int logSize = i32Value; - - offset = GetObjFieldOffset(cdaTpHcInstance, cdaTpHcMethodTable, W("_log")); - if (offset <= 0 || FAILED(MOVE(ptrValue, cdaTpHcInstance + offset)) || ptrValue == 0) - { - ExtOut(" %s\n", "Failed to read PortableThreadPool.HillClimbing._log"); - break; - } - CLRDATA_ADDRESS cdaTpHcLog = TO_CDADDR(ptrValue); - - // Validate the log array - if (!sos::IsObject(cdaTpHcLog, false) || - vPortableTpHcLogArray.Request(g_sos, cdaTpHcLog) != S_OK || - vPortableTpHcLogArray.ObjectType != OBJ_ARRAY || - vPortableTpHcLogArray.ArrayDataPtr == 0 || - vPortableTpHcLogArray.dwComponentSize != sizeof(HillClimbingLogEntry) || - vPortableTpHcLogArray.ElementTypeHandle == 0) - { - ExtOut(" %s\n", "Failed to validate PortableThreadPool.HillClimbing._log"); - break; - } - - // Get the log entry field offsets - portableTpHcLogEntry_tickCountOffset = - GetValueFieldOffset(vPortableTpHcLogArray.ElementTypeHandle, W("tickCount")); - portableTpHcLogEntry_stateOrTransitionOffset = - GetValueFieldOffset(vPortableTpHcLogArray.ElementTypeHandle, W("stateOrTransition")); - portableTpHcLogEntry_newControlSettingOffset = - GetValueFieldOffset(vPortableTpHcLogArray.ElementTypeHandle, W("newControlSetting")); - portableTpHcLogEntry_lastHistoryCountOffset = - GetValueFieldOffset(vPortableTpHcLogArray.ElementTypeHandle, W("lastHistoryCount")); - portableTpHcLogEntry_lastHistoryMeanOffset = - GetValueFieldOffset(vPortableTpHcLogArray.ElementTypeHandle, W("lastHistoryMean")); - if (portableTpHcLogEntry_tickCountOffset < 0 || - portableTpHcLogEntry_stateOrTransitionOffset < 0 || - portableTpHcLogEntry_newControlSettingOffset < 0 || - portableTpHcLogEntry_lastHistoryCountOffset < 0 || - portableTpHcLogEntry_lastHistoryMeanOffset < 0) - { - ExtOut(" %s\n", "Failed to get a field offset in PortableThreadPool.HillClimbing.LogEntry"); - break; - } - - ExtOut("logStart: %d\n", logStart); - ExtOut("logSize: %d\n", logSize); - threadpool.HillClimbingLogFirstIndex = logStart; - threadpool.HillClimbingLogSize = logSize; - } - } while (false); - - //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - ExtOut ("CPU utilization: %d %s\n", threadpool.cpuUtilization, "%"); - ExtOut ("Worker Thread:"); - ExtOut (" Total: %d", threadpool.NumWorkingWorkerThreads + threadpool.NumIdleWorkerThreads + threadpool.NumRetiredWorkerThreads); - ExtOut (" Running: %d", threadpool.NumWorkingWorkerThreads); - ExtOut (" Idle: %d", threadpool.NumIdleWorkerThreads); - ExtOut (" MaxLimit: %d", threadpool.MaxLimitTotalWorkerThreads); - ExtOut (" MinLimit: %d", threadpool.MinLimitTotalWorkerThreads); - ExtOut ("\n"); - - int numWorkRequests = 0; - CLRDATA_ADDRESS workRequestPtr = threadpool.FirstUnmanagedWorkRequest; - DacpWorkRequestData workRequestData; - while (workRequestPtr) - { - if ((Status = workRequestData.Request(g_sos,workRequestPtr))!=S_OK) - { - ExtOut(" Failed to examine a WorkRequest\n"); - return Status; - } - numWorkRequests++; - workRequestPtr = workRequestData.NextWorkRequest; - } - - ExtOut ("Work Request in Queue: %d\n", numWorkRequests); - workRequestPtr = threadpool.FirstUnmanagedWorkRequest; - while (workRequestPtr) - { - if ((Status = workRequestData.Request(g_sos,workRequestPtr))!=S_OK) - { - ExtOut(" Failed to examine a WorkRequest\n"); - return Status; - } - - if (workRequestData.Function == threadpool.AsyncTimerCallbackCompletionFPtr) - ExtOut (" AsyncTimerCallbackCompletion TimerInfo@%p\n", SOS_PTR(workRequestData.Context)); - else - ExtOut (" Unknown Function: %p Context: %p\n", SOS_PTR(workRequestData.Function), - SOS_PTR(workRequestData.Context)); - - workRequestPtr = workRequestData.NextWorkRequest; - } - - if (doWorkItemDump && g_snapshot.Build()) - { - // Display a message if the heap isn't verified. - sos::GCHeap gcheap; - if (!gcheap.AreGCStructuresValid()) - { - DisplayInvalidStructuresMessage(); - } - - mdTypeDef threadPoolWorkQueueMd, threadPoolWorkStealingQueueMd; - GetInfoFromName(corelibModule, "System.Threading.ThreadPoolWorkQueue", &threadPoolWorkQueueMd); - GetInfoFromName(corelibModule, "System.Threading.ThreadPoolWorkQueue+WorkStealingQueue", &threadPoolWorkStealingQueueMd); - - // Walk every heap item looking for the global queue and local queues. - ExtOut("\nQueued work items:\n%" THREAD_POOL_WORK_ITEM_TABLE_QUEUE_WIDTH "s %" POINTERSIZE "s %s\n", "Queue", "Address", "Work Item"); - HeapStat stats; - for (sos::ObjectIterator itr = gcheap.WalkHeap(); !IsInterrupt() && itr != NULL; ++itr) - { - DacpMethodTableData mtdata; - if (mtdata.Request(g_sos, TO_TADDR(itr->GetMT())) != S_OK || - mtdata.Module != corelibModule) - { - continue; - } - - if (mtdata.cl == threadPoolWorkQueueMd) - { - // We found a ThreadPoolWorkQueue (there should be only one, given one AppDomain). - - // Enumerate high-priority work items. - int offset = GetObjFieldOffset(itr->GetAddress(), itr->GetMT(), W("highPriorityWorkItems")); - if (offset > 0) - { - DWORD_PTR workItemsConcurrentQueuePtr; - MOVE(workItemsConcurrentQueuePtr, itr->GetAddress() + offset); - if (sos::IsObject(workItemsConcurrentQueuePtr, false)) - { - // We got the ConcurrentQueue. Enumerate it. - EnumerateThreadPoolGlobalWorkItemConcurrentQueue(workItemsConcurrentQueuePtr, "[Global high-pri]", &stats); - } - } - - // Enumerate assignable normal-priority work items. - offset = GetObjFieldOffset(itr->GetAddress(), itr->GetMT(), W("_assignableWorkItemQueues")); - if (offset > 0) - { - DWORD_PTR workItemsConcurrentQueueArrayPtr; - MOVE(workItemsConcurrentQueueArrayPtr, itr->GetAddress() + offset); - DacpObjectData workItemsConcurrentQueueArray; - if (workItemsConcurrentQueueArray.Request(g_sos, TO_CDADDR(workItemsConcurrentQueueArrayPtr)) == S_OK && - workItemsConcurrentQueueArray.ObjectType == OBJ_ARRAY) - { - for (int i = 0; i < workItemsConcurrentQueueArray.dwNumComponents; i++) - { - DWORD_PTR workItemsConcurrentQueuePtr; - MOVE(workItemsConcurrentQueuePtr, workItemsConcurrentQueueArray.ArrayDataPtr + (i * workItemsConcurrentQueueArray.dwComponentSize)); - if (workItemsConcurrentQueuePtr != NULL && sos::IsObject(TO_CDADDR(workItemsConcurrentQueuePtr), false)) - { - // We got the ConcurrentQueue. Enumerate it. - EnumerateThreadPoolGlobalWorkItemConcurrentQueue(workItemsConcurrentQueuePtr, "[Global]", &stats); - } - } - } - } - - // Enumerate normal-priority work items. - offset = GetObjFieldOffset(itr->GetAddress(), itr->GetMT(), W("workItems")); - if (offset > 0) - { - DWORD_PTR workItemsConcurrentQueuePtr; - MOVE(workItemsConcurrentQueuePtr, itr->GetAddress() + offset); - if (sos::IsObject(workItemsConcurrentQueuePtr, false)) - { - // We got the ConcurrentQueue. Enumerate it. - EnumerateThreadPoolGlobalWorkItemConcurrentQueue(workItemsConcurrentQueuePtr, "[Global]", &stats); - } - } - } - else if (mtdata.cl == threadPoolWorkStealingQueueMd) - { - // We found a local queue. Get its work items array. - int offset = GetObjFieldOffset(itr->GetAddress(), itr->GetMT(), W("m_array")); - if (offset > 0) - { - // Walk every element in the array, outputting details on non-null work items. - DWORD_PTR workItemArrayPtr; - MOVE(workItemArrayPtr, itr->GetAddress() + offset); - DacpObjectData workItemArray; - if (workItemArray.Request(g_sos, TO_CDADDR(workItemArrayPtr)) == S_OK && workItemArray.ObjectType == OBJ_ARRAY) - { - for (int i = 0; i < workItemArray.dwNumComponents; i++) - { - DWORD_PTR workItemPtr; - MOVE(workItemPtr, workItemArray.ArrayDataPtr + (i * workItemArray.dwComponentSize)); - if (workItemPtr != NULL && sos::IsObject(TO_CDADDR(workItemPtr), false)) - { - sos::Object workItem = TO_TADDR(workItemPtr); - stats.Add((DWORD_PTR)workItem.GetMT(), (DWORD)workItem.GetSize()); - DMLOut("%" THREAD_POOL_WORK_ITEM_TABLE_QUEUE_WIDTH "s %s %S", DMLObject(itr->GetAddress()), DMLObject(workItem.GetAddress()), workItem.GetTypeName()); - if ((offset = GetObjFieldOffset(workItem.GetAddress(), workItem.GetMT(), W("_callback"))) > 0 || - (offset = GetObjFieldOffset(workItem.GetAddress(), workItem.GetMT(), W("m_action"))) > 0) - { - DWORD_PTR delegatePtr; - MOVE(delegatePtr, workItem.GetAddress() + offset); - CLRDATA_ADDRESS md; - if (TryGetMethodDescriptorForDelegate(TO_CDADDR(delegatePtr), &md)) - { - NameForMD_s((DWORD_PTR)md, g_mdName, mdNameLen); - ExtOut(" => %S", g_mdName); - } - } - ExtOut("\n"); - } - } - } - } - } - } - - // Output a summary. - stats.Sort(); - stats.Print(); - ExtOut("\n"); - } - - if (doHCDump) - { - ExtOut ("--------------------------------------\n"); - ExtOut ("\nThread Injection History\n"); - if (threadpool.HillClimbingLogSize > 0) - { - static char const * const TransitionNames[] = - { - "Warmup", - "Initializing", - "RandomMove", - "ClimbingMove", - "ChangePoint", - "Stabilizing", - "Starvation", - "ThreadTimedOut", - "CooperativeBlocking", - "Undefined" - }; - - bool usePortableThreadPoolHillClimbingData = threadpool.HillClimbingLog == 0; - int logCapacity = - usePortableThreadPoolHillClimbingData - ? (int)vPortableTpHcLogArray.dwNumComponents - : HillClimbingLogCapacity; - - ExtOut("\n Time Transition New #Threads #Samples Throughput\n"); - DacpHillClimbingLogEntry entry; - - // Get the most recent entry first, so we can calculate time offsets - DWORD endTime; - int index = (threadpool.HillClimbingLogFirstIndex + threadpool.HillClimbingLogSize - 1) % logCapacity; - if (usePortableThreadPoolHillClimbingData) - { - CLRDATA_ADDRESS entryPtr = - TO_CDADDR(vPortableTpHcLogArray.ArrayDataPtr + index * sizeof(HillClimbingLogEntry)); - INT32 i32Value = 0; - - if (FAILED(Status = MOVE(i32Value, entryPtr + portableTpHcLogEntry_tickCountOffset))) - { - ExtOut(" Failed to examine a HillClimbing log entry\n"); - return Status; - } - - endTime = i32Value; - } - else - { - CLRDATA_ADDRESS entryPtr = threadpool.HillClimbingLog + (index * sizeof(HillClimbingLogEntry)); - if ((Status = entry.Request(g_sos, entryPtr)) != S_OK) - { - ExtOut(" Failed to examine a HillClimbing log entry\n"); - return Status; - } - - endTime = entry.TickCount; - } - - for (int i = 0; i < threadpool.HillClimbingLogSize; i++) - { - index = (i + threadpool.HillClimbingLogFirstIndex) % logCapacity; - if (usePortableThreadPoolHillClimbingData) - { - CLRDATA_ADDRESS entryPtr = - TO_CDADDR(vPortableTpHcLogArray.ArrayDataPtr + (index * sizeof(HillClimbingLogEntry))); - INT32 i32Value = 0; - float f32Value = 0; - - if (FAILED(Status = MOVE(i32Value, entryPtr + portableTpHcLogEntry_tickCountOffset))) - { - ExtOut(" Failed to examine a HillClimbing log entry\n"); - return Status; - } - entry.TickCount = i32Value; - - if (FAILED(Status = MOVE(i32Value, entryPtr + portableTpHcLogEntry_stateOrTransitionOffset))) - { - ExtOut(" Failed to examine a HillClimbing log entry\n"); - return Status; - } - entry.Transition = i32Value; - - if (FAILED(Status = MOVE(i32Value, entryPtr + portableTpHcLogEntry_newControlSettingOffset))) - { - ExtOut(" Failed to examine a HillClimbing log entry\n"); - return Status; - } - entry.NewControlSetting = i32Value; - - if (FAILED(Status = MOVE(i32Value, entryPtr + portableTpHcLogEntry_lastHistoryCountOffset))) - { - ExtOut(" Failed to examine a HillClimbing log entry\n"); - return Status; - } - entry.LastHistoryCount = i32Value; - - if (FAILED(Status = MOVE(f32Value, entryPtr + portableTpHcLogEntry_lastHistoryMeanOffset))) - { - ExtOut(" Failed to examine a HillClimbing log entry\n"); - return Status; - } - entry.LastHistoryMean = f32Value; - } - else - { - CLRDATA_ADDRESS entryPtr = threadpool.HillClimbingLog + (index * sizeof(HillClimbingLogEntry)); - - if ((Status = entry.Request(g_sos, entryPtr)) != S_OK) - { - ExtOut(" Failed to examine a HillClimbing log entry\n"); - return Status; - } - } - - ExtOut("%8.2lf %-14s %12d %12d %11.2lf\n", - (double)(int)(entry.TickCount - endTime) / 1000.0, - TransitionNames[entry.Transition], - entry.NewControlSetting, - entry.LastHistoryCount, - entry.LastHistoryMean); - } - } - } - - ExtOut ("--------------------------------------\n"); - ExtOut ("Number of Timers: %d\n", threadpool.NumTimers); - ExtOut ("--------------------------------------\n"); - - // Determine if the portable thread pool is being used for IO. The portable thread pool does not use a separate set of - // threads for processing IO completions. - if (FAILED( - GetNonSharedStaticFieldValueFromName( - &ui64Value, - corelibModule, - "System.Threading.ThreadPool", - W("UsePortableThreadPoolForIO"), - ELEMENT_TYPE_BOOLEAN)) || - ui64Value == 0) - { - ExtOut ("Completion Port Thread:"); - ExtOut ("Total: %d", threadpool.NumCPThreads); - ExtOut (" Free: %d", threadpool.NumFreeCPThreads); - ExtOut (" MaxFree: %d", threadpool.MaxFreeCPThreads); - ExtOut (" CurrentLimit: %d", threadpool.CurrentLimitTotalCPThreads); - ExtOut (" MaxLimit: %d", threadpool.MaxLimitTotalCPThreads); - ExtOut (" MinLimit: %d", threadpool.MinLimitTotalCPThreads); - ExtOut ("\n"); - } - - return S_OK; + return ExecuteCommand("threadpool", args); } DECLARE_API(FindAppDomain) diff --git a/src/SOS/Strike/util.cpp b/src/SOS/Strike/util.cpp index db556a16ed..768c919ca0 100644 --- a/src/SOS/Strike/util.cpp +++ b/src/SOS/Strike/util.cpp @@ -1128,125 +1128,6 @@ void DisplayFields(CLRDATA_ADDRESS cdaMT, DacpMethodTableData *pMTD, DacpMethodT return; } -HRESULT GetNonSharedStaticFieldValueFromName( - UINT64* pValue, - DWORD_PTR moduleAddr, - const char *typeName, - __in_z LPCWSTR wszFieldName, - CorElementType fieldType) -{ - HRESULT hr = S_OK; - - mdTypeDef mdType = 0; - GetInfoFromName(moduleAddr, typeName, &mdType); - if (mdType == 0) - { - return E_FAIL; // Failed to find type token - } - - CLRDATA_ADDRESS cdaMethodTable = 0; - if (FAILED(hr = g_sos->GetMethodDescFromToken(moduleAddr, mdType, &cdaMethodTable)) || - !IsValidToken(moduleAddr, mdType) || - cdaMethodTable == 0) - { - return FAILED(hr) ? hr : E_FAIL; // Invalid type token or type is not loaded yet - } - - DacpMethodTableData vMethodTable; - if ((hr = vMethodTable.Request(g_sos, cdaMethodTable)) != S_OK) - { - return FAILED(hr) ? hr : E_FAIL; // Failed to get method table data - } - if (vMethodTable.bIsShared) - { - ExtOut(" %s: %s\n", "Method table is shared (not implemented)", typeName); - return E_NOTIMPL; - } - - DacpMethodTableFieldData vMethodTableFields; - if (FAILED(hr = vMethodTableFields.Request(g_sos, cdaMethodTable))) - { - return hr; // Failed to get field data - } - - DacpModuleData vModule; - if ((hr = vModule.Request(g_sos, vMethodTable.Module)) != S_OK) - { - return FAILED(hr) ? hr : E_FAIL; // Failed to get module data - } - - DacpDomainLocalModuleData vDomainLocalModule; - if ((hr = g_sos->GetDomainLocalModuleDataFromModule(vMethodTable.Module, &vDomainLocalModule)) != S_OK) - { - return FAILED(hr) ? hr : E_FAIL; // Failed to get domain local module data - } - - ToRelease pImport = MDImportForModule(&vModule); - CLRDATA_ADDRESS cdaField = vMethodTableFields.FirstField; - DacpFieldDescData vFieldDesc; - bool found = false; - for (DWORD staticFieldIndex = 0; staticFieldIndex < vMethodTableFields.wNumStaticFields; ) - { - if ((hr = vFieldDesc.Request(g_sos, cdaField)) != S_OK || vFieldDesc.Type >= ELEMENT_TYPE_MAX) - { - return FAILED(hr) ? hr : E_FAIL; // Failed to get member field desc - } - cdaField = vFieldDesc.NextField; - - if (!vFieldDesc.bIsStatic) - { - continue; - } - - ++staticFieldIndex; - - if (vFieldDesc.Type != fieldType) - { - continue; - } - - if (FAILED(hr = NameForToken_s(TokenFromRid(vFieldDesc.mb, mdtFieldDef), pImport, g_mdName, mdNameLen, false))) - { - return hr; // Failed to get member field name - } - - if (_wcscmp(g_mdName, wszFieldName) != 0) - { - continue; - } - - if (vFieldDesc.bIsThreadLocal || vFieldDesc.bIsContextLocal) - { - ExtOut(" %s: %s.%S\n", "Static field is thread-local or context-local (not implemented)", typeName, wszFieldName); - return E_NOTIMPL; - } - - found = true; - break; - } - - if (!found) - { - return E_FAIL; // Static field not found - } - - DWORD_PTR pValueAddr = 0; - GetStaticFieldPTR(&pValueAddr, &vDomainLocalModule, &vMethodTable, &vFieldDesc); - if (pValueAddr == 0) - { - return E_FAIL; // Failed to get static field address - } - - UINT64 value = 0; - if (FAILED(MOVEBLOCK(value, pValueAddr, gElementTypeInfo[fieldType]))) - { - return E_FAIL; // Failed to read static field - } - - *pValue = value; - return S_OK; -} - // Return value: -1 = error, // 0 = field not found, // > 0 = offset to field from objAddr @@ -1330,65 +1211,6 @@ int GetObjFieldOffset(CLRDATA_ADDRESS cdaObj, CLRDATA_ADDRESS cdaMT, __in_z LPCW } -// Return value: -1 = error -// -2 = not found -// >= 0 = offset to field from cdaValue -int GetValueFieldOffset(CLRDATA_ADDRESS cdaMT, __in_z LPCWSTR wszFieldName, DacpFieldDescData* pDacpFieldDescData) -{ -#define EXITPOINT(EXPR) do { if(!(EXPR)) { return -1; } } while (0) - - const int NOT_FOUND = -2; - DacpMethodTableData dmtd; - DacpMethodTableFieldData vMethodTableFields; - DacpFieldDescData vFieldDesc; - DacpModuleData module; - static DWORD numInstanceFields = 0; // Static due to recursion visiting parents - numInstanceFields = 0; - - EXITPOINT(vMethodTableFields.Request(g_sos, cdaMT) == S_OK); - - EXITPOINT(dmtd.Request(g_sos, cdaMT) == S_OK); - EXITPOINT(module.Request(g_sos, dmtd.Module) == S_OK); - if (dmtd.ParentMethodTable) - { - DWORD retVal = GetValueFieldOffset(dmtd.ParentMethodTable, wszFieldName, pDacpFieldDescData); - if (retVal != (DWORD)NOT_FOUND) - { - // Return in case of error or success. Fall through for field-not-found. - return retVal; - } - } - - CLRDATA_ADDRESS dwAddr = vMethodTableFields.FirstField; - ToRelease pImport = MDImportForModule(&module); - - while (numInstanceFields < vMethodTableFields.wNumInstanceFields) - { - EXITPOINT(vFieldDesc.Request(g_sos, dwAddr) == S_OK); - - if (!vFieldDesc.bIsStatic) - { - NameForToken_s(TokenFromRid(vFieldDesc.mb, mdtFieldDef), pImport, g_mdName, mdNameLen, false); - if (_wcscmp(wszFieldName, g_mdName) == 0) - { - if (pDacpFieldDescData != NULL) - { - *pDacpFieldDescData = vFieldDesc; - } - return vFieldDesc.dwOffset; - } - numInstanceFields++; - } - - dwAddr = vFieldDesc.NextField; - } - - // Field name not found... - return NOT_FOUND; - -#undef EXITPOINT -} - // Returns an AppDomain address if AssemblyPtr is loaded into that domain only. Otherwise // returns NULL CLRDATA_ADDRESS IsInOneDomainOnly(CLRDATA_ADDRESS AssemblyPtr) diff --git a/src/SOS/Strike/util.h b/src/SOS/Strike/util.h index 9fd90c7ba0..2fb1eb0bea 100644 --- a/src/SOS/Strike/util.h +++ b/src/SOS/Strike/util.h @@ -1584,7 +1584,6 @@ void IP2MethodDesc (DWORD_PTR IP, DWORD_PTR &methodDesc, JITTypes &jitType, const char *ElementTypeName (unsigned type); void DisplayFields (CLRDATA_ADDRESS cdaMT, DacpMethodTableData *pMTD, DacpMethodTableFieldData *pMTFD, DWORD_PTR dwStartAddr = 0, BOOL bFirst=TRUE, BOOL bValueClass=FALSE); -HRESULT GetNonSharedStaticFieldValueFromName(UINT64* pValue, DWORD_PTR moduleAddr, const char *typeName, __in_z LPCWSTR wszFieldName, CorElementType fieldType); int GetObjFieldOffset(CLRDATA_ADDRESS cdaObj, __in_z LPCWSTR wszFieldName, BOOL bFirst=TRUE); int GetObjFieldOffset(CLRDATA_ADDRESS cdaObj, CLRDATA_ADDRESS cdaMT, __in_z LPCWSTR wszFieldName, BOOL bFirst=TRUE, DacpFieldDescData* pDacpFieldDescData=NULL); int GetValueFieldOffset(CLRDATA_ADDRESS cdaMT, __in_z LPCWSTR wszFieldName, DacpFieldDescData* pDacpFieldDescData=NULL); diff --git a/src/SOS/lldbplugin/soscommand.cpp b/src/SOS/lldbplugin/soscommand.cpp index a5dbbbefc5..2185778304 100644 --- a/src/SOS/lldbplugin/soscommand.cpp +++ b/src/SOS/lldbplugin/soscommand.cpp @@ -219,7 +219,7 @@ sosCommandInitialize(lldb::SBDebugger debugger) g_services->AddCommand("sosstatus", new sosCommand("SOSStatus"), "Displays the global SOS status."); g_services->AddCommand("sosflush", new sosCommand("SOSFlush"), "Resets the internal cached state."); g_services->AddCommand("syncblk", new sosCommand("SyncBlk"), "Displays the SyncBlock holder info."); - g_services->AddCommand("threadpool", new sosCommand("ThreadPool"), "Displays info about the runtime thread pool."); + g_services->AddManagedCommand("threadpool", "Displays info about the runtime thread pool."); g_services->AddCommand("threadstate", new sosCommand("ThreadState"), "Pretty prints the meaning of a threads state."); g_services->AddCommand("token2ee", new sosCommand("token2ee"), "Displays the MethodTable structure and MethodDesc structure for the specified token and module."); g_services->AddManagedCommand("verifyheap", "Checks the GC heap for signs of corruption."); From 2b79085781419364aef9c16adaa61c01db2c29ce Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Thu, 13 Apr 2023 16:46:37 +0000 Subject: [PATCH 018/111] Update dependencies from https://github.com/dotnet/source-build-reference-packages build 20230413.2 (#3825) [main] Update dependencies from dotnet/source-build-reference-packages --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index e6f3099c90..cbc92b5c08 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -47,9 +47,9 @@ https://github.com/dotnet/runtime a64420c79cb63c485138f4f1352b8730f27d7b19 - + https://github.com/dotnet/source-build-reference-packages - 02ee87c8a232a9786b56cd2102cf318559e72210 + 1325ba66a392ff99a6813e6577110fabc1dc075d diff --git a/eng/Versions.props b/eng/Versions.props index cecc4b1342..157ad39e32 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -66,7 +66,7 @@ 7.0.0-beta.22316.2 10.0.18362 13.0.1 - 8.0.0-alpha.1.23212.2 + 8.0.0-alpha.1.23213.2 1.2.0-beta-23165-02 From 6b7240d60db1167266eaf345f93e6f79f1f713cf Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Thu, 13 Apr 2023 16:46:48 +0000 Subject: [PATCH 019/111] Update dependencies from https://github.com/dotnet/symstore build 20230412.1 (#3826) [main] Update dependencies from dotnet/symstore --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index cbc92b5c08..641c41d453 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -1,8 +1,8 @@ - + https://github.com/dotnet/symstore - e09f81a0b38786cb20f66b589a8b88b6997a62da + 0ef70c89b4f9592eade9af090b055fcac3dfd688 https://github.com/microsoft/clrmd diff --git a/eng/Versions.props b/eng/Versions.props index 157ad39e32..eea6fce8d9 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -16,7 +16,7 @@ - 1.0.417001 + 1.0.421201 8.0.0-preview.3.23155.1 8.0.0-preview.3.23155.1 From a66abfc90c7ea267aeb8105acf80ae5ace2dd924 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Thu, 13 Apr 2023 17:23:52 +0000 Subject: [PATCH 020/111] Update dependencies from https://github.com/dotnet/aspnetcore build 20230413.2 (#3827) [main] Update dependencies from dotnet/aspnetcore --- eng/Version.Details.xml | 8 ++++---- eng/Versions.props | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 641c41d453..6288e24995 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -31,13 +31,13 @@ https://github.com/dotnet/installer 51e06f6931e859f56564556fa6ba519761fa7141 - + https://github.com/dotnet/aspnetcore - 7d0c27344d193cb6ad263732d1fef6d3e0fd1f71 + 68ae6b0d8aa2f4a0ff189d5cedc741e32cc643d2 - + https://github.com/dotnet/aspnetcore - 7d0c27344d193cb6ad263732d1fef6d3e0fd1f71 + 68ae6b0d8aa2f4a0ff189d5cedc741e32cc643d2 https://github.com/dotnet/runtime diff --git a/eng/Versions.props b/eng/Versions.props index eea6fce8d9..65bed04308 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -21,8 +21,8 @@ 8.0.0-preview.3.23155.1 8.0.0-preview.3.23155.1 - 8.0.0-preview.4.23212.2 - 8.0.0-preview.4.23212.2 + 8.0.0-preview.4.23213.2 + 8.0.0-preview.4.23213.2 8.0.100-preview.3.23156.1 From b89fb14d8f42f9c491e4aebe2d0ccfb720385e4a Mon Sep 17 00:00:00 2001 From: Andrew Moskevitz <49752377+Applesauce314@users.noreply.github.com> Date: Fri, 14 Apr 2023 15:41:27 -0400 Subject: [PATCH 021/111] dotnet-dump returns failure after exhausting retries on ERROR_PARTIAL_COPY (#3830) * updated to retry on ERROR_PARTIAL_COPY more times and to return a failure on the last loop * Update Dumper.Windows.cs --------- Co-authored-by: apmoskevitz --- src/Tools/dotnet-dump/Dumper.Windows.cs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/Tools/dotnet-dump/Dumper.Windows.cs b/src/Tools/dotnet-dump/Dumper.Windows.cs index ba35f93e08..876fec0266 100644 --- a/src/Tools/dotnet-dump/Dumper.Windows.cs +++ b/src/Tools/dotnet-dump/Dumper.Windows.cs @@ -67,8 +67,9 @@ internal static void CollectDump(int processId, string outputFile, DumpTypeOptio break; } + int loopEnd = 10; // Retry the write dump on ERROR_PARTIAL_COPY - for (int i = 0; i < 5; i++) + for (int i = 0; i <= loopEnd; i++) { // Dump the process! if (NativeMethods.MiniDumpWriteDump(processHandle.DangerousGetHandle(), (uint)processId, stream.SafeFileHandle, dumpType, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero)) @@ -78,10 +79,14 @@ internal static void CollectDump(int processId, string outputFile, DumpTypeOptio else { int err = Marshal.GetHRForLastWin32Error(); - if (err != NativeMethods.HR_ERROR_PARTIAL_COPY) + if (err != NativeMethods.HR_ERROR_PARTIAL_COPY || i == loopEnd) { Marshal.ThrowExceptionForHR(err); } + else + { + Console.WriteLine($"retrying due to PARTIAL_COPY #{i}"); + } } } } From d218cea31ccf66db09503568cb06a415aa674cb7 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Fri, 14 Apr 2023 20:25:29 +0000 Subject: [PATCH 022/111] Update dependencies from https://github.com/dotnet/source-build-reference-packages build 20230414.3 (#3831) [main] Update dependencies from dotnet/source-build-reference-packages --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 6288e24995..00e3fcc3f4 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -47,9 +47,9 @@ https://github.com/dotnet/runtime a64420c79cb63c485138f4f1352b8730f27d7b19 - + https://github.com/dotnet/source-build-reference-packages - 1325ba66a392ff99a6813e6577110fabc1dc075d + 94178e62553730ae42f6e02bb2f0ca45d9c3e28d diff --git a/eng/Versions.props b/eng/Versions.props index 65bed04308..177004a61b 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -66,7 +66,7 @@ 7.0.0-beta.22316.2 10.0.18362 13.0.1 - 8.0.0-alpha.1.23213.2 + 8.0.0-alpha.1.23214.3 1.2.0-beta-23165-02 From 554e80abde92c9d35360688df5ff7ca244a0eacd Mon Sep 17 00:00:00 2001 From: Lee Culver Date: Fri, 14 Apr 2023 19:59:00 -0700 Subject: [PATCH 023/111] Update ClrMD (#3835) * Updates with breaking changes from ClrMD 3.0 beta * Update NativeAddressHelper with ISOSDacInterface13 improvements * Fix null size issue * Fix assert * Properly handle GCBookkeeping regions --- eng/Version.Details.xml | 8 +- eng/Versions.props | 2 +- .../EEHeapCommand.cs | 2 +- .../NativeAddressHelper.cs | 86 +++++++++++++------ .../ThreadPoolCommand.cs | 2 +- 5 files changed, 67 insertions(+), 33 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 00e3fcc3f4..94891f57de 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -4,13 +4,13 @@ https://github.com/dotnet/symstore 0ef70c89b4f9592eade9af090b055fcac3dfd688 - + https://github.com/microsoft/clrmd - d68eb893272971726b08473935d2c7d088d1db5c + a85ab0d3e53eb7aef4b3a2f1d595da18342e8696 - + https://github.com/microsoft/clrmd - d68eb893272971726b08473935d2c7d088d1db5c + a85ab0d3e53eb7aef4b3a2f1d595da18342e8696 diff --git a/eng/Versions.props b/eng/Versions.props index 177004a61b..0375194e27 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -45,7 +45,7 @@ 5.0.0 6.0.0 - 3.0.0-beta.23212.1 + 3.0.0-beta.23214.2 16.9.0-beta1.21055.5 3.0.7 6.0.0 diff --git a/src/Microsoft.Diagnostics.ExtensionCommands/EEHeapCommand.cs b/src/Microsoft.Diagnostics.ExtensionCommands/EEHeapCommand.cs index 90afe5dc43..a7fe9e3dd4 100644 --- a/src/Microsoft.Diagnostics.ExtensionCommands/EEHeapCommand.cs +++ b/src/Microsoft.Diagnostics.ExtensionCommands/EEHeapCommand.cs @@ -312,7 +312,7 @@ private bool IsIncludedInFilter(ClrNativeHeapInfo info) sb.Append(')'); ulong wasted = 0; - if (actualSize < size && !heap.IsCurrentBlock) + if (actualSize < size && heap.State != ClrNativeHeapState.Active) { wasted = size - actualSize; } diff --git a/src/Microsoft.Diagnostics.ExtensionCommands/NativeAddressHelper.cs b/src/Microsoft.Diagnostics.ExtensionCommands/NativeAddressHelper.cs index 8a2c03cfff..2f48a81337 100644 --- a/src/Microsoft.Diagnostics.ExtensionCommands/NativeAddressHelper.cs +++ b/src/Microsoft.Diagnostics.ExtensionCommands/NativeAddressHelper.cs @@ -101,10 +101,32 @@ private DescribedRegion[] EnumerateAddressSpaceWorker(bool tagClrMemoryRanges, b RootCacheService rootCache = runtime.Services.GetService(); if (clrRuntime is not null) { - foreach ((ulong Address, ulong? Size, ClrMemoryKind Kind) mem in EnumerateClrMemoryAddresses(clrRuntime, rootCache, includeHandleTableIfSlow)) + foreach ((ulong Address, ulong Size, ClrMemoryKind Kind) mem in EnumerateClrMemoryAddresses(clrRuntime, rootCache, includeHandleTableIfSlow)) { - DescribedRegion[] found = rangeList.Where(r => r.Start <= mem.Address && mem.Address < r.End).ToArray(); + // The GCBookkeeping range is a large region of memory that the GC reserved. We'll simply mark every + // region within it as bookkeeping. + if (mem.Kind == ClrMemoryKind.GCBookkeeping) + { + MemoryRange bookkeepingRange = MemoryRange.CreateFromLength(mem.Address, mem.Size); + foreach (DescribedRegion region in rangeList) + { + if (bookkeepingRange.Contains(region.Start)) + { + if (region.State == MemoryRegionState.MEM_RESERVE) + { + region.ClrMemoryKind = ClrMemoryKind.GCBookkeepingReserve; + } + else + { + region.ClrMemoryKind = ClrMemoryKind.GCBookkeeping; + } + } + } + continue; + } + + DescribedRegion[] found = rangeList.Where(r => r.Start <= mem.Address && mem.Address < r.End).ToArray(); if (found.Length == 0 && mem.Kind != ClrMemoryKind.GCHeapReserve) { Trace.WriteLine($"Warning: Could not find a memory range for {mem.Address:x} - {mem.Kind}."); @@ -119,13 +141,13 @@ private DescribedRegion[] EnumerateAddressSpaceWorker(bool tagClrMemoryRanges, b } // Add the memory range if we know its size. - if (mem.Size is ulong size && size > 0) + if (mem.Size > 0) { IModule module = ModuleService.GetModuleFromAddress(mem.Address); rangeList.Add(new DescribedRegion() { Start = mem.Address, - End = mem.Address + size, + End = mem.Address + mem.Size, ClrMemoryKind = mem.Kind, State = mem.Kind == ClrMemoryKind.GCHeapReserve ? MemoryRegionState.MEM_RESERVE : MemoryRegionState.MEM_COMMIT, Module = module, @@ -143,7 +165,7 @@ private DescribedRegion[] EnumerateAddressSpaceWorker(bool tagClrMemoryRanges, b foreach (DescribedRegion region in found) { - if (!mem.Size.HasValue || mem.Size.Value == 0) + if (mem.Size == 0) { // If we don't know the length of memory, just mark the Region with this tag. SetRegionKindWithWarning(mem, region); @@ -167,7 +189,7 @@ private DescribedRegion[] EnumerateAddressSpaceWorker(bool tagClrMemoryRanges, b DescribedRegion middleRegion = new(region) { Start = mem.Address, - End = mem.Address + mem.Size.Value, + End = mem.Address + mem.Size, ClrMemoryKind = mem.Kind, Usage = MemoryRegionUsage.CLR, }; @@ -194,7 +216,7 @@ private DescribedRegion[] EnumerateAddressSpaceWorker(bool tagClrMemoryRanges, b // Region is now the starting region of this set. region.End = middleRegion.Start; } - else if (region.Size < mem.Size.Value) + else if (region.Size < mem.Size) { SetRegionKindWithWarning(mem, region); @@ -213,15 +235,15 @@ private DescribedRegion[] EnumerateAddressSpaceWorker(bool tagClrMemoryRanges, b // If we found no matching regions, expand the current region to be the right length. if (!foundNext) { - region.End = mem.Address + mem.Size.Value; + region.End = mem.Address + mem.Size; } } - else if (region.Size > mem.Size.Value) + else if (region.Size > mem.Size) { // The CLR memory segment is at the beginning of this region. DescribedRegion newRange = new(region) { - End = mem.Address + mem.Size.Value, + End = mem.Address + mem.Size, ClrMemoryKind = mem.Kind }; @@ -265,14 +287,26 @@ private DescribedRegion[] EnumerateAddressSpaceWorker(bool tagClrMemoryRanges, b /// /// Enumerates pointers to various CLR heaps in memory. /// - private static IEnumerable<(ulong Address, ulong? Size, ClrMemoryKind Kind)> EnumerateClrMemoryAddresses(ClrRuntime runtime, RootCacheService rootCache, bool includeHandleTableIfSlow) + private static IEnumerable<(ulong Address, ulong Size, ClrMemoryKind Kind)> EnumerateClrMemoryAddresses(ClrRuntime runtime, RootCacheService rootCache, bool includeHandleTableIfSlow) { foreach (ClrNativeHeapInfo nativeHeap in runtime.EnumerateClrNativeHeaps()) { - yield return (nativeHeap.Address, nativeHeap.Size, nativeHeap.Kind == NativeHeapKind.Unknown ? ClrMemoryKind.None : (ClrMemoryKind)nativeHeap.Kind); + Debug.Assert((int)NativeHeapKind.GCBookkeeping == (int)ClrMemoryKind.GCBookkeeping); + + ClrMemoryKind kind = nativeHeap.Kind switch + { + NativeHeapKind.Unknown => ClrMemoryKind.Unknown, + > NativeHeapKind.Unknown and <= NativeHeapKind.GCBookkeeping => (ClrMemoryKind)nativeHeap.Kind, // enums match for these ranges + >= NativeHeapKind.GCFreeRegion and <= NativeHeapKind.GCFreeUohSegment => ClrMemoryKind.GCHeapToBeFreed, + _ => ClrMemoryKind.Unknown + }; + + yield return (nativeHeap.Address, nativeHeap.Size ?? 0, kind); } - if (includeHandleTableIfSlow) + // .Net 8 and beyond has accurate HandleTable memory info. + bool haveAccurateHandleInfo = runtime.ClrInfo.Flavor == ClrFlavor.Core && runtime.ClrInfo.Version.Major >= 8; + if (includeHandleTableIfSlow && !haveAccurateHandleInfo) { ulong prevHandle = 0; ulong granularity = 0x100; @@ -286,29 +320,27 @@ private DescribedRegion[] EnumerateAddressSpaceWorker(bool tagClrMemoryRanges, b if (handle.Address < prevHandle || handle.Address >= (prevHandle | (granularity - 1))) { - yield return (handle.Address, null, ClrMemoryKind.HandleTable); + yield return (handle.Address, 0, ClrMemoryKind.HandleTable); prevHandle = handle.Address; } } } - // We don't really have the true bounds of the committed or reserved segments. - // Return null for the size so that we will mark the entire region with this type. foreach (ClrSegment seg in runtime.Heap.Segments) { if (seg.CommittedMemory.Length > 0) { - yield return (seg.CommittedMemory.Start, null, ClrMemoryKind.GCHeap); + yield return (seg.CommittedMemory.Start, seg.CommittedMemory.Length, ClrMemoryKind.GCHeap); } if (seg.ReservedMemory.Length > 0) { - yield return (seg.ReservedMemory.Start, null, ClrMemoryKind.GCHeapReserve); + yield return (seg.ReservedMemory.Start, seg.ReservedMemory.Length, ClrMemoryKind.GCHeapReserve); } } } - private static void SetRegionKindWithWarning((ulong Address, ulong? Size, ClrMemoryKind Kind) mem, DescribedRegion region) + private static void SetRegionKindWithWarning((ulong Address, ulong Size, ClrMemoryKind Kind) mem, DescribedRegion region) { if (region.ClrMemoryKind != mem.Kind) { @@ -318,12 +350,7 @@ private static void SetRegionKindWithWarning((ulong Address, ulong? Size, ClrMem if (region.ClrMemoryKind is not ClrMemoryKind.None and not ClrMemoryKind.HighFrequencyHeap) { - if (mem.Size is not ulong size) - { - size = 0; - } - - Trace.WriteLine($"Warning: Overwriting range [{region.Start:x},{region.End:x}] {region.ClrMemoryKind} -> [{mem.Address:x},{mem.Address + size:x}] {mem.Kind}."); + Trace.WriteLine($"Warning: Overwriting range [{region.Start:x},{region.End:x}] {region.ClrMemoryKind} -> [{mem.Address:x},{mem.Address + mem.Size:x}] {mem.Kind}."); } region.ClrMemoryKind = mem.Kind; @@ -490,12 +517,19 @@ public enum ClrMemoryKind StubHeap, HighFrequencyHeap, LowFrequencyHeap, + ExecutableHeap, + FixupPrecodeHeap, + NewStubPrecodeHeap, + ThunkHeap, + HandleTable, + GCBookkeeping, // Skip ahead so new ClrMD NativeHeapKind values don't break the enum. Unknown = 100, GCHeap, + GCHeapToBeFreed, GCHeapReserve, - HandleTable, + GCBookkeepingReserve, } public sealed class DescribedRegion : IMemoryRegion diff --git a/src/Microsoft.Diagnostics.ExtensionCommands/ThreadPoolCommand.cs b/src/Microsoft.Diagnostics.ExtensionCommands/ThreadPoolCommand.cs index 074bb5321d..8736bcc4fb 100644 --- a/src/Microsoft.Diagnostics.ExtensionCommands/ThreadPoolCommand.cs +++ b/src/Microsoft.Diagnostics.ExtensionCommands/ThreadPoolCommand.cs @@ -96,7 +96,7 @@ public override void Invoke() foreach (HillClimbingLogEntry entry in hcl) { Console.CancellationToken.ThrowIfCancellationRequested(); - output.WriteRow($"{(entry.TickCount - end)/1000.0:0.00}", entry.StateOrTransition, entry.NewControlSetting, entry.LastHistoryCount, $"{entry.LastHistoryMean:0.00}"); + output.WriteRow($"{(entry.TickCount - end)/1000.0:0.00}", entry.StateOrTransition, entry.NewThreadCount, entry.SampleCount, $"{entry.Throughput:0.00}"); } Console.WriteLine(); From 63e9634df8f44603adf1ccf8d12f41480bf73271 Mon Sep 17 00:00:00 2001 From: Tom McDonald Date: Mon, 17 Apr 2023 23:07:57 -0400 Subject: [PATCH 024/111] Fix incorrect rendering of counters (#3816) * Fix incorrect rendering of counters * Fixing IDE0008 Use explicit type instead of 'var' build error * PR feedback and truncate output for multiple providers * Simplify counter refresh console output * Better drawing for very small console height screens * Remove lambda to avoid unnecessary memory allocations --- .../Exporters/ConsoleWriter.cs | 95 ++++++++++++++----- 1 file changed, 73 insertions(+), 22 deletions(-) diff --git a/src/Tools/dotnet-counters/Exporters/ConsoleWriter.cs b/src/Tools/dotnet-counters/Exporters/ConsoleWriter.cs index ded01c7d8f..76f06931f7 100644 --- a/src/Tools/dotnet-counters/Exporters/ConsoleWriter.cs +++ b/src/Tools/dotnet-counters/Exporters/ConsoleWriter.cs @@ -28,8 +28,13 @@ public ObservedProvider(string name) public readonly CounterProvider KnownProvider; } + private interface ICounterRow + { + int Row { get; set; } + } + /// Information about an observed counter. - private class ObservedCounter + private class ObservedCounter : ICounterRow { public ObservedCounter(string displayName) => DisplayName = displayName; public string DisplayName { get; } // Display name for this counter. @@ -41,7 +46,7 @@ private class ObservedCounter public double LastValue { get; set; } } - private class ObservedTagSet + private class ObservedTagSet : ICounterRow { public ObservedTagSet(string tags) { @@ -128,6 +133,19 @@ public void AssignRowsAndInitializeDisplay() { Clear(); + // clear row data on all counters + foreach (ObservedProvider provider in _providers.Values) + { + foreach (ObservedCounter counter in provider.Counters.Values) + { + counter.Row = -1; + foreach (ObservedTagSet tagSet in counter.TagSets.Values) + { + tagSet.Row = -1; + } + } + } + _consoleWidth = Console.WindowWidth; _consoleHeight = Console.WindowHeight; _maxNameLength = Math.Max(Math.Min(80, _consoleWidth) - (CounterValueLength + Indent + 1), 0); // Truncate the name to prevent line wrapping as long as the console width is >= CounterValueLength + Indent + 1 characters @@ -144,38 +162,67 @@ public void AssignRowsAndInitializeDisplay() Console.WriteLine(_errorText); row += GetLineWrappedLines(_errorText); } - Console.WriteLine(); row++; // Blank line. - foreach (ObservedProvider provider in _providers.Values.OrderBy(p => p.KnownProvider == null).ThenBy(p => p.Name)) // Known providers first. + bool RenderRow(ref int row, string lineOutput = null, ICounterRow counterRow = null) { - Console.WriteLine($"[{provider.Name}]"); row++; + if (row >= _consoleHeight + _topRow) // prevents from displaying more counters than vertical space available + { + return false; + } + + if (lineOutput != null) + { + Console.Write(lineOutput); + } - foreach (ObservedCounter counter in provider.Counters.Values.OrderBy(c => c.DisplayName)) + if (row < _consoleHeight + _topRow - 1) // prevents screen from scrolling due to newline on last line of console { + Console.WriteLine(); + } + + if (counterRow != null) + { + counterRow.Row = row; + } + + row++; - string name = MakeFixedWidth($"{new string(' ', Indent)}{counter.DisplayName}", Indent + _maxNameLength); - counter.Row = row++; - if (counter.RenderValueInline) + return true; + } + + if (RenderRow(ref row)) // Blank line. + { + foreach (ObservedProvider provider in _providers.Values.OrderBy(p => p.KnownProvider == null).ThenBy(p => p.Name)) // Known providers first. + { + if (!RenderRow(ref row, $"[{provider.Name}]")) { - if (row >= _consoleHeight) // prevents from displaying more counters than vertical space available - { - break; - } - Console.WriteLine($"{name} {FormatValue(counter.LastValue)}"); + break; } - else + + foreach (ObservedCounter counter in provider.Counters.Values.OrderBy(c => c.DisplayName)) { - Console.WriteLine(name); - foreach (ObservedTagSet tagSet in counter.TagSets.Values.OrderBy(t => t.Tags)) + string name = MakeFixedWidth($"{new string(' ', Indent)}{counter.DisplayName}", Indent + _maxNameLength); + if (counter.RenderValueInline) { - if (row >= _consoleHeight) + if (!RenderRow(ref row, $"{name} {FormatValue(counter.LastValue)}", counter)) { break; } - - string tagName = MakeFixedWidth($"{new string(' ', 2 * Indent)}{tagSet.Tags}", Indent + _maxNameLength); - Console.WriteLine($"{tagName} {FormatValue(tagSet.LastValue)}"); - tagSet.Row = row++; + } + else + { + if (!RenderRow(ref row, name, counter)) + { + break; + } + foreach (ObservedTagSet tagSet in counter.TagSets.Values.OrderBy(t => t.Tags)) + { + string tagName = MakeFixedWidth($"{new string(' ', 2 * Indent)}{tagSet.Tags}", Indent + _maxNameLength); + if (!RenderRow(ref row, $"{tagName} {FormatValue(tagSet.LastValue)}", tagSet)) + { + break; + } + } } } } @@ -253,6 +300,10 @@ public void CounterPayloadReceived(CounterPayload payload, bool pauseCmdSet) } int row = counter.RenderValueInline ? counter.Row : tagSet.Row; + if (row < 0) + { + return; + } SetCursorPosition(Indent + _maxNameLength + 1, row); Console.Write(FormatValue(payload.Value)); } From 21efc3d1bbf1e2a260b7583b27b5551bb9e00092 Mon Sep 17 00:00:00 2001 From: Nickolas McDonald <43690021+n77y@users.noreply.github.com> Date: Tue, 18 Apr 2023 01:40:13 -0400 Subject: [PATCH 025/111] Fix #3699 (#3836) --- .../DiagnosticsClient/DiagnosticsClient.cs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/Microsoft.Diagnostics.NETCore.Client/DiagnosticsClient/DiagnosticsClient.cs b/src/Microsoft.Diagnostics.NETCore.Client/DiagnosticsClient/DiagnosticsClient.cs index 3168df5e15..8a98866293 100644 --- a/src/Microsoft.Diagnostics.NETCore.Client/DiagnosticsClient/DiagnosticsClient.cs +++ b/src/Microsoft.Diagnostics.NETCore.Client/DiagnosticsClient/DiagnosticsClient.cs @@ -4,6 +4,7 @@ using System; using System.Buffers.Binary; using System.Collections.Generic; +using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; @@ -322,6 +323,15 @@ static IEnumerable GetAllPublishedProcesses(string[] files) continue; } + try + { + Process.GetProcessById(processId); + } + catch (ArgumentException) + { + continue; + } + yield return processId; } } From 2e7b357547b9de831e78e1333ab80743aeda098d Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Tue, 18 Apr 2023 17:53:38 +0000 Subject: [PATCH 026/111] Update dependencies from https://github.com/dotnet/source-build-reference-packages build 20230417.1 (#3838) [main] Update dependencies from dotnet/source-build-reference-packages --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 94891f57de..90af1b5bbd 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -47,9 +47,9 @@ https://github.com/dotnet/runtime a64420c79cb63c485138f4f1352b8730f27d7b19 - + https://github.com/dotnet/source-build-reference-packages - 94178e62553730ae42f6e02bb2f0ca45d9c3e28d + 8a91992a869b6e4dccd49b1c3246486e963595af diff --git a/eng/Versions.props b/eng/Versions.props index 0375194e27..debf5a70ff 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -66,7 +66,7 @@ 7.0.0-beta.22316.2 10.0.18362 13.0.1 - 8.0.0-alpha.1.23214.3 + 8.0.0-alpha.1.23217.1 1.2.0-beta-23165-02 From e185855b61597059094375ac13e8dbd12441b10d Mon Sep 17 00:00:00 2001 From: Lee Culver Date: Wed, 19 Apr 2023 11:55:53 -0700 Subject: [PATCH 027/111] Remove BOM marker from the middle of !traversexml (#3844) --- .../TraverseHeapCommand.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Microsoft.Diagnostics.ExtensionCommands/TraverseHeapCommand.cs b/src/Microsoft.Diagnostics.ExtensionCommands/TraverseHeapCommand.cs index 64647201a0..40d2820502 100644 --- a/src/Microsoft.Diagnostics.ExtensionCommands/TraverseHeapCommand.cs +++ b/src/Microsoft.Diagnostics.ExtensionCommands/TraverseHeapCommand.cs @@ -36,7 +36,7 @@ public override void Invoke() // create file early in case it throws using StreamWriter output = File.CreateText(Filename); - using (XmlWriter xml = Xml ? XmlWriter.Create(output, new XmlWriterSettings() { Indent = true, OmitXmlDeclaration = true }) : null) + using (XmlWriter xml = Xml ? XmlWriter.Create(output, new XmlWriterSettings() { Encoding = new UTF8Encoding(true), Indent = true, OmitXmlDeclaration = true }) : null) { using StreamWriter text = Xml ? null : output; @@ -81,6 +81,7 @@ public override void Invoke() using StreamWriter text = Xml ? null : new StreamWriter(rootObjectStream, Encoding.Default, 4096, leaveOpen: true); using XmlWriter xml = Xml ? XmlWriter.Create(rootObjectStream, new XmlWriterSettings() { + Encoding = new UTF8Encoding(false), CloseOutput = false, Indent = true, OmitXmlDeclaration = true, From a2d913fb84baf637b20eb1680ef04bb02751fe01 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Thu, 20 Apr 2023 13:22:26 +0000 Subject: [PATCH 028/111] Update dependencies from https://github.com/dotnet/symstore build 20230418.1 (#3845) [main] Update dependencies from dotnet/symstore --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 90af1b5bbd..86c15f7d10 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -1,8 +1,8 @@ - + https://github.com/dotnet/symstore - 0ef70c89b4f9592eade9af090b055fcac3dfd688 + cfbac6b5f6f9a628e89dbd38c074cbd41665820e https://github.com/microsoft/clrmd diff --git a/eng/Versions.props b/eng/Versions.props index debf5a70ff..08e88bb88e 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -16,7 +16,7 @@ - 1.0.421201 + 1.0.421801 8.0.0-preview.3.23155.1 8.0.0-preview.3.23155.1 From 69392e9467434d60261026d482c8e416427e7aa1 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Thu, 20 Apr 2023 13:47:10 +0000 Subject: [PATCH 029/111] Update dependencies from https://github.com/dotnet/source-build-reference-packages build 20230418.5 (#3846) [main] Update dependencies from dotnet/source-build-reference-packages --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 86c15f7d10..683e969d3e 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -47,9 +47,9 @@ https://github.com/dotnet/runtime a64420c79cb63c485138f4f1352b8730f27d7b19 - + https://github.com/dotnet/source-build-reference-packages - 8a91992a869b6e4dccd49b1c3246486e963595af + 252170d24e1c667b627b0d1328a5cdbc8e038fa2 diff --git a/eng/Versions.props b/eng/Versions.props index 08e88bb88e..5942962870 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -66,7 +66,7 @@ 7.0.0-beta.22316.2 10.0.18362 13.0.1 - 8.0.0-alpha.1.23217.1 + 8.0.0-alpha.1.23218.5 1.2.0-beta-23165-02 From 554b8e578df08c995e82e37adc9c7ce2852051a9 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Fri, 21 Apr 2023 13:41:45 +0000 Subject: [PATCH 030/111] Update dependencies from https://github.com/dotnet/source-build-reference-packages build 20230420.1 (#3847) [main] Update dependencies from dotnet/source-build-reference-packages --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 683e969d3e..ea9f565a8f 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -47,9 +47,9 @@ https://github.com/dotnet/runtime a64420c79cb63c485138f4f1352b8730f27d7b19 - + https://github.com/dotnet/source-build-reference-packages - 252170d24e1c667b627b0d1328a5cdbc8e038fa2 + c73065ba502e1982f4ae743ebd0fc6bb8cf06690 diff --git a/eng/Versions.props b/eng/Versions.props index 5942962870..ca4451abc5 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -66,7 +66,7 @@ 7.0.0-beta.22316.2 10.0.18362 13.0.1 - 8.0.0-alpha.1.23218.5 + 8.0.0-alpha.1.23220.1 1.2.0-beta-23165-02 From 089816724a404159785892ecd937e48cbfcd6b22 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Sat, 22 Apr 2023 13:29:07 +0000 Subject: [PATCH 031/111] Update dependencies from https://github.com/dotnet/source-build-reference-packages build 20230421.1 (#3848) [main] Update dependencies from dotnet/source-build-reference-packages --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index ea9f565a8f..6dd5b18a97 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -47,9 +47,9 @@ https://github.com/dotnet/runtime a64420c79cb63c485138f4f1352b8730f27d7b19 - + https://github.com/dotnet/source-build-reference-packages - c73065ba502e1982f4ae743ebd0fc6bb8cf06690 + 453ab23d599ac904ded70bd9194959a76b05702f diff --git a/eng/Versions.props b/eng/Versions.props index ca4451abc5..85f4d5074d 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -66,7 +66,7 @@ 7.0.0-beta.22316.2 10.0.18362 13.0.1 - 8.0.0-alpha.1.23220.1 + 8.0.0-alpha.1.23221.1 1.2.0-beta-23165-02 From 0dd3b75902a849e209752f6ec94af91134a297f3 Mon Sep 17 00:00:00 2001 From: Lee Culver Date: Mon, 24 Apr 2023 08:14:01 -0700 Subject: [PATCH 032/111] Reimplement !dso and !fq in C# (#3837) * Add initial managed !fq command * Update ClrMD version * Finish managed !fq implementation * Implement managed !dumpstackobjs * Remove !dso and !fq C++ implementations * Remove more dead code * More dead code * Remove ObjectSize helpers * Remove usages of g_snapshot * Remove GCHeap logic from SOS * Cleanup * Add RcwCleanup output * Ensure what we don't read past stack range * Change validation * Update validation * Add registers, fix output * Remove !dso heading in C++ * Fix dso regexes * Always print the statistics table * Always print dumpheap statistics * Add proper flush check * Restore previous DumpHeapService behavior Only print header when we have objects. * Update ClrMD version * Code review feedback * TESTONLY: Add !runtimes to get more diagnostics * TESTONLY: Fix previous command * TESTONLY: Write all warning/errors to normal * TESTONLY: Printf debugging * Fix DumpStackObject failures. Remove the test only code. Enable sos logging to a file --------- Co-authored-by: Mike McLaughlin --- eng/Version.Details.xml | 8 +- eng/Versions.props | 2 +- .../DumpHeapService.cs | 16 +- .../DumpStackObjectsCommand.cs | 381 +++++++++++++++ .../EEHeapCommand.cs | 17 +- .../FinalizeQueueCommand.cs | 224 +++++++++ .../GCRootCommand.cs | 16 + .../LiveObjectService.cs | 5 + .../NativeAddressHelper.cs | 13 +- src/SOS/SOS.Hosting/Commands/SOSCommand.cs | 2 - src/SOS/SOS.UnitTests/SOS.cs | 3 +- src/SOS/SOS.UnitTests/SOSRunner.cs | 14 + src/SOS/SOS.UnitTests/Scripts/GCPOH.script | 2 +- src/SOS/SOS.UnitTests/Scripts/GCTests.script | 4 +- .../Scripts/OtherCommands.script | 4 +- .../Scripts/StackAndOtherTests.script | 18 +- .../SOS.UnitTests/Scripts/StackTests.script | 4 +- src/SOS/Strike/disasm.cpp | 4 - src/SOS/Strike/disasm.h | 8 - src/SOS/Strike/eeheap.cpp | 437 ------------------ src/SOS/Strike/exts.cpp | 11 + src/SOS/Strike/exts.h | 5 +- src/SOS/Strike/strike.cpp | 263 +---------- src/SOS/Strike/util.cpp | 283 ------------ src/SOS/Strike/util.h | 316 ------------- src/SOS/lldbplugin/soscommand.cpp | 6 +- 26 files changed, 719 insertions(+), 1347 deletions(-) create mode 100644 src/Microsoft.Diagnostics.ExtensionCommands/DumpStackObjectsCommand.cs create mode 100644 src/Microsoft.Diagnostics.ExtensionCommands/FinalizeQueueCommand.cs diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 6dd5b18a97..53bdf10a6d 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -4,13 +4,13 @@ https://github.com/dotnet/symstore cfbac6b5f6f9a628e89dbd38c074cbd41665820e - + https://github.com/microsoft/clrmd - a85ab0d3e53eb7aef4b3a2f1d595da18342e8696 + 80b19b666752ae64301e33f819c39d4279ec0727 - + https://github.com/microsoft/clrmd - a85ab0d3e53eb7aef4b3a2f1d595da18342e8696 + 80b19b666752ae64301e33f819c39d4279ec0727 diff --git a/eng/Versions.props b/eng/Versions.props index 85f4d5074d..36b9b10965 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -45,7 +45,7 @@ 5.0.0 6.0.0 - 3.0.0-beta.23214.2 + 3.0.0-beta.23219.1 16.9.0-beta1.21055.5 3.0.7 6.0.0 diff --git a/src/Microsoft.Diagnostics.ExtensionCommands/DumpHeapService.cs b/src/Microsoft.Diagnostics.ExtensionCommands/DumpHeapService.cs index f9687f8f33..3fddb73587 100644 --- a/src/Microsoft.Diagnostics.ExtensionCommands/DumpHeapService.cs +++ b/src/Microsoft.Diagnostics.ExtensionCommands/DumpHeapService.cs @@ -42,11 +42,7 @@ public void PrintHeap(IEnumerable objects, DisplayKind displayKind, b Dictionary stats = new(); TableOutput thinLockOutput = null; - TableOutput objectTable = new(Console, (12, "x12"), (12, "x12"), (12, ""), (0, "")); - if (!statsOnly && (displayKind is DisplayKind.Normal or DisplayKind.Strings)) - { - objectTable.WriteRow("Address", "MT", "Size"); - } + TableOutput objectTable = null; ClrObject lastFreeObject = default; foreach (ClrObject obj in objects) @@ -77,6 +73,15 @@ public void PrintHeap(IEnumerable objects, DisplayKind displayKind, b ulong size = obj.IsValid ? obj.Size : 0; if (!statsOnly) { + if (objectTable is null) + { + objectTable = new(Console, (12, "x12"), (12, "x12"), (12, ""), (0, "")); + if (displayKind is DisplayKind.Normal or DisplayKind.Strings) + { + objectTable.WriteRow("Address", "MT", "Size"); + } + } + objectTable.WriteRow(new DmlDumpObj(obj), new DmlDumpHeap(obj.Type?.MethodTable ?? 0), size, obj.IsFree ? "Free" : ""); } @@ -192,6 +197,7 @@ orderby TotalSize } else if (displayKind == DisplayKind.Normal) { + // Print statistics table if (stats.Count != 0) { // Print statistics table diff --git a/src/Microsoft.Diagnostics.ExtensionCommands/DumpStackObjectsCommand.cs b/src/Microsoft.Diagnostics.ExtensionCommands/DumpStackObjectsCommand.cs new file mode 100644 index 0000000000..69f20de9a8 --- /dev/null +++ b/src/Microsoft.Diagnostics.ExtensionCommands/DumpStackObjectsCommand.cs @@ -0,0 +1,381 @@ +// 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.Buffers; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Diagnostics; +using System.Linq; +using System.Runtime.CompilerServices; +using Microsoft.Diagnostics.DebugServices; +using Microsoft.Diagnostics.Runtime; + +namespace Microsoft.Diagnostics.ExtensionCommands +{ + [Command(Name = "dumpstackobjects", Aliases = new string[] { "dso" }, Help = "Displays all managed objects found within the bounds of the current stack.")] + public class DumpStackObjectsCommand : CommandBase + { + [ServiceImport] + public IMemoryService MemoryService { get; set; } + + [ServiceImport] + public IThread CurrentThread { get; set; } + + [ServiceImport] + public IThreadService ThreadService { get; set; } + + [ServiceImport] + public ClrRuntime Runtime { get; set; } + + [Option(Name = "-verify", Help = "Verify each object and only print ones that are valid objects.")] + public bool Verify { get; set; } + + [Argument(Name = "StackBounds", Help = "The top and bottom of the stack (in hex).")] + public string[] Bounds { get; set; } + + public override void Invoke() + { + if (Runtime.Heap.Segments.Length == 0) + { + throw new DiagnosticsException("Cannot walk heap."); + } + + MemoryRange range; + if (Bounds is null || Bounds.Length == 0) + { + range = GetStackRange(); + } + else if (Bounds.Length == 2) + { + ulong start = ParseAddress(Bounds[0]) ?? throw new ArgumentException($"Failed to parse start address '{Bounds[0]}'."); + ulong end = ParseAddress(Bounds[1]) ?? throw new ArgumentException($"Failed to parse end address '{Bounds[1]}'."); + if (start > end) + { + (start, end) = (end, start); + } + + range = new(AlignDown(start), AlignUp(end)); + } + else + { + throw new ArgumentException("Invalid arguments."); + } + + if (range.Start == 0 || range.End == 0) + { + throw new ArgumentException($"Invalid range {range.Start:x} - {range.End:x}"); + } + + PrintStackObjects(range); + } + + private void PrintStackObjects(MemoryRange stack) + { + Console.WriteLine($"OS Thread Id: 0x{CurrentThread.ThreadId:x} ({CurrentThread.ThreadIndex})"); + + TableOutput output = new(Console, (16, "x12"), (16, "x12")); + output.WriteRow("SP/REG", "Object", "Name"); + + int regCount = ThreadService.Registers.Count(); + foreach ((ulong address, ClrObject obj) in EnumerateValidObjectsWithinRange(stack).OrderBy(r => r.StackAddress)) + { + Console.CancellationToken.ThrowIfCancellationRequested(); + + if (address < (ulong)regCount) + { + string registerName; + if (ThreadService.TryGetRegisterInfo((int)address, out RegisterInfo regInfo)) + { + registerName = regInfo.RegisterName; + } + else + { + registerName = $"reg{address}"; + } + + output.WriteRow(registerName, obj.Address, obj.Type?.Name); + } + else + { + output.WriteRow(address, obj.Address, obj.Type?.Name); + } + } + } + + /// + /// Enumerates all valid objects (and the address they came from) within the given range. + /// + private IEnumerable<(ulong StackAddress, ClrObject Object)> EnumerateValidObjectsWithinRange(MemoryRange range) + { + // Note: This implementation is careful to enumerate only real objects and not generate a lot of native + // exceptions within the dac. A naïve implementation could simply read every pointer aligned address + // and call ClrHeap.GetObject(objAddr).IsValid. That approach will generate a lot of exceptions + // within the dac trying to validate wild pointers as MethodTables, and it will often find old + // pointers which the GC has already swept but not zeroed yet. + + // Sort the list of potential objects so that we can go through each in segment order. + // Sorting this array saves us a lot of time by not searching for segments. + IEnumerable<(ulong StackAddress, ulong PotentialObject)> potentialObjects = EnumeratePointersWithinHeapBounds(range); + potentialObjects = potentialObjects.Concat(EnumerateRegistersWithinHeapBounds()); + potentialObjects = potentialObjects.OrderBy(r => r.PotentialObject); + + ClrSegment currSegment = null; + List<(ulong StackAddress, ulong PotentialObject)> withinCurrSegment = new(64); + int segmentIndex = 0; + foreach ((ulong _, ulong PotentialObject) entry in potentialObjects) + { + Console.CancellationToken.ThrowIfCancellationRequested(); + + // Find the segment of the current potential object, or null if it doesn't live + // within a segment. + ClrSegment segment = GetSegment(entry.PotentialObject, ref segmentIndex); + if (segment is null) + { + continue; + } + + // If we are already processing this segment, just add the entry to the list + if (currSegment == segment) + { + withinCurrSegment.Add(entry); + continue; + } + + // We are finished walking objects from "currSegment". If we found any pointers + // within its range, walk the segment and return every valid object. + if (withinCurrSegment.Count > 0) + { + foreach ((ulong StackAddress, ClrObject Object) validObject in EnumerateObjectsOnSegment(withinCurrSegment, currSegment)) + { + yield return validObject; + } + + withinCurrSegment.Clear(); + } + + // Update currSegment and add this entry to the processing list. + currSegment = segment; + withinCurrSegment.Add(entry); + } + + // Process leftover items + if (withinCurrSegment.Count > 0) + { + foreach ((ulong StackAddress, ClrObject Object) validObject in EnumerateObjectsOnSegment(withinCurrSegment, currSegment)) + { + yield return validObject; + } + } + } + + /// + /// Simultaneously walks the withinCurrSegment list and objects on segment returning valid objects found. + /// + private IEnumerable<(ulong StackAddress, ClrObject Object)> EnumerateObjectsOnSegment(List<(ulong StackAddress, ulong PotentialObject)> withinCurrSegment, ClrSegment segment) + { + if (withinCurrSegment.Count == 0) + { + yield break; + } + + int index = 0; + MemoryRange range = new(withinCurrSegment[0].PotentialObject, withinCurrSegment[withinCurrSegment.Count - 1].PotentialObject + 1); + foreach (ClrObject obj in segment.EnumerateObjects(range, carefully: true)) + { + Console.CancellationToken.ThrowIfCancellationRequested(); + + if (index >= withinCurrSegment.Count) + { + yield break; + } + + while (index < withinCurrSegment.Count && withinCurrSegment[index].PotentialObject < obj) + { + Console.CancellationToken.ThrowIfCancellationRequested(); + + index++; + } + + while (index < withinCurrSegment.Count && obj == withinCurrSegment[index].PotentialObject) + { + Console.CancellationToken.ThrowIfCancellationRequested(); + + if (Verify) + { + if (!Runtime.Heap.IsObjectCorrupted(obj, out _)) + { + yield return (withinCurrSegment[index].StackAddress, obj); + } + } + else + { + yield return (withinCurrSegment[index].StackAddress, obj); + } + + index++; + } + } + } + + private ClrSegment GetSegment(ulong potentialObject, ref int segmentIndex) + { + ImmutableArray segments = Runtime.Heap.Segments; + + // This function assumes that segmentIndex is always within the bounds of segments + // and that all objects passed to it are within the given + // range of segment bounds. + Debug.Assert(segmentIndex >= 0 && segmentIndex <= segments.Length); + Debug.Assert(segments[0].ObjectRange.Start < potentialObject); + Debug.Assert(potentialObject < segments[segments.Length - 1].ObjectRange.End); + + for (; segmentIndex < segments.Length; segmentIndex++) + { + ClrSegment curr = segments[segmentIndex]; + if (potentialObject < curr.Start) + { + return null; + } + else if (potentialObject < curr.ObjectRange.End) + { + return segments[segmentIndex]; + } + } + + // Unreachable. + Debug.Fail("Reached the end of the segment array."); + return null; + } + + private IEnumerable<(ulong RegisterIndex, ulong PotentialObject)> EnumerateRegistersWithinHeapBounds() + { + ClrHeap heap = Runtime.Heap; + + // Segments are always sorted by address + ulong minAddress = heap.Segments[0].ObjectRange.Start; + ulong maxAddress = heap.Segments[heap.Segments.Length - 1].ObjectRange.End - (uint)MemoryService.PointerSize; + + int regCount = ThreadService.Registers.Count(); + for (int i = 0; i < regCount; i++) + { + if (CurrentThread.TryGetRegisterValue(i, out ulong value)) + { + if (minAddress <= value && value < maxAddress) + { + yield return ((ulong)i, value); + } + } + } + } + + private IEnumerable<(ulong StackAddress, ulong PotentialObject)> EnumeratePointersWithinHeapBounds(MemoryRange stack) + { + Debug.Assert(AlignDown(stack.Start) == stack.Start); + Debug.Assert(AlignUp(stack.End) == stack.End); + + uint pointerSize = (uint)MemoryService.PointerSize; + ClrHeap heap = Runtime.Heap; + + // Segments are always sorted by address + ulong minAddress = heap.Segments[0].ObjectRange.Start; + ulong maxAddress = heap.Segments[heap.Segments.Length - 1].ObjectRange.End - pointerSize; + + // Read in 64k chunks + byte[] buffer = ArrayPool.Shared.Rent(64 * 1024); + try + { + ulong address = stack.Start; + while (stack.Contains(address)) + { + Console.CancellationToken.ThrowIfCancellationRequested(); + + if (!MemoryService.ReadMemory(address, buffer, out int read)) + { + break; + } + + read = AlignDown(read); + if (read < pointerSize) + { + break; + } + + for (int i = 0; i < read; i += (int)pointerSize) + { + Console.CancellationToken.ThrowIfCancellationRequested(); + + ulong stackAddress = address + (uint)i; + if (!stack.Contains(stackAddress)) + { + yield break; + } + + ulong potentialObj = GetIndex(buffer, i); + if (minAddress <= potentialObj && potentialObj < maxAddress) + { + yield return (stackAddress, potentialObj); + } + } + + address += (uint)read; + } + } + finally + { + ArrayPool.Shared.Return(buffer); + } + } + + private static ulong GetIndex(Span buffer, int i) => Unsafe.As(ref buffer[i]); + + private MemoryRange GetStackRange() + { + ulong end = 0; + + int spIndex = ThreadService.StackPointerIndex; + if (!CurrentThread.TryGetRegisterValue(spIndex, out ulong stackPointer)) + { + throw new DiagnosticsException($"Unable to get the stack pointer for thread {CurrentThread.ThreadId:x}."); + } + + // On Windows we have the TEB to know where to end the walk. + ulong teb = CurrentThread.GetThreadTeb(); + if (teb != 0) + { + // The stack base is after the first pointer, see TEB and NT_TIB. + MemoryService.ReadPointer(teb + (uint)MemoryService.PointerSize, out end); + } + + if (end == 0) + { + end = stackPointer + 0xFFFF; + } + + return new(AlignDown(stackPointer), AlignUp(end)); + } + + private ulong AlignDown(ulong address) + { + ulong mask = ~((ulong)MemoryService.PointerSize - 1); + return address & mask; + } + + private int AlignDown(int value) + { + int mask = ~(MemoryService.PointerSize - 1); + return value & mask; + } + + private ulong AlignUp(ulong address) + { + ulong pointerSize = (ulong)MemoryService.PointerSize; + if (address > ulong.MaxValue - pointerSize) + { + return AlignDown(address); + } + + ulong mask = ~(pointerSize - 1); + return (address + pointerSize - 1) & mask; + } + } +} diff --git a/src/Microsoft.Diagnostics.ExtensionCommands/EEHeapCommand.cs b/src/Microsoft.Diagnostics.ExtensionCommands/EEHeapCommand.cs index a7fe9e3dd4..326f2efef2 100644 --- a/src/Microsoft.Diagnostics.ExtensionCommands/EEHeapCommand.cs +++ b/src/Microsoft.Diagnostics.ExtensionCommands/EEHeapCommand.cs @@ -151,7 +151,7 @@ private ulong PrintAppDomain(TableOutput output, ClrAppDomain appDomain, string IOrderedEnumerable> filteredHeapsByKind = from heap in appDomain.EnumerateLoaderAllocatorHeaps() where IsIncludedInFilter(heap) - where loaderAllocatorsSeen.Add(heap.Address) + where loaderAllocatorsSeen.Add(heap.MemoryRange.Start) group heap by heap.Kind into g orderby GetSortOrder(g.Key) select g; @@ -244,7 +244,7 @@ private ulong PrintCodeHeaps(TableOutput output, ClrRuntime clrRuntime) { output.WriteRow("JIT Manager:", jitManager.Address); - IEnumerable heaps = jitManager.EnumerateNativeHeaps().Where(IsIncludedInFilter).OrderBy(r => r.Kind).ThenBy(r => r.Address); + IEnumerable heaps = jitManager.EnumerateNativeHeaps().Where(IsIncludedInFilter).OrderBy(r => r.Kind).ThenBy(r => r.MemoryRange.Start); ulong jitMgrSize = 0, jitMgrWasted = 0; foreach (ClrNativeHeapInfo heap in heaps) @@ -284,15 +284,15 @@ private bool IsIncludedInFilter(ClrNativeHeapInfo info) return true; } - if (filterRange.Contains(info.Address)) + if (filterRange.Contains(info.MemoryRange.Start)) { return true; } - if (info.Size is ulong size && size > 0) + if (info.MemoryRange.Length > 0) { // Check for the last valid address in the range - return filterRange.Contains(info.Address + size - 1); + return filterRange.Contains(info.MemoryRange.End - 1); } return false; @@ -300,14 +300,15 @@ private bool IsIncludedInFilter(ClrNativeHeapInfo info) private (ulong Size, ulong Wasted) CalculateSizeAndWasted(StringBuilder sb, ClrNativeHeapInfo heap) { - sb.Append(heap.Address.ToString("x12")); + sb.Append(heap.MemoryRange.Start.ToString("x12")); - if (heap.Size is ulong size) + ulong size = heap.MemoryRange.Length; + if (size > 0) { sb.Append('('); sb.Append(size.ToString("x")); sb.Append(':'); - ulong actualSize = GetActualSize(heap.Address, size); + ulong actualSize = GetActualSize(heap.MemoryRange.Start, size); sb.Append(actualSize.ToString("x")); sb.Append(')'); diff --git a/src/Microsoft.Diagnostics.ExtensionCommands/FinalizeQueueCommand.cs b/src/Microsoft.Diagnostics.ExtensionCommands/FinalizeQueueCommand.cs new file mode 100644 index 0000000000..f413b5cb90 --- /dev/null +++ b/src/Microsoft.Diagnostics.ExtensionCommands/FinalizeQueueCommand.cs @@ -0,0 +1,224 @@ +// 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.Collections.Generic; +using System.Linq; +using Microsoft.Diagnostics.DebugServices; +using Microsoft.Diagnostics.Runtime; + +namespace Microsoft.Diagnostics.ExtensionCommands +{ + [Command(Name = "finalizequeue", Help = "Displays all objects registered for finalization.")] + public class FinalizeQueueCommand : CommandBase + { + [Option(Name = "-detail", Help = "Will display extra information on any SyncBlocks that need to be cleaned up, and on any RuntimeCallableWrappers (RCWs) that await cleanup. Both of these data structures are cached and cleaned up by the finalizer thread when it gets a chance to run.")] + public bool Detail { get; set; } + + [Option(Name = "-allReady", Help = "Specifying this argument will allow for the display of all objects that are ready for finalization, whether they are already marked by the GC as such, or whether the next GC will. The objects that are not in the \"Ready for finalization\" list are finalizable objects that are no longer rooted. This option can be very expensive, as it verifies whether all the objects in the finalizable queues are still rooted or not.")] + public bool AllReady { get; set; } + + [Option(Name = "-short", Help = "Limits the output to just the address of each object. If used in conjunction with -allReady it enumerates all objects that have a finalizer that are no longer rooted. If used independently it lists all objects in the finalizable and \"ready for finalization\" queues.")] + public bool Short { get; set; } + + [Option(Name = "-mt", Help = "Limits the search for finalizable objects to only those matching the given MethodTable.")] + public string MethodTable { get; set; } + + [Option(Name = "-stat", Aliases = new string[] { "-summary" }, Help = "Only print object statistics, not the list of all objects.")] + public bool Stat { get; set; } + + [ServiceImport] + public LiveObjectService LiveObjects { get; set; } + + [ServiceImport] + public RootCacheService RootCache { get; set; } + + [ServiceImport] + public DumpHeapService DumpHeap { get; set; } + + [ServiceImport] + public ClrRuntime Runtime { get; set; } + + public override void Invoke() + { + ulong mt = 0; + if (!string.IsNullOrWhiteSpace(MethodTable)) + { + mt = ParseAddress(MethodTable) ?? throw new ArgumentException($"Could not parse MethodTable: '{MethodTable}'"); + } + + if (Short && Stat) + { + throw new ArgumentException("Cannot specify both -short and -stat."); + } + + // If we are going to search for only live objects, be sure to print a warning first + // in the output of the command instead of in between the rest of the output. + if (AllReady) + { + LiveObjects.PrintWarning = true; + LiveObjects.Initialize(); + } + + if (!Short) + { + PrintSyncBlockCleanupData(); + PrintRcwCleanupData(); + Console.WriteLine("----------------------------------"); + Console.WriteLine(); + + PrintGenerationalRanges(); + + if (AllReady) + { + Console.WriteLine("Statistics for all finalizable objects that are no longer rooted:"); + } + else + { + Console.WriteLine("Statistics for all finalizable objects (including all objects ready for finalization):"); + } + } + + IEnumerable objects = EnumerateFinalizableObjects(AllReady, mt); + DumpHeapService.DisplayKind displayKind = Short ? DumpHeapService.DisplayKind.Short : DumpHeapService.DisplayKind.Normal; + + DumpHeap.PrintHeap(objects, displayKind, Stat, printFragmentation: false); + + } + private IEnumerable EnumerateFinalizableObjects(bool allReady, ulong mt) + { + IEnumerable result = EnumerateValidFinalizableObjectsWithTypeFilter(mt); + + if (allReady) + { + HashSet rootedByFinalizer = new(); + foreach (ClrRoot root in Runtime.Heap.EnumerateFinalizerRoots()) + { + Console.CancellationToken.ThrowIfCancellationRequested(); + + ClrObject obj = root.Object; + if (obj.IsValid) + { + rootedByFinalizer.Add(obj); + } + } + + // We are trying to find all objects that are ready to be finalized, which is essentially + // all dead objects. However, objects which were previously collected but waiting on + // the finalizer thread to process them are considered "live" because they are rooted by + // the finalizer queue. So our result needs to be either dead objects or directly rooted + // by the finalizer queue. + result = result.Where(obj => rootedByFinalizer.Contains(obj) || !LiveObjects.IsLive(obj)); + } + + return result; + } + + private IEnumerable EnumerateValidFinalizableObjectsWithTypeFilter(ulong mt) + { + foreach (ClrObject obj in Runtime.Heap.EnumerateFinalizableObjects()) + { + Console.CancellationToken.ThrowIfCancellationRequested(); + + if (!obj.IsValid) + { + continue; + } + + if (mt != 0 && obj.Type.MethodTable != mt) + { + continue; + } + + yield return obj; + } + } + + private void PrintSyncBlockCleanupData() + { + TableOutput output = null; + int total = 0; + foreach (ClrSyncBlockCleanupData cleanup in Runtime.EnumerateSyncBlockCleanupData()) + { + Console.CancellationToken.ThrowIfCancellationRequested(); + + if (output is null) + { + output = new(Console, (16, "x12"), (16, "x12"), (16, "x12")); + output.WriteRow("SyncBlock", "RCW", "CCW", "ComClassFactory"); + } + + output.WriteRow(cleanup.SyncBlock, cleanup.Rcw, cleanup.Ccw, cleanup.ClassFactory); + total++; + } + + Console.WriteLine($"SyncBlocks to be cleaned up: {total:n0}"); + } + + private void PrintRcwCleanupData() + { + TableOutput output = null; + int freeThreadedCount = 0; + int mtaCount = 0; + int staCount = 0; + + foreach (ClrRcwCleanupData cleanup in Runtime.EnumerateRcwCleanupData()) + { + Console.CancellationToken.ThrowIfCancellationRequested(); + + if (output is null) + { + output = new(Console, (16, "x12"), (16, "x12"), (16, "x12")); + output.WriteRow("RCW", "Context", "Thread", "Apartment"); + } + + string apartment; + if (cleanup.IsFreeThreaded) + { + freeThreadedCount++; + apartment = "(FreeThreaded)"; + } + else if (cleanup.Thread == 0) + { + mtaCount++; + apartment = "(MTA)"; + } + else + { + staCount++; + apartment = "(STA)"; + } + + output.WriteRow(cleanup.Rcw, cleanup.Context, cleanup.Thread, apartment); + } + + Console.WriteLine($"Free-Threaded Interfaces to be released: {freeThreadedCount:n0}"); + Console.WriteLine($"MTA Interfaces to be released: {mtaCount:n0}"); + Console.WriteLine($"STA Interfaces to be released: {staCount:n0}"); + } + + private void PrintGenerationalRanges() + { + foreach (ClrSubHeap heap in Runtime.Heap.SubHeaps) + { + Console.CancellationToken.ThrowIfCancellationRequested(); + + Console.WriteLine($"Heap {heap.Index}"); + + WriteGeneration(heap, 0); + WriteGeneration(heap, 1); + WriteGeneration(heap, 2); + + Console.WriteLine($"Ready for finalization {heap.FinalizerQueueRoots.Length / (uint)IntPtr.Size:n0} objects ({heap.FinalizerQueueRoots.Start:x}->{heap.FinalizerQueueRoots.End:x})"); + + Console.WriteLine("------------------------------"); + } + } + + private void WriteGeneration(ClrSubHeap heap, int gen) + { + MemoryRange range = heap.GenerationalFinalizableObjects[gen]; + Console.WriteLine($"generation {gen} has {range.Length / (uint)IntPtr.Size:n0} objects ({range.Start:x}->{range.End:x})"); + } + } +} diff --git a/src/Microsoft.Diagnostics.ExtensionCommands/GCRootCommand.cs b/src/Microsoft.Diagnostics.ExtensionCommands/GCRootCommand.cs index 4edb693492..abe025273c 100644 --- a/src/Microsoft.Diagnostics.ExtensionCommands/GCRootCommand.cs +++ b/src/Microsoft.Diagnostics.ExtensionCommands/GCRootCommand.cs @@ -61,6 +61,22 @@ public override void Invoke() if (AsGCGeneration.HasValue) { int gen = AsGCGeneration.Value; + + ClrSegment seg = Runtime.Heap.GetSegmentByAddress(address); + if (seg is null) + { + Console.WriteLineError($"Address {address:x} is not in the managed heap."); + return; + } + + Generation objectGen = seg.GetGeneration(address); + if (gen < (int)objectGen) + { + Console.WriteLine($"Object {address:x} will survive this collection:"); + Console.WriteLine($" gen({address:x}) = {objectGen} > {gen} = condemned generation."); + return; + } + if (gen < 0 || gen > 1) { // If not gen0 or gen1, treat it as a normal !gcroot diff --git a/src/Microsoft.Diagnostics.ExtensionCommands/LiveObjectService.cs b/src/Microsoft.Diagnostics.ExtensionCommands/LiveObjectService.cs index ed39e0de0b..a77b997eba 100644 --- a/src/Microsoft.Diagnostics.ExtensionCommands/LiveObjectService.cs +++ b/src/Microsoft.Diagnostics.ExtensionCommands/LiveObjectService.cs @@ -35,6 +35,11 @@ public bool IsLive(ulong obj) return _liveObjs.Contains(obj); } + public void Initialize() + { + _liveObjs ??= CreateObjectSet(); + } + private HashSet CreateObjectSet() { ClrHeap heap = Runtime.Heap; diff --git a/src/Microsoft.Diagnostics.ExtensionCommands/NativeAddressHelper.cs b/src/Microsoft.Diagnostics.ExtensionCommands/NativeAddressHelper.cs index 2f48a81337..9658d026e3 100644 --- a/src/Microsoft.Diagnostics.ExtensionCommands/NativeAddressHelper.cs +++ b/src/Microsoft.Diagnostics.ExtensionCommands/NativeAddressHelper.cs @@ -13,10 +13,19 @@ namespace Microsoft.Diagnostics.ExtensionCommands { [ServiceExport(Scope = ServiceScope.Target)] - public sealed class NativeAddressHelper + public sealed class NativeAddressHelper : IDisposable { + private readonly IDisposable _onFlushEvent; private ((bool, bool, bool, bool) Key, DescribedRegion[] Result) _previous; + public NativeAddressHelper(ITarget target) + { + Target = target; + _onFlushEvent = target.OnFlushEvent.Register(() => _previous = default); + } + + public void Dispose() => _onFlushEvent.Dispose(); + [ServiceImport] public ITarget Target { get; set; } @@ -301,7 +310,7 @@ private DescribedRegion[] EnumerateAddressSpaceWorker(bool tagClrMemoryRanges, b _ => ClrMemoryKind.Unknown }; - yield return (nativeHeap.Address, nativeHeap.Size ?? 0, kind); + yield return (nativeHeap.MemoryRange.Start, nativeHeap.MemoryRange.Length, kind); } // .Net 8 and beyond has accurate HandleTable memory info. diff --git a/src/SOS/SOS.Hosting/Commands/SOSCommand.cs b/src/SOS/SOS.Hosting/Commands/SOSCommand.cs index d398b19459..1190fd29ab 100644 --- a/src/SOS/SOS.Hosting/Commands/SOSCommand.cs +++ b/src/SOS/SOS.Hosting/Commands/SOSCommand.cs @@ -27,12 +27,10 @@ namespace SOS.Hosting [Command(Name = "dumpobj", DefaultOptions = "DumpObj", Aliases = new string[] { "do" }, Help = "Displays info about an object at the specified address.")] [Command(Name = "dumpsig", DefaultOptions = "DumpSig", Help = "Dumps the signature of a method or field specified by .")] [Command(Name = "dumpsigelem", DefaultOptions = "DumpSigElem", Help = "Dumps a single element of a signature object.")] - [Command(Name = "dumpstackobjects", DefaultOptions = "DumpStackObjects", Aliases = new string[] { "dso" }, Help = "Displays all managed objects found within the bounds of the current stack.")] [Command(Name = "dumpvc", DefaultOptions = "DumpVC", Help = "Displays info about the fields of a value class.")] [Command(Name = "eeversion", DefaultOptions = "EEVersion", Help = "Displays information about the runtime version.")] [Command(Name = "ehinfo", DefaultOptions = "EHInfo", Help = "Displays the exception handling blocks in a JIT-ed method.")] [Command(Name = "enummem", DefaultOptions = "enummem", Help = "ICLRDataEnumMemoryRegions.EnumMemoryRegions test command.")] - [Command(Name = "finalizequeue", DefaultOptions = "FinalizeQueue", Help = "Displays all objects registered for finalization.")] [Command(Name = "findappdomain", DefaultOptions = "FindAppDomain", Help = "Attempts to resolve the AppDomain of a GC object.")] [Command(Name = "gchandles", DefaultOptions = "GCHandles", Help = "Provides statistics about GCHandles in the process.")] [Command(Name = "gcinfo", DefaultOptions = "GCInfo", Help = "Displays JIT GC encoding for a method.")] diff --git a/src/SOS/SOS.UnitTests/SOS.cs b/src/SOS/SOS.UnitTests/SOS.cs index ae55c129bf..4332a63da8 100644 --- a/src/SOS/SOS.UnitTests/SOS.cs +++ b/src/SOS/SOS.UnitTests/SOS.cs @@ -340,8 +340,7 @@ public async Task StackAndOtherTests(TestConfiguration config) // This debuggee needs the directory of the exes/dlls to load the SymbolTestDll assembly. await SOSTestHelpers.RunTest( - scriptName: "StackAndOtherTests.script", - new SOSRunner.TestInformation + scriptName: "StackAndOtherTests.script", new SOSRunner.TestInformation { TestConfiguration = currentConfig, TestName = "SOS.StackAndOtherTests", diff --git a/src/SOS/SOS.UnitTests/SOSRunner.cs b/src/SOS/SOS.UnitTests/SOSRunner.cs index e1f993f3be..98366fb0d0 100644 --- a/src/SOS/SOS.UnitTests/SOSRunner.cs +++ b/src/SOS/SOS.UnitTests/SOSRunner.cs @@ -145,6 +145,8 @@ public DumpType DumpType public string DumpNameSuffix { get; set; } + public bool EnableSOSLogging { get; set; } = true; + public bool TestCrashReport { get { return _testCrashReport && DumpGenerator == DumpGenerator.CreateDump && OS.Kind != OSKind.Windows && TestConfiguration.RuntimeFrameworkVersionMajor >= 6; } @@ -457,6 +459,7 @@ public static async Task StartDebugger(TestInformation information, D { // Setup the logging from the options in the config file outputHelper = TestRunner.ConfigureLogging(config, information.OutputHelper, information.TestName); + string sosLogFile = information.EnableSOSLogging ? Path.Combine(config.LogDirPath, $"{information.TestName}.{config.LogSuffix}.soslog") : null; // Figure out which native debugger to use NativeDebugger debugger = GetNativeDebuggerToUse(config, action); @@ -669,6 +672,7 @@ public static async Task StartDebugger(TestInformation information, D break; } + // Create the native debugger process running ProcessRunner processRunner = new ProcessRunner(debuggerPath, ReplaceVariables(variables, arguments.ToString())). WithEnvironmentVariable("DOTNET_MULTILEVEL_LOOKUP", "0"). @@ -682,6 +686,11 @@ public static async Task StartDebugger(TestInformation information, D processRunner.WithExpectedExitCode(0); } + if (sosLogFile != null) + { + processRunner.WithEnvironmentVariable("DOTNET_ENABLED_SOS_LOGGING", sosLogFile); + } + // Disable W^E so that the bpmd command and the tests pass // Issue: https://github.com/dotnet/diagnostics/issues/3126 processRunner.WithRuntimeConfiguration("EnableWriteXorExecute", "0"); @@ -1420,6 +1429,11 @@ private HashSet GetEnabledDefines() defines.Add("UNIX_SINGLE_FILE_APP"); } } + string setHostRuntime = _config.SetHostRuntime(); + if (!string.IsNullOrEmpty(setHostRuntime) && setHostRuntime == "-none") + { + defines.Add("HOST_RUNTIME_NONE"); + } return defines; } diff --git a/src/SOS/SOS.UnitTests/Scripts/GCPOH.script b/src/SOS/SOS.UnitTests/Scripts/GCPOH.script index 4873d7037b..2c223a6bf0 100644 --- a/src/SOS/SOS.UnitTests/Scripts/GCPOH.script +++ b/src/SOS/SOS.UnitTests/Scripts/GCPOH.script @@ -18,7 +18,7 @@ ENDIF:CDB LOADSOS SOSCOMMAND:DumpStackObjects -VERIFY:\s+\s+System.Byte\[\]\s+ +VERIFY:\s*\s+\s+System.Byte\[\]\s+ SOSCOMMAND:DumpObj \w+\s+()\s+(System.Byte\[\]!\$0_)*System.Byte\[\]\s+ VERIFY:\s+Name: System.Byte\[\]\s+ diff --git a/src/SOS/SOS.UnitTests/Scripts/GCTests.script b/src/SOS/SOS.UnitTests/Scripts/GCTests.script index 96f558f780..38be904a97 100644 --- a/src/SOS/SOS.UnitTests/Scripts/GCTests.script +++ b/src/SOS/SOS.UnitTests/Scripts/GCTests.script @@ -24,7 +24,7 @@ ENDIF:CDB LOADSOS SOSCOMMAND:DumpStackObjects -VERIFY:\s+\s+System.IO.StringWriter\s+ +VERIFY:\s*\s+\s+System.IO.StringWriter\s+ SOSCOMMAND:DumpObj \w+\s+()\s+(System.IO.StringWriter!\$0_)*System.IO.StringWriter\s+ IFDEF:MAJOR_RUNTIME_VERSION_2 @@ -36,7 +36,7 @@ VERIFY:\s+\s+\s+\s+System\.IO.TextWriter\s+\s+st ENDIF:MAJOR_RUNTIME_VERSION_GE_3 SOSCOMMAND:DumpStackObjects -VERIFY:\s\s([Gg][Cc]where!\$0_)*GCWhere\s+ +VERIFY:\s*\s+\s+([Gg][Cc]where!\$0_)*GCWhere\s+ SOSCOMMAND:GCWhere \w+\s+()\s+([Gg][Cc]where!\$0_)*GCWhere\s+ # we care that the Gen is 0 diff --git a/src/SOS/SOS.UnitTests/Scripts/OtherCommands.script b/src/SOS/SOS.UnitTests/Scripts/OtherCommands.script index 62e5c9b359..8274219dcd 100644 --- a/src/SOS/SOS.UnitTests/Scripts/OtherCommands.script +++ b/src/SOS/SOS.UnitTests/Scripts/OtherCommands.script @@ -126,9 +126,9 @@ SOSCOMMAND:FinalizeQueue VERIFY:\s*SyncBlocks to be cleaned up:\s+\s+ VERIFY:(\s*Free-Threaded Interfaces to be released:\s+\s+)? VERIFY:\s*Statistics for all finalizable objects.*:\s+ -VERIFY:\s+MT\s+Count\s+TotalSize\s+Class Name\s+ +VERIFY:\s+Address\s+MT\s+Size\s+ VERIFY:(\s*\s+\s+\s+.*)? -VERIFY:\s*Total\s+\s+objects\s+ +VERIFY:\s*Total\s+\s+objects.*\s+bytes\s* EXTCOMMAND:logopen %LOG_PATH%/%TEST_NAME%.%LOG_SUFFIX%.consolelog EXTCOMMAND:logging %LOG_PATH%/%TEST_NAME%.%LOG_SUFFIX%.diaglog diff --git a/src/SOS/SOS.UnitTests/Scripts/StackAndOtherTests.script b/src/SOS/SOS.UnitTests/Scripts/StackAndOtherTests.script index 685b0d2edf..5c31e0ef1d 100644 --- a/src/SOS/SOS.UnitTests/Scripts/StackAndOtherTests.script +++ b/src/SOS/SOS.UnitTests/Scripts/StackAndOtherTests.script @@ -180,19 +180,25 @@ VERIFY:.*\s+\s+\s+\[DEFAULT\] I4 SymbolTestApp\.Program\.Foo1\(. VERIFY:.*\s+\s+\s+\[DEFAULT\] Void SymbolTestApp\.Program\.Main\(.*\)\s+\(.*\)\s+ VERIFY:.*\s+Stack walk complete.\s+ +SOSCOMMAND: runtimes + +!IFDEF:HOST_RUNTIME_NONE + # Verify DumpStackObjects works SOSCOMMAND:DumpStackObjects VERIFY:.*OS Thread Id:\s+0x\s+.* -VERIFY:\s+([R|E])*SP/REG\s+Object\s+Name\s+ -VERIFY:.*\s+\s+\s+System\.String.* -VERIFY:.*\s+\s+\s+System\.String\[\].* +VERIFY:\s*SP/REG\s+Object\s+Name\s+ +VERIFY:.*\s*\s+\s+System\.String.* +VERIFY:.*\s*\s+\s+System\.String\[\].* # Verify DumpStackObjects -verify works SOSCOMMAND:DumpStackObjects -verify VERIFY:.*OS Thread Id:\s+0x\s+.* -VERIFY:\s+([R|E])*SP/REG\s+Object\s+Name\s+ -VERIFY:.*\s+\s+\s+System\.String.* -VERIFY:.*\s+\s+\s+System\.String\[\].* +VERIFY:\s*SP/REG\s+Object\s+Name\s+ +VERIFY:.*\s*\s+\s+System\.String.* +VERIFY:.*\s*\s+\s+System\.String\[\].* + +ENDIF:HOST_RUNTIME_NONE ENDIF:NETCORE_OR_DOTNETDUMP diff --git a/src/SOS/SOS.UnitTests/Scripts/StackTests.script b/src/SOS/SOS.UnitTests/Scripts/StackTests.script index 57a5d87ee3..002a019e0c 100644 --- a/src/SOS/SOS.UnitTests/Scripts/StackTests.script +++ b/src/SOS/SOS.UnitTests/Scripts/StackTests.script @@ -137,7 +137,7 @@ ENDIF:NETCORE_OR_DOTNETDUMP # 7) Verify DumpStackObjects works SOSCOMMAND:DumpStackObjects VERIFY:.*OS Thread Id:\s+0x\s+.* -VERIFY:\s+([R|E])*SP/REG\s+Object\s+Name\s+ +VERIFY:\s*SP/REG\s+Object\s+Name\s+ VERIFY:.*\s+\s+\s+System\.FormatException\s+ VERIFY:.*\s+\s+\s+System\.InvalidOperationException\s+ VERIFY:.*\s+\s+\s+System\.String.* @@ -145,7 +145,7 @@ VERIFY:.*\s+\s+\s+System\.String.* # 8) Verify DumpStackObjects -verify works SOSCOMMAND:DumpStackObjects -verify VERIFY:.*OS Thread Id:\s+0x\s+.* -VERIFY:\s+([R|E])*SP/REG\s+Object\s+Name\s+ +VERIFY:\s*SP/REG\s+Object\s+Name\s+ VERIFY:.*\s+\s+\s+System\.FormatException\s+ VERIFY:.*\s+\s+\s+System\.InvalidOperationException\s+ VERIFY:.*\s+\s+\s+System\.String.* diff --git a/src/SOS/Strike/disasm.cpp b/src/SOS/Strike/disasm.cpp index 482f48f854..10590c165d 100644 --- a/src/SOS/Strike/disasm.cpp +++ b/src/SOS/Strike/disasm.cpp @@ -1039,7 +1039,6 @@ void DumpStackWorker (DumpStackFlag &DSFlag) /// X86Machine implementation /// LPCSTR X86Machine::s_DumpStackHeading = "ChildEBP RetAddr Caller, Callee\n"; -LPCSTR X86Machine::s_DSOHeading = "ESP/REG Object Name\n"; LPCSTR X86Machine::s_GCRegs[7] = {"eax", "ebx", "ecx", "edx", "esi", "edi", "ebp"}; LPCSTR X86Machine::s_SPName = "ESP"; @@ -1081,7 +1080,6 @@ void X86Machine::DumpGCInfo(GCInfoToken gcInfoToken, unsigned methodSize, printf /// ARMMachine implementation /// LPCSTR ARMMachine::s_DumpStackHeading = "ChildFP RetAddr Caller, Callee\n"; -LPCSTR ARMMachine::s_DSOHeading = "SP/REG Object Name\n"; LPCSTR ARMMachine::s_GCRegs[14] = {"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "lr"}; LPCSTR ARMMachine::s_SPName = "sp"; @@ -1093,7 +1091,6 @@ LPCSTR ARMMachine::s_SPName = "sp"; /// AMD64Machine implementation /// LPCSTR AMD64Machine::s_DumpStackHeading = "Child-SP RetAddr Caller, Callee\n"; -LPCSTR AMD64Machine::s_DSOHeading = "RSP/REG Object Name\n"; LPCSTR AMD64Machine::s_GCRegs[15] = {"rax", "rbx", "rcx", "rdx", "rsi", "rdi", "rbp", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"}; LPCSTR AMD64Machine::s_SPName = "RSP"; @@ -1121,7 +1118,6 @@ void AMD64Machine::DumpGCInfo(GCInfoToken gcInfoToken, unsigned methodSize, prin /// ARM64Machine implementation /// LPCSTR ARM64Machine::s_DumpStackHeading = "ChildFP RetAddr Caller, Callee\n"; -LPCSTR ARM64Machine::s_DSOHeading = "SP/REG Object Name\n"; // excluding x18, fp & lr as these will not contain object references LPCSTR ARM64Machine::s_GCRegs[28] = {"x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7", "x8", "x9", "x10", "x11", "x12", "x13", diff --git a/src/SOS/Strike/disasm.h b/src/SOS/Strike/disasm.h index 0bacb2b17e..a09e5abecf 100644 --- a/src/SOS/Strike/disasm.h +++ b/src/SOS/Strike/disasm.h @@ -171,7 +171,6 @@ class X86Machine : public IMachine virtual void FillTargetContext(LPVOID destCtx, LPVOID srcCtx, int idx = 0) const; virtual LPCSTR GetDumpStackHeading() const { return s_DumpStackHeading; } - virtual LPCSTR GetDumpStackObjectsHeading() const { return s_DSOHeading; } virtual LPCSTR GetSPName() const { return s_SPName; } virtual void GetGCRegisters(LPCSTR** regNames, unsigned int* cntRegs) const { _ASSERTE(cntRegs != NULL); *regNames = s_GCRegs; *cntRegs = ARRAY_SIZE(s_GCRegs); } @@ -188,7 +187,6 @@ class X86Machine : public IMachine private: static LPCSTR s_DumpStackHeading; - static LPCSTR s_DSOHeading; static LPCSTR s_GCRegs[7]; static LPCSTR s_SPName; }; // class X86Machine @@ -243,7 +241,6 @@ class ARMMachine : public IMachine virtual void FillTargetContext(LPVOID destCtx, LPVOID srcCtx, int idx = 0) const; virtual LPCSTR GetDumpStackHeading() const { return s_DumpStackHeading; } - virtual LPCSTR GetDumpStackObjectsHeading() const { return s_DSOHeading; } virtual LPCSTR GetSPName() const { return s_SPName; } virtual void GetGCRegisters(LPCSTR** regNames, unsigned int* cntRegs) const { _ASSERTE(cntRegs != NULL); *regNames = s_GCRegs; *cntRegs = ARRAY_SIZE(s_GCRegs); } @@ -260,7 +257,6 @@ class ARMMachine : public IMachine private: static LPCSTR s_DumpStackHeading; - static LPCSTR s_DSOHeading; static LPCSTR s_GCRegs[14]; static LPCSTR s_SPName; static ARMMachine s_ARMMachineInstance; @@ -316,7 +312,6 @@ class AMD64Machine : public IMachine virtual void FillTargetContext(LPVOID destCtx, LPVOID srcCtx, int idx = 0) const; virtual LPCSTR GetDumpStackHeading() const { return s_DumpStackHeading; } - virtual LPCSTR GetDumpStackObjectsHeading() const { return s_DSOHeading; } virtual LPCSTR GetSPName() const { return s_SPName; } virtual void GetGCRegisters(LPCSTR** regNames, unsigned int* cntRegs) const { _ASSERTE(cntRegs != NULL); *regNames = s_GCRegs; *cntRegs = ARRAY_SIZE(s_GCRegs); } @@ -333,7 +328,6 @@ class AMD64Machine : public IMachine private: static LPCSTR s_DumpStackHeading; - static LPCSTR s_DSOHeading; static LPCSTR s_GCRegs[15]; static LPCSTR s_SPName; }; // class AMD64Machine @@ -386,7 +380,6 @@ class ARM64Machine : public IMachine virtual void FillTargetContext(LPVOID destCtx, LPVOID srcCtx, int idx = 0) const; virtual LPCSTR GetDumpStackHeading() const { return s_DumpStackHeading; } - virtual LPCSTR GetDumpStackObjectsHeading() const { return s_DSOHeading; } virtual LPCSTR GetSPName() const { return s_SPName; } virtual void GetGCRegisters(LPCSTR** regNames, unsigned int* cntRegs) const { _ASSERTE(cntRegs != NULL); *regNames = s_GCRegs; *cntRegs = ARRAY_SIZE(s_GCRegs);} @@ -402,7 +395,6 @@ class ARM64Machine : public IMachine ARM64Machine & operator=(const ARM64Machine&); // undefined static LPCSTR s_DumpStackHeading; - static LPCSTR s_DSOHeading; static LPCSTR s_GCRegs[28]; static LPCSTR s_SPName; diff --git a/src/SOS/Strike/eeheap.cpp b/src/SOS/Strike/eeheap.cpp index 3b89f7023d..259cb42996 100644 --- a/src/SOS/Strike/eeheap.cpp +++ b/src/SOS/Strike/eeheap.cpp @@ -529,440 +529,3 @@ BOOL GetCollectibleDataEfficient(DWORD_PTR dwAddrMethTable, BOOL& bCollectible, return TRUE; } - -// This function expects stat to be valid, and ready to get statistics. -void GatherOneHeapFinalization(DacpGcHeapDetails& heapDetails, HeapStat *stat, BOOL bAllReady, BOOL bShort) -{ - DWORD_PTR dwAddr=0; - UINT m; - - if (!bShort) - { - for (m = 0; m <= GetMaxGeneration(); m ++) - { - if (IsInterrupt()) - return; - - ExtOut("generation %d has %d finalizable objects ", m, - (SegQueueLimit(heapDetails,gen_segment(m)) - SegQueue(heapDetails,gen_segment(m))) / sizeof(size_t)); - - ExtOut ("(%p->%p)\n", - SOS_PTR(SegQueue(heapDetails,gen_segment(m))), - SOS_PTR(SegQueueLimit(heapDetails,gen_segment(m)))); - } - } - - if (bAllReady) - { - if (!bShort) - { - ExtOut ("Finalizable but not rooted: "); - } - - TADDR rngStart = (TADDR)SegQueue(heapDetails, gen_segment(GetMaxGeneration())); - TADDR rngEnd = (TADDR)SegQueueLimit(heapDetails, gen_segment(0)); - - std::stringstream argsBuilder; - argsBuilder << std::hex << rngStart << " "; - argsBuilder << std::hex << rngEnd << " "; - argsBuilder << "-nofinalizer "; - if (bShort) - argsBuilder << "-short"; - - ExecuteCommand("notreachableinrange", argsBuilder.str().c_str()); - } - - if (!bShort) - { - ExtOut ("Ready for finalization %d objects ", - (SegQueueLimit(heapDetails,FinalizerListSeg)-SegQueue(heapDetails,CriticalFinalizerListSeg)) / sizeof(size_t)); - ExtOut ("(%p->%p)\n", - SOS_PTR(SegQueue(heapDetails,CriticalFinalizerListSeg)), - SOS_PTR(SegQueueLimit(heapDetails,FinalizerListSeg))); - } - - // if bAllReady we only count objects that are ready for finalization, - // otherwise we count all finalizable objects. - TADDR taddrLowerLimit = (bAllReady ? (TADDR)SegQueue(heapDetails, CriticalFinalizerListSeg) : - (DWORD_PTR)SegQueue(heapDetails, gen_segment(GetMaxGeneration()))); - for (dwAddr = taddrLowerLimit; - dwAddr < (DWORD_PTR)SegQueueLimit(heapDetails, FinalizerListSeg); - dwAddr += sizeof (dwAddr)) - { - if (IsInterrupt()) - { - return; - } - - DWORD_PTR objAddr = NULL, - MTAddr = NULL; - - if (SUCCEEDED(MOVE(objAddr, dwAddr)) && SUCCEEDED(GetMTOfObject(objAddr, &MTAddr)) && MTAddr) - { - if (bShort) - { - DMLOut("%s\n", DMLObject(objAddr)); - } - else - { - size_t s = ObjectSize(objAddr); - stat->Add(MTAddr, (DWORD)s); - } - } - } -} - -GCHeapSnapshot::GCHeapSnapshot() -{ - m_isBuilt = FALSE; - m_heapDetails = NULL; -} - -/////////////////////////////////////////////////////////// -SegmentLookup::SegmentLookup() -{ - m_iSegmentsSize = m_iSegmentCount = 0; - - m_segments = new DacpHeapSegmentData[nSegLookupStgIncrement]; - if (m_segments == NULL) - { - ReportOOM(); - } - else - { - m_iSegmentsSize = nSegLookupStgIncrement; - } -} - -BOOL SegmentLookup::AddSegment(DacpHeapSegmentData *pData) -{ - // appends the address of a new (initialized) instance of DacpHeapSegmentData to the list of segments - // (m_segments) adding space for a segment when necessary. - // @todo Microsoft: The field name m_iSegmentSize is a little misleading. It's not the size in bytes, - // but the number of elements allocated for the array. It probably should have been named something like - // m_iMaxSegments instead. - if (m_iSegmentCount >= m_iSegmentsSize) - { - // expand buffer--allocate enough space to hold the elements we already have plus nSegLookupStgIncrement - // more elements - DacpHeapSegmentData *pNewBuffer = new DacpHeapSegmentData[m_iSegmentsSize+nSegLookupStgIncrement]; - if (pNewBuffer==NULL) - return FALSE; - - // copy the old elements into the new array - memcpy(pNewBuffer, m_segments, sizeof(DacpHeapSegmentData)*m_iSegmentsSize); - - // record the new number of elements available - m_iSegmentsSize+=nSegLookupStgIncrement; - - // delete the old array - delete [] m_segments; - - // set m_segments to point to the new array - m_segments = pNewBuffer; - } - - // add pData to the array - m_segments[m_iSegmentCount++] = *pData; - - return TRUE; -} - -SegmentLookup::~SegmentLookup() -{ - if (m_segments) - { - delete [] m_segments; - m_segments = NULL; - } -} - -void SegmentLookup::Clear() -{ - m_iSegmentCount = 0; -} - -CLRDATA_ADDRESS SegmentLookup::GetHeap(CLRDATA_ADDRESS object, BOOL& bFound) -{ - CLRDATA_ADDRESS ret = NULL; - bFound = FALSE; - - // Visit our segments - for (int i=0; i TO_TADDR(object)) - { - ret = m_segments[i].gc_heap; - bFound = TRUE; - break; - } - } - - return ret; -} - -/////////////////////////////////////////////////////////////////////////// - -BOOL GCHeapSnapshot::Build() -{ - Clear(); - - m_isBuilt = FALSE; - - ///- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - /// 1. Get some basic information such as the heap type (SVR or WKS), how many heaps there are, mode and max generation - /// (See code:ClrDataAccess::RequestGCHeapData) - ///- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - if (m_gcheap.Request(g_sos) != S_OK) - { - ExtOut("Error requesting GC Heap data\n"); - return FALSE; - } - - ArrayHolder heapAddrs = NULL; - - ///- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - /// 2. Get a list of the addresses of the heaps when we have multiple heaps in server mode - ///- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - if (m_gcheap.bServerMode) - { - UINT AllocSize; - // allocate an array to hold the starting addresses of each heap when we're in server mode - if (!ClrSafeInt::multiply(sizeof(CLRDATA_ADDRESS), m_gcheap.HeapCount, AllocSize) || - (heapAddrs = new CLRDATA_ADDRESS [m_gcheap.HeapCount]) == NULL) - { - ReportOOM(); - return FALSE; - } - - // and initialize it with their addresses (see code:ClrDataAccess::RequestGCHeapList - // for details) - if (g_sos->GetGCHeapList(m_gcheap.HeapCount, heapAddrs, NULL) != S_OK) - { - ExtOut("Failed to get GCHeaps\n"); - return FALSE; - } - } - - ///- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - /// 3. Get some necessary information about each heap, such as the card table location, the generation - /// table, the heap bounds, etc., and retrieve the heap segments - ///- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // allocate an array to hold the information - m_heapDetails = new GCHeapDetails[m_gcheap.HeapCount]; - - if (m_heapDetails == NULL) - { - ReportOOM(); - return FALSE; - } - - // get the heap information for each heap - // See code:ClrDataAccess::RequestGCHeapDetails for details - for (UINT n = 0; n < m_gcheap.HeapCount; n ++) - { - if (m_gcheap.bServerMode) - { - DacpGcHeapDetails dacHeapDetails; - if (dacHeapDetails.Request(g_sos, heapAddrs[n]) != S_OK) - { - ExtOut("Error requesting details\n"); - return FALSE; - } - - m_heapDetails[n].Set(dacHeapDetails, heapAddrs[n]); - } - else - { - DacpGcHeapDetails dacHeapDetails; - if (dacHeapDetails.Request(g_sos) != S_OK) - { - ExtOut("Error requesting details\n"); - return FALSE; - } - - m_heapDetails[n].Set(dacHeapDetails); - } - - // now get information about the heap segments for this heap - if (!AddSegments(m_heapDetails[n])) - { - ExtOut("Failed to retrieve segments for gc heap\n"); - return FALSE; - } - } - - m_isBuilt = TRUE; - return TRUE; -} - -BOOL GCHeapSnapshot::AddSegments(const GCHeapDetails& details) -{ - int n = 0; - DacpHeapSegmentData segment; - - // This array of addresses gives us access to all the segments. - CLRDATA_ADDRESS AddrSegs[5]; - if (details.has_regions) - { - // with regions, each generation has its own list of segments - for (unsigned gen = 0; gen <= GetMaxGeneration() + 1; gen++) - { - AddrSegs[gen] = details.generation_table[gen].start_segment; - } - if (details.has_poh) - { - AddrSegs[4] = details.generation_table[GetMaxGeneration() + 2].start_segment; // pinned object heap - } - } - else - { - // The generation segments are linked to each other, starting with the maxGeneration segment. - // The second address gives us the large object heap, the third the pinned object heap - - AddrSegs[0] = details.generation_table[GetMaxGeneration()].start_segment; - AddrSegs[1] = details.generation_table[GetMaxGeneration() + 1].start_segment; - AddrSegs[2] = NULL; - if (details.has_poh) - { - AddrSegs[2] = details.generation_table[GetMaxGeneration() + 2].start_segment; // pinned object heap - } - AddrSegs[3] = NULL; - AddrSegs[4] = NULL; - } - - // this loop will get information for all the heap segments in this heap. The outer loop iterates once - // for the "normal" generation segments and once for the large object heap. The inner loop follows the chain - // of segments rooted at AddrSegs[i] - for (unsigned int i = 0; i < ARRAY_SIZE(AddrSegs); ++i) - { - if (AddrSegs[i] == NULL) - { - continue; - } - - CLRDATA_ADDRESS AddrSeg = AddrSegs[i]; - - while (AddrSeg != NULL) - { - if (IsInterrupt()) - { - return FALSE; - } - // Initialize segment by copying fields from the target's heap segment at AddrSeg. - // See code:ClrDataAccess::RequestGCHeapSegment for details. - if (segment.Request(g_sos, AddrSeg, details.original_heap_details) != S_OK) - { - ExtOut("Error requesting heap segment %p\n", SOS_PTR(AddrSeg)); - return FALSE; - } - // add the new segment to the array of segments. This will expand the array if necessary - if (!m_segments.AddSegment(&segment)) - { - ExtOut("strike: Failed to store segment\n"); - return FALSE; - } - // get the next segment in the chain - AddrSeg = segment.next; - } - } - - return TRUE; -} - -void GCHeapSnapshot::Clear() -{ - if (m_heapDetails != NULL) - { - delete [] m_heapDetails; - m_heapDetails = NULL; - } - - m_segments.Clear(); - - m_isBuilt = FALSE; -} - -GCHeapSnapshot g_snapshot; - -GCHeapDetails *GCHeapSnapshot::GetHeap(CLRDATA_ADDRESS objectPointer) -{ - // We need bFound because heap will be NULL if we are Workstation Mode. - // We still need a way to know if the address was found in our segment - // list. - BOOL bFound = FALSE; - CLRDATA_ADDRESS heap = m_segments.GetHeap(objectPointer, bFound); - if (heap) - { - for (UINT i=0; ihas_regions) - { - for (int gen_num = 0; gen_num <= 1; gen_num++) - { - CLRDATA_ADDRESS dwAddrSeg = pDetails->generation_table[gen_num].start_segment; - while (dwAddrSeg != 0) - { - DacpHeapSegmentData segment; - if (segment.Request(g_sos, dwAddrSeg, pDetails->original_heap_details) != S_OK) - { - ExtOut("Error requesting heap segment %p\n", SOS_PTR(dwAddrSeg)); - return 0; - } - // The DAC doesn't fill the generation table with true CLRDATA_ADDRESS values - // but rather with ULONG64 values (i.e. non-sign-extended 64-bit values) - // We use the TO_TADDR below to ensure we won't break if this will ever - // be fixed in the DAC. - if (TO_TADDR(segment.mem) <= taObj && taObj < TO_TADDR(segment.highAllocMark)) - { - return gen_num; - } - dwAddrSeg = segment.next; - } - } - } - else - { - // The DAC doesn't fill the generation table with true CLRDATA_ADDRESS values - // but rather with ULONG64 values (i.e. non-sign-extended 64-bit values) - // We use the TO_TADDR below to ensure we won't break if this will ever - // be fixed in the DAC. - if (taObj >= TO_TADDR(pDetails->generation_table[0].allocation_start) && - taObj <= TO_TADDR(pDetails->alloc_allocated)) - return 0; - - if (taObj >= TO_TADDR(pDetails->generation_table[1].allocation_start) && - taObj <= TO_TADDR(pDetails->generation_table[0].allocation_start)) - return 1; - } - return 2; -} diff --git a/src/SOS/Strike/exts.cpp b/src/SOS/Strike/exts.cpp index c72c91829e..3ebe83fde0 100644 --- a/src/SOS/Strike/exts.cpp +++ b/src/SOS/Strike/exts.cpp @@ -409,3 +409,14 @@ HRESULT GetRuntime(IRuntime** ppRuntime) #endif return target->GetRuntime(ppRuntime); } + +void FlushCheck() +{ +#ifndef FEATURE_PAL + SOSExtensions* extensions = (SOSExtensions*)Extensions::GetInstance(); + if (extensions != nullptr) + { + extensions->FlushCheck(); + } +#endif // !FEATURE_PAL +} diff --git a/src/SOS/Strike/exts.h b/src/SOS/Strike/exts.h index 71916ec45a..cf29ce595b 100644 --- a/src/SOS/Strike/exts.h +++ b/src/SOS/Strike/exts.h @@ -192,6 +192,7 @@ class SOSExtensions : public Extensions }; extern HRESULT GetRuntime(IRuntime** ppRuntime); +extern void FlushCheck(); #ifndef MINIDUMP @@ -322,7 +323,8 @@ inline void DACMessage(HRESULT Status) ControlC = FALSE; \ g_bDacBroken = TRUE; \ g_clrData = NULL; \ - g_sos = NULL; + g_sos = NULL; \ + FlushCheck(); // Also initializes the target machine #define INIT_API_NOEE() \ @@ -464,7 +466,6 @@ class IMachine // Retrieve some target specific output strings virtual LPCSTR GetDumpStackHeading() const = 0; - virtual LPCSTR GetDumpStackObjectsHeading() const = 0; virtual LPCSTR GetSPName() const = 0; // Retrieves the non-volatile registers reported to the GC virtual void GetGCRegisters(LPCSTR** regNames, unsigned int* cntRegs) const = 0; diff --git a/src/SOS/Strike/strike.cpp b/src/SOS/Strike/strike.cpp index f0efe93e8c..20feea9e79 100644 --- a/src/SOS/Strike/strike.cpp +++ b/src/SOS/Strike/strike.cpp @@ -390,6 +390,7 @@ HRESULT ExecuteCommand(PCSTR commandName, PCSTR args) return hostServices->DispatchCommand(commandName, args); } } + ExtErr("Unrecognized command %s\n", commandName); return E_NOTIMPL; } @@ -616,82 +617,6 @@ DECLARE_API (EEStack) return Status; } -HRESULT DumpStackObjectsRaw(size_t nArg, __in_z LPSTR exprBottom, __in_z LPSTR exprTop, BOOL bVerify) -{ - size_t StackTop = 0; - size_t StackBottom = 0; - if (nArg==0) - { - ULONG64 StackOffset; - g_ExtRegisters->GetStackOffset(&StackOffset); - - StackTop = TO_TADDR(StackOffset); - } - else - { - StackTop = GetExpression(exprTop); - if (StackTop == 0) - { - ExtOut("wrong option: %s\n", exprTop); - return E_FAIL; - } - - if (nArg==2) - { - StackBottom = GetExpression(exprBottom); - if (StackBottom == 0) - { - ExtOut("wrong option: %s\n", exprBottom); - return E_FAIL; - } - } - } - -#ifndef FEATURE_PAL - if (IsWindowsTarget()) - { - NT_TIB teb; - ULONG64 dwTebAddr = 0; - HRESULT hr = g_ExtSystem->GetCurrentThreadTeb(&dwTebAddr); - if (SUCCEEDED(hr) && SafeReadMemory(TO_TADDR(dwTebAddr), &teb, sizeof(NT_TIB), NULL)) - { - if (StackTop > TO_TADDR(teb.StackLimit) && StackTop <= TO_TADDR(teb.StackBase)) - { - if (StackBottom == 0 || StackBottom > TO_TADDR(teb.StackBase)) - StackBottom = TO_TADDR(teb.StackBase); - } - } - } -#endif - - if (StackBottom == 0) - StackBottom = StackTop + 0xFFFF; - - if (StackBottom < StackTop) - { - ExtOut("Wrong option: stack selection wrong\n"); - return E_FAIL; - } - - // We can use the gc snapshot to eliminate object addresses that are - // not on the gc heap. - if (!g_snapshot.Build()) - { - ExtOut("Unable to determine bounds of gc heap\n"); - return E_FAIL; - } - - // Print thread ID. - ULONG id = 0; - g_ExtSystem->GetCurrentThreadSystemId (&id); - ExtOut("OS Thread Id: 0x%x ", id); - g_ExtSystem->GetCurrentThreadId (&id); - ExtOut("(%d)\n", id); - - DumpStackObjectsHelper(StackTop, StackBottom, bVerify); - return S_OK; -} - /**********************************************************************\ * Routine Description: * * * @@ -701,32 +626,10 @@ HRESULT DumpStackObjectsRaw(size_t nArg, __in_z LPSTR exprBottom, __in_z LPSTR e \**********************************************************************/ DECLARE_API(DumpStackObjects) { - INIT_API(); + INIT_API_EXT(); MINIDUMP_NOT_SUPPORTED(); - StringHolder exprTop, exprBottom; - - BOOL bVerify = FALSE; - BOOL dml = FALSE; - CMDOption option[] = - { // name, vptr, type, hasValue - {"-verify", &bVerify, COBOOL, FALSE}, - {"/d", &dml, COBOOL, FALSE} - }; - CMDValue arg[] = - { // vptr, type - {&exprTop.data, COSTRING}, - {&exprBottom.data, COSTRING} - }; - size_t nArg; - - if (!GetCMDOption(args, option, ARRAY_SIZE(option), arg, ARRAY_SIZE(arg), &nArg)) - { - return Status; - } - EnableDMLHolder enableDML(dml); - - return DumpStackObjectsRaw(nArg, exprBottom.data, exprTop.data, bVerify); + return ExecuteCommand("dumpstackobjects", args); } /**********************************************************************\ @@ -890,13 +793,7 @@ DECLARE_API(DumpIL) return DecodeILFromAddress(NULL, dwStartAddr); } - if (!g_snapshot.Build()) - { - ExtOut("Unable to build snapshot of the garbage collector state\n"); - return Status; - } - - if (g_snapshot.GetHeap(dwStartAddr) != NULL) + if (sos::IsObject(dwStartAddr)) { dwDynamicMethodObj = dwStartAddr; } @@ -4027,138 +3924,10 @@ DECLARE_API(RCWCleanupList) \**********************************************************************/ DECLARE_API(FinalizeQueue) { - INIT_API(); + INIT_API_EXT(); MINIDUMP_NOT_SUPPORTED(); - BOOL bDetail = FALSE; - BOOL bAllReady = FALSE; - BOOL bShort = FALSE; - BOOL dml = FALSE; - TADDR taddrMT = 0; - - CMDOption option[] = - { // name, vptr, type, hasValue - {"-detail", &bDetail, COBOOL, FALSE}, - {"-allReady", &bAllReady, COBOOL, FALSE}, - {"-short", &bShort, COBOOL, FALSE}, - {"/d", &dml, COBOOL, FALSE}, - {"-mt", &taddrMT, COHEX, TRUE}, - }; - - if (!GetCMDOption(args, option, ARRAY_SIZE(option), NULL, 0, NULL)) - { - return Status; - } - - EnableDMLHolder dmlHolder(dml); - if (!bShort) - { - DacpSyncBlockCleanupData dsbcd; - CLRDATA_ADDRESS sbCurrent = NULL; - ULONG cleanCount = 0; - while ((dsbcd.Request(g_sos,sbCurrent) == S_OK) && dsbcd.SyncBlockPointer) - { - if (bDetail) - { - if (cleanCount == 0) // print first time only - { - ExtOut("SyncBlocks to be cleaned by the finalizer thread:\n"); - ExtOut("%" POINTERSIZE "s %" POINTERSIZE "s %" POINTERSIZE "s %" POINTERSIZE "s\n", - "SyncBlock", "RCW", "CCW", "ComClassFactory"); - } - - ExtOut("%" POINTERSIZE "p %" POINTERSIZE "p %" POINTERSIZE "p %" POINTERSIZE "p\n", - (ULONG64) dsbcd.SyncBlockPointer, - (ULONG64) dsbcd.blockRCW, - (ULONG64) dsbcd.blockCCW, - (ULONG64) dsbcd.blockClassFactory); - } - - cleanCount++; - sbCurrent = dsbcd.nextSyncBlock; - if (sbCurrent == NULL) - { - break; - } - } - - ExtOut("SyncBlocks to be cleaned up: %d\n", cleanCount); - -#ifdef FEATURE_COMINTEROP - VisitRcwArgs travArgs; - ZeroMemory(&travArgs,sizeof(VisitRcwArgs)); - travArgs.bDetail = bDetail; - g_sos->TraverseRCWCleanupList(0, (VISITRCWFORCLEANUP) VisitRcw, &travArgs); - ExtOut("Free-Threaded Interfaces to be released: %d\n", travArgs.FTMCount); - ExtOut("MTA Interfaces to be released: %d\n", travArgs.MTACount); - ExtOut("STA Interfaces to be released: %d\n", travArgs.STACount); -#endif // FEATURE_COMINTEROP - -// noRCW: - ExtOut("----------------------------------\n"); - } - - // GC Heap - DWORD dwNHeaps = GetGcHeapCount(); - - HeapStat hpStat; - - if (!IsServerBuild()) - { - DacpGcHeapDetails heapDetails; - if (heapDetails.Request(g_sos) != S_OK) - { - ExtOut("Error requesting details\n"); - return Status; - } - - GatherOneHeapFinalization(heapDetails, &hpStat, bAllReady, bShort); - } - else - { - DWORD dwAllocSize; - if (!ClrSafeInt::multiply(sizeof(CLRDATA_ADDRESS), dwNHeaps, dwAllocSize)) - { - ExtOut("Failed to get GCHeaps: integer overflow\n"); - return Status; - } - - CLRDATA_ADDRESS *heapAddrs = (CLRDATA_ADDRESS*)alloca(dwAllocSize); - if (g_sos->GetGCHeapList(dwNHeaps, heapAddrs, NULL) != S_OK) - { - ExtOut("Failed to get GCHeaps\n"); - return Status; - } - - for (DWORD n = 0; n < dwNHeaps; n ++) - { - DacpGcHeapDetails heapDetails; - if (heapDetails.Request(g_sos, heapAddrs[n]) != S_OK) - { - ExtOut("Error requesting details\n"); - return Status; - } - - ExtOut("------------------------------\n"); - ExtOut("Heap %d\n", n); - - GatherOneHeapFinalization(heapDetails, &hpStat, bAllReady, bShort); - } - } - - if (!bShort) - { - if (bAllReady) - { - PrintGCStat(&hpStat, "Statistics for all finalizable objects that are no longer rooted:\n"); - } - else - { - PrintGCStat(&hpStat, "Statistics for all finalizable objects (including all objects ready for finalization):\n"); - } - } - - return Status; + return ExecuteCommand("finalizequeue", args); } enum { @@ -9020,26 +8789,6 @@ DECLARE_API(FindRoots) ExtOut("At this time %sgcroot should be used instead.\n", SOSPrefix); return Status; } - // validate argument - if (!g_snapshot.Build()) - { - ExtOut("Unable to build snapshot of the garbage collector state\n"); - return Status; - } - - if (g_snapshot.GetHeap(taObj) == NULL) - { - ExtOut("Address %#p is not in the managed heap.\n", SOS_PTR(taObj)); - return Status; - } - - int ogen = g_snapshot.GetGeneration(taObj); - if (ogen > CNotification::GetCondemnedGen()) - { - DMLOut("Object %s will survive this collection:\n\tgen(%#p) = %d > %d = condemned generation.\n", - DMLObject(taObj), SOS_PTR(taObj), ogen, CNotification::GetCondemnedGen()); - return Status; - } std::stringstream argsBuilder; argsBuilder << "-gcgen " << CNotification::GetCondemnedGen() << " " << std::hex << taObj; diff --git a/src/SOS/Strike/util.cpp b/src/SOS/Strike/util.cpp index 768c919ca0..8ef8d8344f 100644 --- a/src/SOS/Strike/util.cpp +++ b/src/SOS/Strike/util.cpp @@ -1927,109 +1927,6 @@ BOOL TryGetMethodDescriptorForDelegate(CLRDATA_ADDRESS delegateAddr, CLRDATA_ADD return FALSE; } -void DumpStackObjectsOutput(const char *location, DWORD_PTR objAddr, BOOL verifyFields) -{ - // rule out pointers that are outside of the gc heap. - if (g_snapshot.GetHeap(objAddr) == NULL) - return; - - DacpObjectData objectData; - if (objectData.Request(g_sos, TO_CDADDR(objAddr)) != S_OK) - return; - - if (sos::IsObject(objAddr, verifyFields != FALSE) - && !sos::MethodTable::IsFreeMT(TO_TADDR(objectData.MethodTable))) - { - DMLOut("%-" POINTERSIZE "s %s ", location, DMLObject(objAddr)); - if (g_sos->GetObjectClassName(TO_CDADDR(objAddr), mdNameLen, g_mdName, NULL)==S_OK) - { - ExtOut("%S", g_mdName); - - if (IsStringObject(objAddr)) - { - ExtOut(" "); - StringObjectContent(objAddr, FALSE, 40); - } - else if (IsObjectArray(objAddr) && - (g_sos->GetMethodTableName(objectData.ElementTypeHandle, mdNameLen, g_mdName, NULL) == S_OK)) - { - ExtOut(" "); - ExtOut("(%S[])", g_mdName); - } - } - else - { - ExtOut(""); - } - ExtOut("\n"); - } -} - -void DumpStackObjectsOutput(DWORD_PTR ptr, DWORD_PTR objAddr, BOOL verifyFields) -{ - char location[64]; - sprintf_s(location, 64, "%p", (DWORD_PTR *)ptr); - - DumpStackObjectsOutput(location, objAddr, verifyFields); -} - -void DumpStackObjectsInternal(size_t StackTop, size_t StackBottom, BOOL verifyFields) -{ - for (DWORD_PTR ptr = StackTop; ptr <= StackBottom; ptr += sizeof(DWORD_PTR)) - { - if (IsInterrupt()) - return; - - DWORD_PTR objAddr; - move_xp(objAddr, ptr); - - DumpStackObjectsOutput(ptr, objAddr, verifyFields); - } -} - -void DumpRegObjectHelper(const char *regName, BOOL verifyFields) -{ - DWORD_PTR reg; -#ifdef FEATURE_PAL - if (FAILED(g_ExtRegisters->GetValueByName(regName, ®))) - return; -#else - DEBUG_VALUE value; - ULONG IREG; - if (FAILED(g_ExtRegisters->GetIndexByName(regName, &IREG)) || - FAILED(g_ExtRegisters->GetValue(IREG, &value))) - return; - -#if defined(SOS_TARGET_X86) || defined(SOS_TARGET_ARM) - reg = (DWORD_PTR) value.I32; -#elif defined(SOS_TARGET_AMD64) || defined(SOS_TARGET_ARM64) - reg = (DWORD_PTR) value.I64; -#else -#error Unsupported target -#endif -#endif // FEATURE_PAL - - DumpStackObjectsOutput(regName, reg, verifyFields); -} - -void DumpStackObjectsHelper ( - TADDR StackTop, - TADDR StackBottom, - BOOL verifyFields) -{ - ExtOut(g_targetMachine->GetDumpStackObjectsHeading()); - - LPCSTR* regs; - unsigned int cnt; - g_targetMachine->GetGCRegisters(®s, &cnt); - - for (size_t i = 0; i < cnt; ++i) - DumpRegObjectHelper(regs[i], verifyFields); - - // Make certain StackTop is dword aligned: - DumpStackObjectsInternal(StackTop & ~ALIGNCONST, StackBottom, verifyFields); -} - void AddToModuleList(DWORD_PTR * &moduleList, int &numModule, int &maxList, DWORD_PTR dwModuleAddr) { @@ -3437,24 +3334,6 @@ BOOL GetSOSVersion(VS_FIXEDFILEINFO *pFileInfo) #endif // !FEATURE_PAL -size_t ObjectSize(DWORD_PTR obj,BOOL fIsLargeObject) -{ - DWORD_PTR dwMT; - MOVE(dwMT, obj); - return ObjectSize(obj, dwMT, FALSE, fIsLargeObject); -} - -size_t ObjectSize(DWORD_PTR obj, DWORD_PTR mt, BOOL fIsValueClass, BOOL fIsLargeObject) -{ - BOOL bContainsPointers; - size_t size = 0; - if (!GetSizeEfficient(obj, mt, fIsLargeObject, size, bContainsPointers)) - { - return 0; - } - return size; -} - // This takes an array of values and sets every non-printable character // to be a period. void Flatten(__out_ecount(len) char *data, unsigned int len) @@ -4080,83 +3959,6 @@ BOOL GetGcStructuresValid() return heapData.bGcStructuresValid; } -void GetAllocContextPtrs(AllocInfo *pallocInfo) -{ - // gets the allocation contexts for all threads. This provides information about how much of - // the current allocation quantum has been allocated and the heap to which the quantum belongs. - // The allocation quantum is a fixed size chunk of zeroed memory from which allocations will come - // until it's filled. Each managed thread has its own allocation context. - - pallocInfo->num = 0; - pallocInfo->array = NULL; - - // get the thread store (See code:ClrDataAccess::RequestThreadStoreData for details) - DacpThreadStoreData ThreadStore; - if ( ThreadStore.Request(g_sos) != S_OK) - { - return; - } - - int numThread = ThreadStore.threadCount; - if (numThread) - { - pallocInfo->array = new needed_alloc_context[numThread + 1]; - if (pallocInfo->array == NULL) - { - return; - } - } - - // get details for each thread in the thread store - CLRDATA_ADDRESS CurThread = ThreadStore.firstThread; - while (CurThread != NULL) - { - if (IsInterrupt()) - return; - - DacpThreadData Thread; - // Get information about the thread (we're getting the values of several of the - // fields of the Thread instance from the target) See code:ClrDataAccess::RequestThreadData for - // details - if (Thread.Request(g_sos, CurThread) != S_OK) - { - return; - } - - if (Thread.allocContextPtr != 0) - { - // get a list of all the allocation contexts - int j; - for (j = 0; j < pallocInfo->num; j ++) - { - if (pallocInfo->array[j].alloc_ptr == (BYTE *) Thread.allocContextPtr) - break; - } - if (j == pallocInfo->num) - { - pallocInfo->num ++; - pallocInfo->array[j].alloc_ptr = (BYTE *) Thread.allocContextPtr; - pallocInfo->array[j].alloc_limit = (BYTE *) Thread.allocContextLimit; - } - } - - CurThread = Thread.nextThread; - } - - CLRDATA_ADDRESS allocPtr; - CLRDATA_ADDRESS allocLimit; - - ReleaseHolder sos12; - if (SUCCEEDED(g_sos->QueryInterface(__uuidof(ISOSDacInterface12), &sos12)) && - SUCCEEDED(sos12->GetGlobalAllocationContext(&allocPtr, &allocLimit)) && - allocPtr != 0) - { - int j = pallocInfo->num ++; - pallocInfo->array[j].alloc_ptr = (BYTE *) allocPtr; - pallocInfo->array[j].alloc_limit = (BYTE *) allocLimit; - } -} - HRESULT ReadVirtualCache::Read(TADDR address, PVOID buffer, ULONG bufferSize, PULONG lpcbBytesRead) { // address can be any random ULONG64, as it can come from VerifyObjectMember(), and this @@ -5824,88 +5626,3 @@ HRESULT GetMetadataMemory(CLRDATA_ADDRESS address, ULONG32 bufferSize, BYTE* buf } #endif // FEATURE_PAL - -/////////////////////////////////////////////////////////////////////////////////////////// -// -// Miscellaneous helper methods -// - -void EnumerateThreadPoolGlobalWorkItemConcurrentQueue( - DWORD_PTR workItemsConcurrentQueuePtr, - const char *queueName, - HeapStat *stats) -{ - // Get its head segment. - sos::Object workItemsConcurrentQueue = TO_TADDR(workItemsConcurrentQueuePtr); - int offset = GetObjFieldOffset(workItemsConcurrentQueue.GetAddress(), workItemsConcurrentQueue.GetMT(), W("_head")); - if (offset <= 0) - { - return; - } - - // Now, walk from segment to segment, each of which contains an array of work items. - DWORD_PTR segmentPtr; - MOVE(segmentPtr, workItemsConcurrentQueue.GetAddress() + offset); - while (sos::IsObject(segmentPtr, false)) - { - sos::Object segment = TO_TADDR(segmentPtr); - - // Get the work items array. It's an array of Slot structs, which starts with the T. - offset = GetObjFieldOffset(segment.GetAddress(), segment.GetMT(), W("_slots")); - if (offset <= 0) - { - break; - } - - DWORD_PTR slotsPtr; - MOVE(slotsPtr, segment.GetAddress() + offset); - if (!sos::IsObject(slotsPtr, false)) - { - break; - } - - // Walk every element in the array, outputting details on non-null work items. - DacpObjectData slotsArray; - if (slotsArray.Request(g_sos, TO_CDADDR(slotsPtr)) == S_OK && slotsArray.ObjectType == OBJ_ARRAY) - { - for (int i = 0; i < slotsArray.dwNumComponents; i++) - { - DWORD_PTR workItemPtr; - MOVE(workItemPtr, slotsArray.ArrayDataPtr + (i * slotsArray.dwComponentSize)); // the item object reference is at the beginning of the Slot - if (workItemPtr != NULL && sos::IsObject(TO_CDADDR(workItemPtr), false)) - { - sos::Object workItem = TO_TADDR(workItemPtr); - stats->Add((DWORD_PTR)workItem.GetMT(), (DWORD)workItem.GetSize()); - DMLOut("%" THREAD_POOL_WORK_ITEM_TABLE_QUEUE_WIDTH "s %s %S", queueName, DMLObject(workItem.GetAddress()), workItem.GetTypeName()); - if ((offset = GetObjFieldOffset(workItem.GetAddress(), workItem.GetMT(), W("_callback"))) > 0 || - (offset = GetObjFieldOffset(workItem.GetAddress(), workItem.GetMT(), W("m_action"))) > 0) - { - DWORD_PTR delegatePtr; - MOVE(delegatePtr, workItem.GetAddress() + offset); - CLRDATA_ADDRESS md; - if (TryGetMethodDescriptorForDelegate(TO_CDADDR(delegatePtr), &md)) - { - NameForMD_s((DWORD_PTR)md, g_mdName, mdNameLen); - ExtOut(" => %S", g_mdName); - } - } - ExtOut("\n"); - } - } - } - - // Move to the next segment. - DacpFieldDescData segmentField; - offset = GetObjFieldOffset(segment.GetAddress(), segment.GetMT(), W("_nextSegment"), TRUE, &segmentField); - if (offset <= 0) - { - break; - } - - MOVE(segmentPtr, segment.GetAddress() + offset); - if (segmentPtr == NULL) - { - break; - } - } -} diff --git a/src/SOS/Strike/util.h b/src/SOS/Strike/util.h index 2fb1eb0bea..50467dd8ad 100644 --- a/src/SOS/Strike/util.h +++ b/src/SOS/Strike/util.h @@ -262,215 +262,6 @@ class CachedString static StaticData cache; }; -class GCHeapDetails -{ -private: - void GetGenerationTableSize(CLRDATA_ADDRESS svrHeapAddr, unsigned int *count) - { - HRESULT hr = S_OK; - bool success = false; - ReleaseHolder sos8; - if (!SUCCEEDED(hr = g_sos->QueryInterface(__uuidof(ISOSDacInterface8), &sos8)) - || !SUCCEEDED(hr = sos8->GetNumberGenerations(count))) - { - // The runtime will either have the original 4 generations or implement ISOSDacInterface8 - // if the call succeeded, count is already populated. - *count = DAC_NUMBERGENERATIONS; - } - } - - // Fill the target array with either the details from heap or if this is a newer runtime that supports - // the pinned object heap (or potentially future GC generations), get that data too. This abstraction is - // necessary because the original GC heap APIs are hardcoded to 4 generations. - void FillGenerationTable(CLRDATA_ADDRESS svrHeapAddr, const DacpGcHeapDetails &heap, unsigned int count, DacpGenerationData *data) - { - HRESULT hr = S_OK; - bool success = false; - unsigned int generationCount; - ReleaseHolder sos8; - if (SUCCEEDED(hr = g_sos->QueryInterface(__uuidof(ISOSDacInterface8), &sos8))) - { - if (svrHeapAddr == NULL) - { - if (SUCCEEDED(hr = sos8->GetGenerationTable(count, data, &generationCount)) - && hr != S_FALSE) - { - success = true; - // Nothing else to do, data is already populated - } - } - else - { - if (SUCCEEDED(hr = sos8->GetGenerationTableSvr(svrHeapAddr, count, data, &generationCount)) - && hr != S_FALSE) - { - success = true; - // Nothing else to do, data is already populated - } - } - - _ASSERTE(generationCount == count || !success); - } - - if (!success) - { - // This would mean that there are additional, unaccounted for, generations - _ASSERTE(hr != S_FALSE); - - // We couldn't get any data from the newer APIs, so fall back to the original data - memcpy(data, &(heap.generation_table), sizeof(DacpGenerationData) * DAC_NUMBERGENERATIONS); - } - } - - // Fill the target array with either the details from heap or if this is a newer runtime that supports - // the pinned object heap (or potentially future GC generations), get that data too. This abstraction is - // necessary because the original GC heap APIs are hardcoded to 4 generations. - void FillFinalizationPointers(CLRDATA_ADDRESS svrHeapAddr, const DacpGcHeapDetails &heap, unsigned int count, CLRDATA_ADDRESS *data) - { - HRESULT hr = S_OK; - bool success = false; - unsigned int fillPointersCount; - ReleaseHolder sos8; - if (SUCCEEDED(hr = g_sos->QueryInterface(__uuidof(ISOSDacInterface8), &sos8))) - { - if (svrHeapAddr == NULL) - { - if (SUCCEEDED(hr = sos8->GetFinalizationFillPointers(count, data, &fillPointersCount)) - && hr != S_FALSE) - { - success = true; - // Nothing else to do, data is already populated - } - } - else - { - if (SUCCEEDED(hr = sos8->GetFinalizationFillPointersSvr(svrHeapAddr, count, data, &fillPointersCount)) - && hr != S_FALSE) - { - success = true; - // Nothing else to do, data is already populated - } - } - - _ASSERTE(fillPointersCount == count); - } - - if (!success) - { - // This would mean that there are additional, unaccounted for, generations - _ASSERTE(hr != S_FALSE); - - // We couldn't get any data from the newer APIs, so fall back to the original data - memcpy(data, &(heap.finalization_fill_pointers), sizeof(CLRDATA_ADDRESS) * (DAC_NUMBERGENERATIONS + 2)); - } - } - -public: - GCHeapDetails() - { - generation_table = NULL; - finalization_fill_pointers = NULL; - } - - GCHeapDetails(const DacpGcHeapDetails &dacGCDetails, CLRDATA_ADDRESS svrHeapAddr = NULL) - { - generation_table = NULL; - finalization_fill_pointers = NULL; - - Set(dacGCDetails, svrHeapAddr); - } - - ~GCHeapDetails() - { - if (generation_table != NULL) - { - delete[] generation_table; - generation_table = NULL; - } - - if (finalization_fill_pointers != NULL) - { - delete[] finalization_fill_pointers; - finalization_fill_pointers = NULL; - } - } - - // Due to the raw pointers, we are not a POD and have to be careful about lifetime - GCHeapDetails(const GCHeapDetails& other) = delete; - GCHeapDetails(GCHeapDetails&& other) = delete; - GCHeapDetails& operator=(const GCHeapDetails& other) = delete; - GCHeapDetails& operator=(GCHeapDetails&& other) = delete; - - void Set(const DacpGcHeapDetails dacGCDetails, CLRDATA_ADDRESS svrHeapAddr = NULL) - { - original_heap_details = dacGCDetails; - - GetGenerationTableSize(svrHeapAddr, &num_generations); - // Either we're pre POH and have 4, or post and have 5. If there's a different - // number it's either a bug or we need to update SOS. - _ASSERTE(num_generations == 4 || num_generations == 5); - has_poh = num_generations > 4; - - if (generation_table != NULL) - { - delete[] generation_table; - } - generation_table = new DacpGenerationData[num_generations]; - FillGenerationTable(svrHeapAddr, dacGCDetails, num_generations, generation_table); - - if (finalization_fill_pointers != NULL) - { - delete[] finalization_fill_pointers; - } - - unsigned int num_fill_pointers = num_generations + 2; - finalization_fill_pointers = new CLRDATA_ADDRESS[num_fill_pointers]; - FillFinalizationPointers(svrHeapAddr, dacGCDetails, num_fill_pointers, finalization_fill_pointers); - - heapAddr = svrHeapAddr; - alloc_allocated = dacGCDetails.alloc_allocated; - mark_array = dacGCDetails.mark_array; - current_c_gc_state = dacGCDetails.current_c_gc_state; - next_sweep_obj = dacGCDetails.next_sweep_obj; - saved_sweep_ephemeral_seg = dacGCDetails.saved_sweep_ephemeral_seg; - saved_sweep_ephemeral_start = dacGCDetails.saved_sweep_ephemeral_start; - background_saved_lowest_address = dacGCDetails.background_saved_lowest_address; - background_saved_highest_address = dacGCDetails.background_saved_highest_address; - ephemeral_heap_segment = dacGCDetails.ephemeral_heap_segment; - lowest_address = dacGCDetails.lowest_address; - highest_address = dacGCDetails.highest_address; - card_table = dacGCDetails.card_table; - has_regions = generation_table[0].start_segment != generation_table[1].start_segment; - has_background_gc = dacGCDetails.mark_array != -1; - } - - DacpGcHeapDetails original_heap_details; - bool has_poh; - bool has_regions; - bool has_background_gc; - CLRDATA_ADDRESS heapAddr; // Only filled in in server mode, otherwise NULL - CLRDATA_ADDRESS alloc_allocated; - - CLRDATA_ADDRESS mark_array; - CLRDATA_ADDRESS current_c_gc_state; - CLRDATA_ADDRESS next_sweep_obj; - CLRDATA_ADDRESS saved_sweep_ephemeral_seg; - CLRDATA_ADDRESS saved_sweep_ephemeral_start; - CLRDATA_ADDRESS background_saved_lowest_address; - CLRDATA_ADDRESS background_saved_highest_address; - - // There are num_generations entries in generation_table and num_generations + 3 entries - // in finalization_fill_pointers - unsigned int num_generations; - DacpGenerationData *generation_table; - CLRDATA_ADDRESS ephemeral_heap_segment; - CLRDATA_ADDRESS *finalization_fill_pointers; - CLRDATA_ADDRESS lowest_address; - CLRDATA_ADDRESS highest_address; - CLRDATA_ADDRESS card_table; - -}; - // Things in this namespace should not be directly accessed/called outside of // the output-related functions. namespace Output @@ -1915,33 +1706,6 @@ struct DumpArrayFlags HRESULT GetMTOfObject(TADDR obj, TADDR *mt); -struct needed_alloc_context -{ - BYTE* alloc_ptr; // starting point for next allocation - BYTE* alloc_limit; // ending point for allocation region/quantum -}; - -struct AllocInfo -{ - needed_alloc_context *array; - int num; // number of allocation contexts in array - - AllocInfo() - : array(NULL) - , num(0) - {} - void Init() - { - extern void GetAllocContextPtrs(AllocInfo *pallocInfo); - GetAllocContextPtrs(this); - } - ~AllocInfo() - { - if (array != NULL) - delete[] array; - } -}; - struct GCHandleStatistics { HeapStat hs; @@ -1968,47 +1732,6 @@ struct GCHandleStatistics } }; -struct SegmentLookup -{ - DacpHeapSegmentData *m_segments; - int m_iSegmentsSize; - int m_iSegmentCount; - - SegmentLookup(); - ~SegmentLookup(); - - void Clear(); - BOOL AddSegment(DacpHeapSegmentData *pData); - CLRDATA_ADDRESS GetHeap(CLRDATA_ADDRESS object, BOOL& bFound); -}; - -class GCHeapSnapshot -{ -private: - BOOL m_isBuilt; - GCHeapDetails *m_heapDetails; - DacpGcHeapData m_gcheap; - SegmentLookup m_segments; - - BOOL AddSegments(const GCHeapDetails& details); -public: - GCHeapSnapshot(); - - BOOL Build(); - void Clear(); - BOOL IsBuilt() { return m_isBuilt; } - - DacpGcHeapData *GetHeapData() { return &m_gcheap; } - - int GetHeapCount() { return m_gcheap.HeapCount; } - - GCHeapDetails *GetHeap(CLRDATA_ADDRESS objectPointer); - int GetGeneration(CLRDATA_ADDRESS objectPointer); - - -}; -extern GCHeapSnapshot g_snapshot; - BOOL IsSameModuleName (const char *str1, const char *str2); BOOL IsModule (DWORD_PTR moduleAddr); BOOL IsMethodDesc (DWORD_PTR value); @@ -2050,33 +1773,10 @@ struct strobjInfo DWORD m_StringLength; }; -// Just to make figuring out which fill pointer element matches a generation -// a bit less confusing. This gen_segment function is ported from gc.cpp. -inline unsigned int gen_segment (int gen) -{ - return (DAC_NUMBERGENERATIONS - gen - 1); -} - -inline CLRDATA_ADDRESS SegQueue(DacpGcHeapDetails& heapDetails, int seg) -{ - return heapDetails.finalization_fill_pointers[seg - 1]; -} - -inline CLRDATA_ADDRESS SegQueueLimit(DacpGcHeapDetails& heapDetails, int seg) -{ - return heapDetails.finalization_fill_pointers[seg]; -} - -#define FinalizerListSeg (DAC_NUMBERGENERATIONS+1) -#define CriticalFinalizerListSeg (DAC_NUMBERGENERATIONS) - -void GatherOneHeapFinalization(DacpGcHeapDetails& heapDetails, HeapStat *stat, BOOL bAllReady, BOOL bShort); - CLRDATA_ADDRESS GetAppDomainForMT(CLRDATA_ADDRESS mtPtr); CLRDATA_ADDRESS GetAppDomain(CLRDATA_ADDRESS objPtr); BOOL IsMTForFreeObj(DWORD_PTR pMT); -void DumpStackObjectsHelper (TADDR StackTop, TADDR StackBottom, BOOL verifyFields); HRESULT ExecuteCommand(PCSTR commandName, PCSTR args); @@ -2102,7 +1802,6 @@ void DumpMDInfoFromMethodDescData(DacpMethodDescData * pMethodDescData, BOOL fSt void GetDomainList(DWORD_PTR *&domainList, int &numDomain); HRESULT GetThreadList(DWORD_PTR **threadList, int *numThread); CLRDATA_ADDRESS GetCurrentManagedThread(); // returns current managed thread if any -void GetAllocContextPtrs(AllocInfo *pallocInfo); void ReloadSymbolWithLineInfo(); @@ -2122,10 +1821,6 @@ BOOL GetSizeEfficient(DWORD_PTR dwAddrCurrObj, BOOL GetCollectibleDataEfficient(DWORD_PTR dwAddrMethTable, BOOL& bCollectible, TADDR& loaderAllocatorObjectHandle); -// ObjSize now uses the methodtable cache for its work too. -size_t ObjectSize (DWORD_PTR obj, BOOL fIsLargeObject=FALSE); -size_t ObjectSize(DWORD_PTR obj, DWORD_PTR mt, BOOL fIsValueClass, BOOL fIsLargeObject=FALSE); - void CharArrayContent(TADDR pos, ULONG num, bool widechar); void StringObjectContent (size_t obj, BOOL fLiteral=FALSE, const int length=-1); // length=-1: dump everything in the string object. @@ -2906,15 +2601,4 @@ class InternalFrameManager }; #include "sigparser.h" -/////////////////////////////////////////////////////////////////////////////////////////// -// -// Miscellaneous helper methods -// - -#define THREAD_POOL_WORK_ITEM_TABLE_QUEUE_WIDTH "17" -void EnumerateThreadPoolGlobalWorkItemConcurrentQueue( - DWORD_PTR workItemsConcurrentQueuePtr, - const char *queueName, - HeapStat *stats); - #endif // __util_h__ diff --git a/src/SOS/lldbplugin/soscommand.cpp b/src/SOS/lldbplugin/soscommand.cpp index 2185778304..7f79ec8bcb 100644 --- a/src/SOS/lldbplugin/soscommand.cpp +++ b/src/SOS/lldbplugin/soscommand.cpp @@ -181,14 +181,14 @@ sosCommandInitialize(lldb::SBDebugger debugger) g_services->AddCommand("dumpsig", new sosCommand("DumpSig"), "Dumps the signature of a method or field specified by ' '."); g_services->AddCommand("dumpsigelem", new sosCommand("DumpSigElem"), "Dumps a single element of a signature object."); g_services->AddCommand("dumpstack", new sosCommand("DumpStack"), "Displays a native and managed stack trace."); - g_services->AddCommand("dumpstackobjects", new sosCommand("DumpStackObjects"), "Displays all managed objects found within the bounds of the current stack."); - g_services->AddCommand("dso", new sosCommand("DumpStackObjects"), "Displays all managed objects found within the bounds of the current stack."); + g_services->AddManagedCommand("dumpstackobjects", "Displays all managed objects found within the bounds of the current stack."); + g_services->AddManagedCommand("dso", "Displays all managed objects found within the bounds of the current stack."); g_services->AddCommand("dumpvc", new sosCommand("DumpVC"), "Displays info about the fields of a value class."); g_services->AddManagedCommand("eeheap", "Displays info about process memory consumed by internal runtime data structures."); g_services->AddCommand("eestack", new sosCommand("EEStack"), "Runs dumpstack on all threads in the process."); g_services->AddCommand("eeversion", new sosCommand("EEVersion"), "Displays information about the runtime and SOS versions."); g_services->AddCommand("ehinfo", new sosCommand("EHInfo"), "Displays the exception handling blocks in a JIT-ed method."); - g_services->AddCommand("finalizequeue", new sosCommand("FinalizeQueue"), "Displays all objects registered for finalization."); + g_services->AddManagedCommand("finalizequeue", "Displays all objects registered for finalization."); g_services->AddCommand("findappdomain", new sosCommand("FindAppDomain"), "Attempts to resolve the AppDomain of a GC object."); g_services->AddCommand("findroots", new sosCommand("FindRoots"), "Finds and displays object roots across GC collections."); g_services->AddCommand("gchandles", new sosCommand("GCHandles"), "Displays statistics about garbage collector handles in the process."); From 90166b550f2175163aeab99184b58e0d7b9b9c7a Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Tue, 25 Apr 2023 13:33:50 +0000 Subject: [PATCH 033/111] Update dependencies from https://github.com/dotnet/source-build-reference-packages build 20230424.3 (#3851) [main] Update dependencies from dotnet/source-build-reference-packages --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 53bdf10a6d..16956df0d9 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -47,9 +47,9 @@ https://github.com/dotnet/runtime a64420c79cb63c485138f4f1352b8730f27d7b19 - + https://github.com/dotnet/source-build-reference-packages - 453ab23d599ac904ded70bd9194959a76b05702f + 0f1fa8fe854598ec1fb6976cc553e8ee7ebbdd09 diff --git a/eng/Versions.props b/eng/Versions.props index 36b9b10965..eb33dfa2c3 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -66,7 +66,7 @@ 7.0.0-beta.22316.2 10.0.18362 13.0.1 - 8.0.0-alpha.1.23221.1 + 8.0.0-alpha.1.23224.3 1.2.0-beta-23165-02 From ef74d449a2aa27e45417928e448417183afbc5e0 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Tue, 25 Apr 2023 18:25:14 +0000 Subject: [PATCH 034/111] Update dependencies from https://github.com/dotnet/symstore build 20230424.1 (#3850) [main] Update dependencies from dotnet/symstore --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 16956df0d9..8f9546a176 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -1,8 +1,8 @@ - + https://github.com/dotnet/symstore - cfbac6b5f6f9a628e89dbd38c074cbd41665820e + 219e980f2eb48497d727d9fa86892ea54fff4fbb https://github.com/microsoft/clrmd diff --git a/eng/Versions.props b/eng/Versions.props index eb33dfa2c3..81c6c1ce3f 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -16,7 +16,7 @@ - 1.0.421801 + 1.0.422401 8.0.0-preview.3.23155.1 8.0.0-preview.3.23155.1 From 90f96ce56246e1c379874bc6d243673d68b7af73 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Wed, 26 Apr 2023 13:46:31 +0000 Subject: [PATCH 035/111] Update dependencies from https://github.com/dotnet/source-build-reference-packages build 20230425.2 (#3854) [main] Update dependencies from dotnet/source-build-reference-packages --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 8f9546a176..73323ab041 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -47,9 +47,9 @@ https://github.com/dotnet/runtime a64420c79cb63c485138f4f1352b8730f27d7b19 - + https://github.com/dotnet/source-build-reference-packages - 0f1fa8fe854598ec1fb6976cc553e8ee7ebbdd09 + 4bf273ec25cc3983d6a5991cf0a4aa082cb255a5 diff --git a/eng/Versions.props b/eng/Versions.props index 81c6c1ce3f..0d42902a28 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -66,7 +66,7 @@ 7.0.0-beta.22316.2 10.0.18362 13.0.1 - 8.0.0-alpha.1.23224.3 + 8.0.0-alpha.1.23225.2 1.2.0-beta-23165-02 From 7c736bdc68e2128c6dfb8c7d0cf855a9529b87cd Mon Sep 17 00:00:00 2001 From: Adeel Mujahid <3840695+am11@users.noreply.github.com> Date: Wed, 26 Apr 2023 22:17:34 +0300 Subject: [PATCH 036/111] Improve lldb discovery for tests (#3855) --- eng/build.sh | 40 ++++++++++++++++++++++++++++------------ 1 file changed, 28 insertions(+), 12 deletions(-) diff --git a/eng/build.sh b/eng/build.sh index 08fa93f245..92bef5bea0 100755 --- a/eng/build.sh +++ b/eng/build.sh @@ -251,19 +251,35 @@ fi if [[ "$__Test" == 1 ]]; then if [[ "$__CrossBuild" == 0 ]]; then if [[ -z "$LLDB_PATH" ]]; then - export LLDB_PATH="$(which lldb-3.9.1 2> /dev/null)" - if [[ -z "$LLDB_PATH" ]]; then - export LLDB_PATH="$(which lldb-3.9 2> /dev/null)" - if [[ -z "$LLDB_PATH" ]]; then - export LLDB_PATH="$(which lldb-4.0 2> /dev/null)" - if [[ -z "$LLDB_PATH" ]]; then - export LLDB_PATH="$(which lldb-5.0 2> /dev/null)" - if [[ -z "$LLDB_PATH" ]]; then - export LLDB_PATH="$(which lldb 2> /dev/null)" - fi - fi - fi + check_version_exists() { + desired_version=-1 + + # Set up the environment to be used for building with the desired debugger. + if command -v "lldb-$1.$2" > /dev/null; then + desired_version="-$1.$2" + elif command -v "lldb$1$2" > /dev/null; then + desired_version="$1$2" + elif command -v "lldb-$1$2" > /dev/null; then + desired_version="-$1$2" fi + + echo "$desired_version" + } + + # note: clang versions higher than 6 do not have minor version in file name, if it is zero. + versions="16 15 14 13 12 11 10 9 8 7 6.0 5.0 4.0 3.9" + for version in $versions; do + _major="${version%%.*}" + [ -z "${version##*.*}" ] && _minor="${version#*.}" + desired_version="$(check_version_exists "$_major" "$_minor")" + if [ "$desired_version" != "-1" ]; then majorVersion="$_major"; break; fi + done + + if [ -z "$majorVersion" ]; then + export LLDB_PATH="$(command -v "lldb")" + else + export LLDB_PATH="$(command -v "lldb$desired_version")" + fi fi if [[ -z "$GDB_PATH" ]]; then From c31c5c846a83bd2b61153b9629deb6730f1817a3 Mon Sep 17 00:00:00 2001 From: Adeel Mujahid <3840695+am11@users.noreply.github.com> Date: Thu, 27 Apr 2023 00:20:51 +0300 Subject: [PATCH 037/111] Update docker images to latest tags (#3535) * Update docker images to latest tags * Make the CentOS7 builds temporarily build only. * Add buildAndSkipTest. Remove _BuildOnly; it didn't do what it was named --------- Co-authored-by: Mike McLaughlin --- diagnostics.yml | 39 ++++++++++-------------------- eng/build.yml | 2 +- eng/cibuild.sh | 31 +----------------------- src/SOS/SOS.UnitTests/SOSRunner.cs | 3 ++- 4 files changed, 17 insertions(+), 58 deletions(-) diff --git a/diagnostics.yml b/diagnostics.yml index a3c2164984..df452f23b1 100644 --- a/diagnostics.yml +++ b/diagnostics.yml @@ -112,12 +112,10 @@ stages: _PublishArtifacts: bin/Windows_NT.x86.Release ${{ if ne(variables['System.TeamProject'], 'public') }}: Build_Release_arm: - _BuildOnly: true _BuildConfig: Release _BuildArch: arm _PublishArtifacts: bin/Windows_NT.arm.Release Build_Release_arm64: - _BuildOnly: true _BuildConfig: Release _BuildArch: arm64 _PublishArtifacts: bin/Windows_NT.arm64.Release @@ -126,7 +124,9 @@ stages: parameters: name: CentOS_7 osGroup: Linux - dockerImage: mcr.microsoft.com/dotnet-buildtools/prereqs:centos-7-3e800f1-20190501005343 + dockerImage: mcr.microsoft.com/dotnet-buildtools/prereqs:centos-7 + requiresCapPtraceContainer: true + buildAndSkipTest: true strategy: matrix: Build_Debug: @@ -142,7 +142,7 @@ stages: parameters: name: Alpine3_13 osGroup: Linux - dockerImage: mcr.microsoft.com/dotnet-buildtools/prereqs:alpine-3.13-WithNode-20210910135845-c401c85 + dockerImage: mcr.microsoft.com/dotnet-buildtools/prereqs:alpine-3.13-WithNode artifactsTargetPath: bin/Linux-musl.x64.Release requiresCapPtraceContainer: true strategy: @@ -193,7 +193,7 @@ stages: parameters: name: Linux_arm osGroup: Linux - dockerImage: mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-16.04-cross-20210719121212-8a8d3be + dockerImage: mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-18.04-cross crossrootfsDir: '/crossrootfs/arm' buildAndSkipTest: true strategy: @@ -207,7 +207,7 @@ stages: parameters: name: Linux_arm64 osGroup: Linux - dockerImage: mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-16.04-cross-arm64-20210719121212-8a8d3be + dockerImage: mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-18.04-cross-arm64 crossrootfsDir: '/crossrootfs/arm64' buildAndSkipTest: true strategy: @@ -221,7 +221,7 @@ stages: parameters: name: Linux_musl_arm osGroup: Linux - dockerImage: mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-16.04-cross-arm-alpine-20210923140502-78f7860 + dockerImage: mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-18.04-cross-arm-alpine crossrootfsDir: '/crossrootfs/arm' artifactsTargetPath: bin/Linux-musl.arm.Release buildAndSkipTest: true @@ -236,7 +236,7 @@ stages: parameters: name: Linux_musl_arm64 osGroup: Linux - dockerImage: mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-16.04-cross-arm64-alpine-20210923140502-78f7860 + dockerImage: mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-18.04-cross-arm64-alpine crossrootfsDir: '/crossrootfs/arm64' artifactsTargetPath: bin/Linux-musl.arm64.Release buildAndSkipTest: true @@ -255,9 +255,9 @@ stages: - template: /eng/build.yml parameters: - name: Debian_Stretch + name: Debian_Bullseye osGroup: Linux - dockerImage: mcr.microsoft.com/dotnet-buildtools/prereqs:debian-stretch-3e800f1-20190521154431 + dockerImage: mcr.microsoft.com/dotnet-buildtools/prereqs:debian-11-amd64 dependsOn: CentOS_7 testOnly: true strategy: @@ -270,7 +270,7 @@ stages: # parameters: # name: Fedora_34 # osGroup: Linux -# dockerImage: mcr.microsoft.com/dotnet-buildtools/prereqs:fedora-34-helix-20220331150839-4f64125 +# dockerImage: mcr.microsoft.com/dotnet-buildtools/prereqs:fedora-34-helix # dependsOn: CentOS_7 # testOnly: true # requiresCapPtraceContainer: true @@ -284,7 +284,7 @@ stages: # parameters: # name: OpenSuse_15_2 # osGroup: Linux -# dockerImage: mcr.microsoft.com/dotnet-buildtools/prereqs:opensuse-15.2-helix-amd64-20211018152525-9cc02fe +# dockerImage: mcr.microsoft.com/dotnet-buildtools/prereqs:opensuse-15.2-helix-amd64 # dependsOn: CentOS_7 # testOnly: true # strategy: @@ -293,24 +293,11 @@ stages: # _BuildConfig: Debug # _BuildArch: x64 - - template: /eng/build.yml - parameters: - name: Ubuntu_16_04 - osGroup: Linux - dockerImage: mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-16.04-09ca40b-20190520220842 - dependsOn: CentOS_7 - testOnly: true - strategy: - matrix: - Build_Debug: - _BuildConfig: Debug - _BuildArch: x64 - - template: /eng/build.yml parameters: name: Ubuntu_18_04 osGroup: Linux - dockerImage: mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-18.04-3e800f1-20190508143252 + dockerImage: mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-18.04 dependsOn: CentOS_7 testOnly: true strategy: diff --git a/eng/build.yml b/eng/build.yml index c566410d80..6115437680 100644 --- a/eng/build.yml +++ b/eng/build.yml @@ -243,4 +243,4 @@ jobs: mergeTestResults: true buildConfiguration: ${{ parameters.name }} continueOnError: true - condition: ne(variables['_BuildOnly'], 'true') + condition: always() diff --git a/eng/cibuild.sh b/eng/cibuild.sh index ffc534ba0a..cb0000ebc1 100755 --- a/eng/cibuild.sh +++ b/eng/cibuild.sh @@ -9,7 +9,7 @@ while [[ -h $source ]]; do scriptroot="$( cd -P "$( dirname "$source" )" && pwd )" source="$(readlink "$source")" - # if $source was a relative symlink, we need to resolve it relative to the path where + # if $source was a relative symlink, we need to resolve it relative to the path where # the symlink file was located [[ $source != /* ]] && source="$scriptroot/$source" done @@ -35,35 +35,6 @@ if [ "$__osname" == "Linux" ]; then source scl_source enable python27 devtoolset-2 fi fi - - # We are using old (2019) centos image in the CI with old cmake (2.8). - # Upgrading to 2021 centos image was failing SOS tests which rely on - # lldb REPL and ptrace etc. e.g. from test attachment logs: - # - # 00:00.136: error: process launch failed: 'A' packet returned an error: 8 - # 00:00.136: - # 00:00.136: - #System.Exception: 'process launch -s' FAILED - # - # so we will keep using old image for now and install newer cmake as a workaround instead.. - # FIXME: delete this comment and the next `if` block once centos image is upgraded. - if [ "$ID" = "centos" ]; then - # upgrade cmake - requiredversion=3.6.2 - cmakeversion="$(cmake --version | head -1)" - currentversion="${cmakeversion##* }" - if ! printf '%s\n' "$requiredversion" "$currentversion" | sort --version-sort --check 2>/dev/null; then - echo "Old cmake version found: $currentversion, minimal requirement is $requiredversion. Upgrading to 3.15.5 .." - curl -sSL -o /tmp/cmake-install.sh https://github.com/Kitware/CMake/releases/download/v3.15.5/cmake-3.15.5-Linux-$(uname -m).sh - mkdir "$HOME/.cmake" - bash /tmp/cmake-install.sh --skip-license --exclude-subdir --prefix="$HOME/.cmake" - PATH="$HOME/.cmake/bin:$PATH" - export PATH - cmakeversion="$(cmake --version | head -1)" - newversion="${cmakeversion##* }" - echo "New cmake version is: $newversion" - fi - fi fi "$scriptroot/build.sh" -restore -prepareMachine -ci $@ diff --git a/src/SOS/SOS.UnitTests/SOSRunner.cs b/src/SOS/SOS.UnitTests/SOSRunner.cs index 98366fb0d0..800b492b38 100644 --- a/src/SOS/SOS.UnitTests/SOSRunner.cs +++ b/src/SOS/SOS.UnitTests/SOSRunner.cs @@ -564,7 +564,8 @@ public static async Task StartDebugger(TestInformation information, D { throw new ArgumentException("LLDB helper script path not set or does not exist: " + lldbHelperScript); } - arguments.AppendFormat(@"--no-lldbinit -o ""settings set interpreter.prompt-on-quit false"" -o ""command script import {0}"" -o ""version""", lldbHelperScript); + arguments.Append(@"--no-lldbinit -o ""settings set target.disable-aslr false"" -o ""settings set interpreter.prompt-on-quit false"""); + arguments.AppendFormat(@" -o ""command script import {0}"" -o ""version""", lldbHelperScript); string debuggeeTarget = config.HostExe; if (string.IsNullOrWhiteSpace(debuggeeTarget)) From f65f0d3efff869fbe9193be4d335abd2beae7197 Mon Sep 17 00:00:00 2001 From: Lee Culver Date: Wed, 26 Apr 2023 15:39:06 -0700 Subject: [PATCH 038/111] Fit and Finish: Clean up SOS command table output (#3852) * Initial version of Table * Update !dumpheap * Update DumpObjGCRefsHelper.cs * Update !dumpruntimetypes * Fix dml escape issue * Update !dso * Update !eeheap * Update !fq * Fix truncation for types * Update FindEphemeralReferencesToLOHCommand.cs * Update !lno * Update !findpointersin * Add BorderedTable * Update !ephrefs * Update !sos GCHeapStat * Update !gcroot * Update GCToNative * Update GCWhere * Update maddress * Update SizeStatsCommand.cs * Update !vh * Update !threadpool * Add a reason to !verifyheap * Remove debug code * Dml cleanup * Remove DumpHeapSegment * Update comments * Fix test whitespace dependency * Revert previous test behavior, change !dumpheap * Ignore whitespace * One last fix? * Code review feedback --- .../DumpHeapService.cs | 53 +-- .../DumpObjGCRefsHelper.cs | 26 +- .../DumpRuntimeTypeCommand.cs | 26 +- .../DumpStackObjectsCommand.cs | 10 +- .../EEHeapCommand.cs | 54 +-- .../FinalizeQueueCommand.cs | 14 +- .../FindEphemeralReferencesToLOHCommand.cs | 25 +- .../FindPointersInCommand.cs | 13 +- .../FindReferencesToEphemeralCommand.cs | 9 +- .../GCHeapStatCommand.cs | 43 ++- .../GCRootCommand.cs | 11 +- .../GCToNativeCommand.cs | 82 ++--- .../GCWhereCommand.cs | 40 +-- .../ListNearObjCommand.cs | 49 ++- .../MAddressCommand.cs | 81 ++--- .../Output/Align.cs | 12 + .../Output/BorderedTable.cs | 125 +++++++ .../Output/Column.cs | 80 +++++ .../Output/ColumnKind.cs | 112 +++++++ .../Output/Dml.cs | 306 +++++++++++++++++ .../Output/DmlFormat.cs | 36 ++ .../Output/Format.cs | 130 ++++++++ .../Output/Formats.cs | 244 ++++++++++++++ .../Output/StringBuilderPool.cs | 45 +++ .../Output/Table.cs | 240 ++++++++++++++ .../SimulateGCHeapCorruption.cs | 21 +- .../SizeStatsCommand.cs | 20 +- .../TableOutput.cs | 311 ------------------ .../ThreadPoolCommand.cs | 38 ++- .../VerifyHeapCommand.cs | 58 +--- .../VerifyObjectCommand.cs | 15 +- .../ConsoleServiceFromDebuggerServices.cs | 13 +- .../Scripts/ConcurrentDictionaries.script | 10 +- 33 files changed, 1697 insertions(+), 655 deletions(-) create mode 100644 src/Microsoft.Diagnostics.ExtensionCommands/Output/Align.cs create mode 100644 src/Microsoft.Diagnostics.ExtensionCommands/Output/BorderedTable.cs create mode 100644 src/Microsoft.Diagnostics.ExtensionCommands/Output/Column.cs create mode 100644 src/Microsoft.Diagnostics.ExtensionCommands/Output/ColumnKind.cs create mode 100644 src/Microsoft.Diagnostics.ExtensionCommands/Output/Dml.cs create mode 100644 src/Microsoft.Diagnostics.ExtensionCommands/Output/DmlFormat.cs create mode 100644 src/Microsoft.Diagnostics.ExtensionCommands/Output/Format.cs create mode 100644 src/Microsoft.Diagnostics.ExtensionCommands/Output/Formats.cs create mode 100644 src/Microsoft.Diagnostics.ExtensionCommands/Output/StringBuilderPool.cs create mode 100644 src/Microsoft.Diagnostics.ExtensionCommands/Output/Table.cs delete mode 100644 src/Microsoft.Diagnostics.ExtensionCommands/TableOutput.cs diff --git a/src/Microsoft.Diagnostics.ExtensionCommands/DumpHeapService.cs b/src/Microsoft.Diagnostics.ExtensionCommands/DumpHeapService.cs index 3fddb73587..d4587697d6 100644 --- a/src/Microsoft.Diagnostics.ExtensionCommands/DumpHeapService.cs +++ b/src/Microsoft.Diagnostics.ExtensionCommands/DumpHeapService.cs @@ -6,8 +6,8 @@ using System.Diagnostics; using System.Linq; using Microsoft.Diagnostics.DebugServices; +using Microsoft.Diagnostics.ExtensionCommands.Output; using Microsoft.Diagnostics.Runtime; -using static Microsoft.Diagnostics.ExtensionCommands.TableOutput; namespace Microsoft.Diagnostics.ExtensionCommands { @@ -41,12 +41,14 @@ public void PrintHeap(IEnumerable objects, DisplayKind displayKind, b Dictionary<(string String, ulong Size), uint> stringTable = null; Dictionary stats = new(); - TableOutput thinLockOutput = null; - TableOutput objectTable = null; + Table thinLockOutput = null; + Table objectTable = null; ClrObject lastFreeObject = default; foreach (ClrObject obj in objects) { + Console.CancellationToken.ThrowIfCancellationRequested(); + if (displayKind == DisplayKind.ThinLock) { ClrThinLock thinLock = obj.GetThinLock(); @@ -54,11 +56,11 @@ public void PrintHeap(IEnumerable objects, DisplayKind displayKind, b { if (thinLockOutput is null) { - thinLockOutput = new(Console, (12, "x"), (16, "x"), (16, "x"), (10, "n0")); - thinLockOutput.WriteRow("Object", "Thread", "OSId", "Recursion"); + thinLockOutput = new(Console, ColumnKind.DumpObj, ColumnKind.Pointer, ColumnKind.HexValue, ColumnKind.Integer); + thinLockOutput.WriteHeader("Object", "Thread", "OSId", "Recursion"); } - thinLockOutput.WriteRow(new DmlDumpObj(obj), thinLock.Thread?.Address ?? 0, thinLock.Thread?.OSThreadId ?? 0, thinLock.Recursion); + thinLockOutput.WriteRow(obj, thinLock.Thread, thinLock.Thread?.OSThreadId ?? 0, thinLock.Recursion); } continue; @@ -75,14 +77,14 @@ public void PrintHeap(IEnumerable objects, DisplayKind displayKind, b { if (objectTable is null) { - objectTable = new(Console, (12, "x12"), (12, "x12"), (12, ""), (0, "")); + objectTable = new(Console, ColumnKind.DumpObj, ColumnKind.DumpHeap, ColumnKind.ByteCount, ColumnKind.Text); if (displayKind is DisplayKind.Normal or DisplayKind.Strings) { - objectTable.WriteRow("Address", "MT", "Size"); + objectTable.WriteHeader("Address", "MT", "Size"); } } - objectTable.WriteRow(new DmlDumpObj(obj), new DmlDumpHeap(obj.Type?.MethodTable ?? 0), size, obj.IsFree ? "Free" : ""); + objectTable.WriteRow(obj, obj.Type, obj.IsValid ? size : null, obj.IsFree ? "Free" : ""); } if (printFragmentation) @@ -175,7 +177,7 @@ public void PrintHeap(IEnumerable objects, DisplayKind displayKind, b } Console.WriteLine("Statistics:"); - TableOutput statsTable = new(Console, (countLen, "n0"), (sizeLen, "n0"), (0, "")); + Table statsTable = new(Console, ColumnKind.Integer, ColumnKind.ByteCount, ColumnKind.Text); var stringsSorted = from item in stringTable let Count = item.Value @@ -191,6 +193,8 @@ orderby TotalSize foreach (var item in stringsSorted) { + Console.CancellationToken.ThrowIfCancellationRequested(); + statsTable.WriteRow(item.Count, item.TotalSize, item.String); } } @@ -206,16 +210,17 @@ orderby TotalSize Console.WriteLine(); } - int countLen = stats.Values.Max(ts => ts.Count).ToString("n0").Length; - countLen = Math.Max(countLen, "Count".Length); + Console.WriteLine("Statistics:"); - int sizeLen = stats.Values.Max(ts => ts.Size).ToString("n0").Length; - sizeLen = Math.Max(sizeLen, "TotalSize".Length); + Column countColumn = ColumnKind.Integer; + countColumn = countColumn.GetAppropriateWidth(stats.Values.Select(ts => ts.Count)); - TableOutput statsTable = new(Console, (12, "x12"), (countLen, "n0"), (sizeLen, "n0"), (0, "")); + Column sizeColumn = ColumnKind.ByteCount; + sizeColumn = sizeColumn.GetAppropriateWidth(stats.Values.Select(ts => ts.Size)); - Console.WriteLine("Statistics:"); - statsTable.WriteRow("MT", "Count", "TotalSize", "Class Name"); + Column methodTableColumn = ColumnKind.DumpHeap.GetAppropriateWidth(stats.Keys); + Table statsTable = new(Console, methodTableColumn, countColumn, sizeColumn, ColumnKind.TypeName); + statsTable.WriteHeader("MT", "Count", "TotalSize", "Class Name"); var statsSorted = from item in stats let MethodTable = item.Key @@ -230,7 +235,9 @@ orderby Size foreach (var item in statsSorted) { - statsTable.WriteRow(new DmlDumpHeap(item.MethodTable), item.Count, item.Size, item.TypeName); + Console.CancellationToken.ThrowIfCancellationRequested(); + + statsTable.WriteRow(item.MethodTable, item.Count, item.Size, item.TypeName); } Console.WriteLine($"Total {stats.Values.Sum(r => r.Count):n0} objects, {stats.Values.Sum(r => (long)r.Size):n0} bytes"); @@ -248,15 +255,17 @@ private void PrintFragmentation(List<(ClrObject Free, ClrObject Next)> fragmenta return; } - TableOutput output = new(Console, (16, "x12"), (12, "n0"), (16, "x12")); - Console.WriteLine(); Console.WriteLine("Fragmented blocks larger than 0.5 MB:"); - output.WriteRow("Address", "Size", "Followed By"); + + Table output = new(Console, ColumnKind.ListNearObj, ColumnKind.ByteCount, ColumnKind.DumpObj, ColumnKind.TypeName); + output.WriteHeader("Address", "Size", "Followed By"); foreach ((ClrObject free, ClrObject next) in fragmentation) { - output.WriteRow(free.Address, free.Size, new DmlDumpObj(next.Address), next.Type?.Name ?? ""); + Console.CancellationToken.ThrowIfCancellationRequested(); + + output.WriteRow(free.Address, free.Size, next.Address, next.Type); } } diff --git a/src/Microsoft.Diagnostics.ExtensionCommands/DumpObjGCRefsHelper.cs b/src/Microsoft.Diagnostics.ExtensionCommands/DumpObjGCRefsHelper.cs index fb81fa121c..adae249ab2 100644 --- a/src/Microsoft.Diagnostics.ExtensionCommands/DumpObjGCRefsHelper.cs +++ b/src/Microsoft.Diagnostics.ExtensionCommands/DumpObjGCRefsHelper.cs @@ -5,14 +5,16 @@ using System.Linq; using System.Text; using Microsoft.Diagnostics.DebugServices; +using Microsoft.Diagnostics.ExtensionCommands.Output; using Microsoft.Diagnostics.Runtime; -using static Microsoft.Diagnostics.ExtensionCommands.TableOutput; namespace Microsoft.Diagnostics.ExtensionCommands { [Command(Name = "dumpobjgcrefs", Help = "A helper command to implement !dumpobj -refs")] public sealed class DumpObjGCRefsHelper : CommandBase { + private readonly StringBuilderPool _stringBuilderPool = new(260); + [ServiceImport] public ClrRuntime Runtime { get; set; } @@ -34,7 +36,7 @@ public override void Invoke() } ClrReference[] refs = obj.EnumerateReferencesWithFields(carefully: false, considerDependantHandles: false).ToArray(); - if (refs.Length == 0 ) + if (refs.Length == 0) { Console.WriteLine("GC Refs: none"); return; @@ -42,19 +44,21 @@ public override void Invoke() Console.WriteLine("GC Refs:"); - int fieldNameLen = Math.Max(refs.Max(r => GetFieldName(r)?.Length ?? 0), 5); - int offsetLen = Math.Max(refs.Max(r => r.Offset.ToSignedHexString().Length), 6); + Column fieldNameColumn = ColumnKind.Text.GetAppropriateWidth(refs.Select(r => GetFieldName(r))); + Column offsetName = ColumnKind.HexOffset.GetAppropriateWidth(refs.Select(r => r.Offset)); - TableOutput output = new(Console, (fieldNameLen, ""), (offsetLen, ""), (16, "x12")); - output.WriteRow("Field", "Offset", "Object", "Type"); + Table output = new(Console, fieldNameColumn, offsetName, ColumnKind.DumpObj, ColumnKind.TypeName); + output.WriteHeader("Field", "Offset", "Object", "Type"); foreach (ClrReference objRef in refs) { - output.WriteRow(GetFieldName(objRef), objRef.Offset, new DmlDumpObj(objRef.Object), objRef.Object.Type?.Name); + output.WriteRow(GetFieldName(objRef), objRef.Offset, objRef.Object, objRef.Object.Type); } } - private static string GetFieldName(ClrReference objRef) + private string GetFieldName(ClrReference objRef) { + Console.CancellationToken.ThrowIfCancellationRequested(); + if (objRef.Field is null) { return null; @@ -65,7 +69,7 @@ private static string GetFieldName(ClrReference objRef) return objRef.Field?.Name; } - StringBuilder sb = new(260); + StringBuilder sb = _stringBuilderPool.Rent(); bool foundOneFieldName = false; for (ClrReference? curr = objRef; curr.HasValue; curr = curr.Value.InnerField) @@ -88,7 +92,9 @@ private static string GetFieldName(ClrReference objRef) } // Make sure we don't just return "???.???.???" - return foundOneFieldName ? sb.ToString() : null; + string result = foundOneFieldName ? sb.ToString() : null; + _stringBuilderPool.Return(sb); + return result; } } } diff --git a/src/Microsoft.Diagnostics.ExtensionCommands/DumpRuntimeTypeCommand.cs b/src/Microsoft.Diagnostics.ExtensionCommands/DumpRuntimeTypeCommand.cs index a1fee8ad8d..cfc8579e6f 100644 --- a/src/Microsoft.Diagnostics.ExtensionCommands/DumpRuntimeTypeCommand.cs +++ b/src/Microsoft.Diagnostics.ExtensionCommands/DumpRuntimeTypeCommand.cs @@ -2,8 +2,9 @@ // The .NET Foundation licenses this file to you under the MIT license. using Microsoft.Diagnostics.DebugServices; +using Microsoft.Diagnostics.ExtensionCommands.Output; using Microsoft.Diagnostics.Runtime; -using static Microsoft.Diagnostics.ExtensionCommands.TableOutput; +using static Microsoft.Diagnostics.ExtensionCommands.Output.ColumnKind; namespace Microsoft.Diagnostics.ExtensionCommands { @@ -15,11 +16,12 @@ public sealed class DumpRuntimeTypeCommand : CommandBase public override void Invoke() { - TableOutput output = null; + Table output = null; foreach (ClrObject runtimeType in Runtime.Heap.EnumerateObjects()) { Console.CancellationToken.ThrowIfCancellationRequested(); + if (!runtimeType.IsValid || !runtimeType.IsRuntimeType) { continue; @@ -31,14 +33,17 @@ public override void Invoke() } ClrAppDomain domain = null; - string typeName; + object typeName = m_handle; bool isMethodTable = (m_handle & 2) == 0; if (isMethodTable) { // Only lookup the type if we have a MethodTable. ClrType type = Runtime.GetTypeByMethodTable(m_handle); - typeName = type?.Name ?? $"methodtable: {m_handle:x}"; - domain = type?.Module?.AppDomain; + if (type is not null) + { + typeName = type; + domain = type.Module?.AppDomain; + } } else { @@ -47,14 +52,13 @@ public override void Invoke() if (output is null) { - output = new(Console, (16, "x12"), (16, "x12"), (16, "x12")); - output.WriteRow("Address", "Domain", "MT", "Type Name"); + output = new(Console, DumpObj, DumpDomain, DumpHeap, TypeName); + output.WriteHeader("Address", "Domain", "MT", "Type Name"); } - output.WriteRow(new DmlDumpObj(runtimeType.Address), - domain is not null ? new DmlDumpDomain(domain.Address) : null, - isMethodTable ? new DmlDumpMT(m_handle) : m_handle, - typeName); + // We pass .Address here instead of the ClrObject because every type is a RuntimeType, we don't need + // or want the alt-text. + output.WriteRow(runtimeType.Address, domain, m_handle, typeName); } if (output is null) diff --git a/src/Microsoft.Diagnostics.ExtensionCommands/DumpStackObjectsCommand.cs b/src/Microsoft.Diagnostics.ExtensionCommands/DumpStackObjectsCommand.cs index 69f20de9a8..1fb0562d63 100644 --- a/src/Microsoft.Diagnostics.ExtensionCommands/DumpStackObjectsCommand.cs +++ b/src/Microsoft.Diagnostics.ExtensionCommands/DumpStackObjectsCommand.cs @@ -9,7 +9,9 @@ using System.Linq; using System.Runtime.CompilerServices; using Microsoft.Diagnostics.DebugServices; +using Microsoft.Diagnostics.ExtensionCommands.Output; using Microsoft.Diagnostics.Runtime; +using static Microsoft.Diagnostics.ExtensionCommands.Output.ColumnKind; namespace Microsoft.Diagnostics.ExtensionCommands { @@ -74,8 +76,8 @@ private void PrintStackObjects(MemoryRange stack) { Console.WriteLine($"OS Thread Id: 0x{CurrentThread.ThreadId:x} ({CurrentThread.ThreadIndex})"); - TableOutput output = new(Console, (16, "x12"), (16, "x12")); - output.WriteRow("SP/REG", "Object", "Name"); + Table output = new(Console, Pointer, DumpObj, TypeName); + output.WriteHeader("SP/REG", "Object", "Name"); int regCount = ThreadService.Registers.Count(); foreach ((ulong address, ClrObject obj) in EnumerateValidObjectsWithinRange(stack).OrderBy(r => r.StackAddress)) @@ -94,11 +96,11 @@ private void PrintStackObjects(MemoryRange stack) registerName = $"reg{address}"; } - output.WriteRow(registerName, obj.Address, obj.Type?.Name); + output.WriteRow(registerName, obj, obj.Type); } else { - output.WriteRow(address, obj.Address, obj.Type?.Name); + output.WriteRow(address, obj, obj.Type); } } } diff --git a/src/Microsoft.Diagnostics.ExtensionCommands/EEHeapCommand.cs b/src/Microsoft.Diagnostics.ExtensionCommands/EEHeapCommand.cs index 326f2efef2..ac2f9507f6 100644 --- a/src/Microsoft.Diagnostics.ExtensionCommands/EEHeapCommand.cs +++ b/src/Microsoft.Diagnostics.ExtensionCommands/EEHeapCommand.cs @@ -7,8 +7,9 @@ using System.Linq; using System.Text; using Microsoft.Diagnostics.DebugServices; +using Microsoft.Diagnostics.ExtensionCommands.Output; using Microsoft.Diagnostics.Runtime; -using static Microsoft.Diagnostics.ExtensionCommands.TableOutput; +using static Microsoft.Diagnostics.ExtensionCommands.Output.ColumnKind; namespace Microsoft.Diagnostics.ExtensionCommands { @@ -72,10 +73,8 @@ public override void Invoke() private ulong PrintOneRuntime(ClrRuntime clrRuntime) { StringBuilder stringBuilder = null; - TableOutput output = new(Console, (21, "x12"), (0, "x12")) - { - AlignLeft = true - }; + Table output = new(Console, Text.WithWidth(21), Pointer.WithWidth(-1)); + output.SetAlignment(Align.Left); HashSet seen = new(); @@ -105,7 +104,7 @@ private ulong PrintOneRuntime(ClrRuntime clrRuntime) return totalSize; } - private ulong PrintAppDomains(TableOutput output, ClrRuntime clrRuntime, HashSet loaderAllocatorsSeen) + private ulong PrintAppDomains(Table output, ClrRuntime clrRuntime, HashSet loaderAllocatorsSeen) { Console.WriteLine("Loader Heap:"); WriteDivider(); @@ -117,6 +116,8 @@ private ulong PrintAppDomains(TableOutput output, ClrRuntime clrRuntime, HashSet for (int i = 0; i < clrRuntime.AppDomains.Length; i++) { + Console.CancellationToken.ThrowIfCancellationRequested(); + ClrAppDomain appDomain = clrRuntime.AppDomains[i]; totalBytes += PrintAppDomain(output, appDomain, $"Domain {i + 1}:", loaderAllocatorsSeen); } @@ -124,7 +125,7 @@ private ulong PrintAppDomains(TableOutput output, ClrRuntime clrRuntime, HashSet return totalBytes; } - private ulong PrintAppDomain(TableOutput output, ClrAppDomain appDomain, string name, HashSet loaderAllocatorsSeen) + private ulong PrintAppDomain(Table output, ClrAppDomain appDomain, string name, HashSet loaderAllocatorsSeen) { if (appDomain is null) { @@ -182,7 +183,7 @@ private static int GetSortOrder(NativeHeapKind key) }; } - private ulong PrintAppDomainHeapsByKind(TableOutput output, IOrderedEnumerable> filteredHeapsByKind) + private ulong PrintAppDomainHeapsByKind(Table output, IOrderedEnumerable> filteredHeapsByKind) { // Just build and print the table. ulong totalSize = 0; @@ -191,6 +192,8 @@ private ulong PrintAppDomainHeapsByKind(TableOutput output, IOrderedEnumerable item in filteredHeapsByKind) { + Console.CancellationToken.ThrowIfCancellationRequested(); + text.Clear(); NativeHeapKind kind = item.Key; ulong heapSize = 0; @@ -236,12 +239,14 @@ private ulong PrintAppDomainHeapsByKind(TableOutput output, IOrderedEnumerable heaps = jitManager.EnumerateNativeHeaps().Where(IsIncludedInFilter).OrderBy(r => r.Kind).ThenBy(r => r.MemoryRange.Start); @@ -324,7 +329,7 @@ private bool IsIncludedInFilter(ClrNativeHeapInfo info) return (0, 0); } - private ulong PrintModuleThunkTable(TableOutput output, ref StringBuilder text, ClrRuntime clrRuntime) + private ulong PrintModuleThunkTable(Table output, ref StringBuilder text, ClrRuntime clrRuntime) { IEnumerable modulesWithThunks = clrRuntime.EnumerateModules().Where(r => r.ThunkHeap != 0); if (!modulesWithThunks.Any()) @@ -338,7 +343,7 @@ private ulong PrintModuleThunkTable(TableOutput output, ref StringBuilder text, return PrintModules(output, ref text, modulesWithThunks); } - private ulong PrintModuleLoaderAllocators(TableOutput output, ref StringBuilder text, ClrRuntime clrRuntime, HashSet loaderAllocatorsSeen) + private ulong PrintModuleLoaderAllocators(Table output, ref StringBuilder text, ClrRuntime clrRuntime, HashSet loaderAllocatorsSeen) { // On .Net Core, modules share their LoaderAllocator with their AppDomain (and AppDomain shares theirs // with SystemDomain). Only collectable assemblies have unique loader allocators, and that's what we @@ -359,17 +364,21 @@ private ulong PrintModuleLoaderAllocators(TableOutput output, ref StringBuilder return PrintModules(output, ref text, collectable); } - private ulong PrintModules(TableOutput output, ref StringBuilder text, IEnumerable modules) + private ulong PrintModules(Table output, ref StringBuilder text, IEnumerable modules) { text ??= new(128); ulong totalSize = 0, totalWasted = 0; foreach (ClrModule module in modules) { + Console.CancellationToken.ThrowIfCancellationRequested(); + ulong moduleSize = 0, moduleWasted = 0; text.Clear(); foreach (ClrNativeHeapInfo info in module.EnumerateThunkHeap().Where(IsIncludedInFilter)) { + Console.CancellationToken.ThrowIfCancellationRequested(); + if (text.Length > 0) { text.Append(' '); @@ -439,14 +448,8 @@ private ulong PrintGCHeap(ClrRuntime clrRuntime) Console.WriteLine(); ClrHeap heap = clrRuntime.Heap; - int pointerWidth = 16; - string pointerToStringFormat = "x16"; - (int pointerWidth, string pointerToStringFormat) pointerFormat = (pointerWidth, pointerToStringFormat); - - int sizeWidth = Math.Max(15, heap.Segments.Max(seg => FormatMemorySize(seg.CommittedMemory.Length).Length)); - (int sizeWidth, string) sizeFormat = (sizeWidth, ""); - - TableOutput gcOutput = new(Console, pointerFormat, pointerFormat, pointerFormat, pointerFormat, sizeFormat, sizeFormat); + Column sizeColumn = Text.GetAppropriateWidth(heap.Segments.Select(seg => FormatMemorySize(seg.CommittedMemory.Length)), max: 32); + Table gcOutput = new(Console, DumpHeap, Pointer, Pointer, Pointer, sizeColumn, sizeColumn); WriteDivider('='); Console.WriteLine($"Number of GC Heaps: {heap.SubHeaps.Length}"); @@ -454,6 +457,8 @@ private ulong PrintGCHeap(ClrRuntime clrRuntime) foreach (ClrSubHeap gc_heap in HeapWithFilters.EnumerateFilteredSubHeaps()) { + Console.CancellationToken.ThrowIfCancellationRequested(); + if (heap.IsServer) { Console.Write("Heap "); @@ -596,15 +601,14 @@ private ulong PrintGCHeap(ClrRuntime clrRuntime) return totalCommitted; } - private static void WriteSegmentHeader(TableOutput gcOutput) + private static void WriteSegmentHeader(Table gcOutput) { - gcOutput.WriteRow("segment", "begin", "allocated", "committed", "allocated size", "committed size"); + gcOutput.WriteHeader("segment", "begin", "allocated", "committed", "allocated size", "committed size"); } - private static void WriteSegment(TableOutput gcOutput, ClrSegment segment) + private static void WriteSegment(Table gcOutput, ClrSegment segment) { - gcOutput.WriteRow(new DmlDumpHeapSegment(segment), - segment.ObjectRange.Start, segment.ObjectRange.End, segment.CommittedMemory.End, + gcOutput.WriteRow(segment, segment.ObjectRange.Start, segment.ObjectRange.End, segment.CommittedMemory.End, FormatMemorySize(segment.ObjectRange.Length), FormatMemorySize(segment.CommittedMemory.Length)); } diff --git a/src/Microsoft.Diagnostics.ExtensionCommands/FinalizeQueueCommand.cs b/src/Microsoft.Diagnostics.ExtensionCommands/FinalizeQueueCommand.cs index f413b5cb90..9d4efb2ede 100644 --- a/src/Microsoft.Diagnostics.ExtensionCommands/FinalizeQueueCommand.cs +++ b/src/Microsoft.Diagnostics.ExtensionCommands/FinalizeQueueCommand.cs @@ -5,7 +5,9 @@ using System.Collections.Generic; using System.Linq; using Microsoft.Diagnostics.DebugServices; +using Microsoft.Diagnostics.ExtensionCommands.Output; using Microsoft.Diagnostics.Runtime; +using static Microsoft.Diagnostics.ExtensionCommands.Output.ColumnKind; namespace Microsoft.Diagnostics.ExtensionCommands { @@ -136,7 +138,7 @@ private IEnumerable EnumerateValidFinalizableObjectsWithTypeFilter(ul private void PrintSyncBlockCleanupData() { - TableOutput output = null; + Table output = null; int total = 0; foreach (ClrSyncBlockCleanupData cleanup in Runtime.EnumerateSyncBlockCleanupData()) { @@ -144,8 +146,8 @@ private void PrintSyncBlockCleanupData() if (output is null) { - output = new(Console, (16, "x12"), (16, "x12"), (16, "x12")); - output.WriteRow("SyncBlock", "RCW", "CCW", "ComClassFactory"); + output = new(Console, Pointer, Pointer, Pointer, Pointer); + output.WriteHeader("SyncBlock", "RCW", "CCW", "ComClassFactory"); } output.WriteRow(cleanup.SyncBlock, cleanup.Rcw, cleanup.Ccw, cleanup.ClassFactory); @@ -157,7 +159,7 @@ private void PrintSyncBlockCleanupData() private void PrintRcwCleanupData() { - TableOutput output = null; + Table output = null; int freeThreadedCount = 0; int mtaCount = 0; int staCount = 0; @@ -168,8 +170,8 @@ private void PrintRcwCleanupData() if (output is null) { - output = new(Console, (16, "x12"), (16, "x12"), (16, "x12")); - output.WriteRow("RCW", "Context", "Thread", "Apartment"); + output = new(Console, Pointer, Pointer, Thread, Text); + output.WriteHeader("RCW", "Context", "Thread", "Apartment"); } string apartment; diff --git a/src/Microsoft.Diagnostics.ExtensionCommands/FindEphemeralReferencesToLOHCommand.cs b/src/Microsoft.Diagnostics.ExtensionCommands/FindEphemeralReferencesToLOHCommand.cs index c7fa399b83..e1715396da 100644 --- a/src/Microsoft.Diagnostics.ExtensionCommands/FindEphemeralReferencesToLOHCommand.cs +++ b/src/Microsoft.Diagnostics.ExtensionCommands/FindEphemeralReferencesToLOHCommand.cs @@ -5,8 +5,9 @@ using System.Diagnostics; using System.Linq; using Microsoft.Diagnostics.DebugServices; +using Microsoft.Diagnostics.ExtensionCommands.Output; using Microsoft.Diagnostics.Runtime; -using static Microsoft.Diagnostics.ExtensionCommands.TableOutput; +using static Microsoft.Diagnostics.ExtensionCommands.Output.ColumnKind; namespace Microsoft.Diagnostics.ExtensionCommands { @@ -28,7 +29,7 @@ public override void Invoke() Console.WriteLineWarning($"Walking {segments:n0} {gcSegKind}, this may take a moment..."); } - TableOutput output = new(Console, (16, "x12"), (64, ""), (16, "x12")); + Table output = new(Console, DumpObj, TypeName.WithWidth(64), DumpObj, TypeName); // Ephemeral -> Large List<(ClrObject From, ClrObject To)> ephToLoh = FindEphemeralToLOH().OrderBy(i => i.From.Address).ThenBy(i => i.To.Address).ToList(); @@ -40,11 +41,11 @@ public override void Invoke() { Console.WriteLine("Ephemeral objects pointing to the Large objects:"); Console.WriteLine(); - output.WriteRow("Ephemeral", "Ephemeral Type", "Large Object", "Large Object Type"); + output.WriteHeader("Ephemeral", "Ephemeral Type", "Large Object", "Large Object Type"); foreach ((ClrObject from, ClrObject to) in ephToLoh) { - output.WriteRow(new DmlDumpObj(from), from.Type?.Name, new DmlDumpObj(to), to.Type?.Name); + output.WriteRow(from, from.Type, to, to.Type); } Console.WriteLine(); @@ -60,11 +61,11 @@ public override void Invoke() { Console.WriteLine("Large objects pointing to Ephemeral objects:"); Console.WriteLine(); - output.WriteRow("Ephemeral", "Ephemeral Type", "Large Object", "Large Object Type"); + output.WriteHeader("Ephemeral", "Ephemeral Type", "Large Object", "Large Object Type"); foreach ((ClrObject from, ClrObject to) in lohToEph) { - output.WriteRow(new DmlDumpObj(from), from.Type?.Name, new DmlDumpObj(to), to.Type?.Name); + output.WriteRow(from, from.Type, to, to.Type); } Console.WriteLine(); @@ -90,8 +91,8 @@ public override void Invoke() { Console.WriteLine($"Ephemeral objects which point to Large objects which point to Ephemeral objects:"); Console.WriteLine(); - output = new(Console, (16, "x12"), (64, ""), (16, "x12"), (64, ""), (16, "x12")); - output.WriteRow(new DmlDumpObj(from), from.Type?.Name, new DmlDumpObj(to), to.Type?.Name, new DmlDumpObj(ephEnd), ephEnd.Type?.Name); + output = new(Console, DumpObj, TypeName.WithWidth(64), DumpObj, TypeName.WithWidth(64), DumpObj, TypeName); + output.WriteRow(from, from.Type, to, to.Type, ephEnd, ephEnd.Type); } } @@ -104,14 +105,6 @@ public override void Invoke() Console.WriteLine(); } } - - foreach ((ClrObject From, ClrObject To) item in ephToLoh) - { - if (lohToEph.Any(r => item.To.Address == r.From.Address)) - { - Console.WriteLine("error!"); - } - } } private IEnumerable<(ClrObject From, ClrObject To)> FindEphemeralToLOH() diff --git a/src/Microsoft.Diagnostics.ExtensionCommands/FindPointersInCommand.cs b/src/Microsoft.Diagnostics.ExtensionCommands/FindPointersInCommand.cs index 66de79e8e7..752bb338c3 100644 --- a/src/Microsoft.Diagnostics.ExtensionCommands/FindPointersInCommand.cs +++ b/src/Microsoft.Diagnostics.ExtensionCommands/FindPointersInCommand.cs @@ -6,9 +6,10 @@ using System.IO; using System.Linq; using Microsoft.Diagnostics.DebugServices; +using Microsoft.Diagnostics.ExtensionCommands.Output; using Microsoft.Diagnostics.Runtime; -using Microsoft.Diagnostics.Runtime.Interfaces; using static Microsoft.Diagnostics.ExtensionCommands.NativeAddressHelper; +using static Microsoft.Diagnostics.ExtensionCommands.Output.ColumnKind; namespace Microsoft.Diagnostics.ExtensionCommands { @@ -239,9 +240,10 @@ private void PrintPointerTable(string nameColumn, string truncatedName, bool for int nameLen = Math.Min(80, maxNameLen); nameLen = Math.Max(nameLen, truncatedName.Length); - TableOutput table = new(Console, (nameLen, ""), (12, "n0"), (12, "n0"), (12, "x")); - table.Divider = " "; - table.WriteRowWithSpacing('-', nameColumn, "Unique", "Count", "RndPtr"); + using BorderedTable table = new(Console, TypeName.WithWidth(nameLen), Integer, Integer, Pointer); + table.Columns[0] = table.Columns[0].WithAlignment(Align.Center); + table.WriteHeader(nameColumn, "Unique", "Count", "RndPtr"); + table.Columns[0] = table.Columns[0].WithAlignment(Align.Left); IEnumerable<(string Name, int Count, int Unique, IEnumerable Pointers)> items = truncate ? resolved.Take(multi) : resolved; foreach ((string Name, int Count, int Unique, IEnumerable Pointers) in items) @@ -254,7 +256,8 @@ private void PrintPointerTable(string nameColumn, string truncatedName, bool for table.WriteRow(truncatedName, single, single); } - table.WriteRowWithSpacing('-', " [ TOTALS ] ", resolved.Sum(r => r.Unique), resolved.Sum(r => r.Count), ""); + table.Columns[0] = table.Columns[0].WithAlignment(Align.Center); + table.WriteFooter("TOTALS", resolved.Sum(r => r.Unique), resolved.Sum(r => r.Count)); } private static string FixTypeName(string typeName, HashSet offsets) diff --git a/src/Microsoft.Diagnostics.ExtensionCommands/FindReferencesToEphemeralCommand.cs b/src/Microsoft.Diagnostics.ExtensionCommands/FindReferencesToEphemeralCommand.cs index 8c5f3c0eac..6614438d78 100644 --- a/src/Microsoft.Diagnostics.ExtensionCommands/FindReferencesToEphemeralCommand.cs +++ b/src/Microsoft.Diagnostics.ExtensionCommands/FindReferencesToEphemeralCommand.cs @@ -4,8 +4,9 @@ using System.Collections.Generic; using System.Linq; using Microsoft.Diagnostics.DebugServices; +using Microsoft.Diagnostics.ExtensionCommands.Output; using Microsoft.Diagnostics.Runtime; -using static Microsoft.Diagnostics.ExtensionCommands.TableOutput; +using static Microsoft.Diagnostics.ExtensionCommands.Output.ColumnKind; namespace Microsoft.Diagnostics.ExtensionCommands { @@ -20,7 +21,7 @@ public class FindReferencesToEphemeralCommand : CommandBase public override void Invoke() { - TableOutput output = new(Console, (16, "x12"), (16, "x12"), (10, "n0"), (8, ""), (8, ""), (12, "n0"), (12, "n0")); + Table output = new(Console, DumpObj, DumpHeap, ByteCount, Column.ForEnum(), Column.ForEnum(), ByteCount, Integer, TypeName); var generationGroup = from item in FindObjectsWithEphemeralReferences() group item by (item.ObjectGeneration, item.ReferenceGeneration) into g @@ -54,7 +55,7 @@ group item by (item.ObjectGeneration, item.ReferenceGeneration) into g Console.WriteLine($"References from {objGen} to {refGen}:"); Console.WriteLine(); - output.WriteRow("Object", "MethodTable", "Size", "Obj Gen", "Ref Gen", "Obj Count", "Obj Size", "Type"); + output.WriteHeader("Object", "MethodTable", "Size", "Obj Gen", "Ref Gen", "Obj Count", "Obj Size", "Type"); } foreach (EphemeralRefCount erc in item.Objects) @@ -62,7 +63,7 @@ group item by (item.ObjectGeneration, item.ReferenceGeneration) into g Console.CancellationToken.ThrowIfCancellationRequested(); objCount++; - output.WriteRow(new DmlDumpObj(erc.Object), erc.Object.Type.MethodTable, erc.Object.Size, erc.ObjectGeneration, erc.ReferenceGeneration, erc.Count, erc.Size, erc.Object.Type.Name); + output.WriteRow(erc.Object, erc.Object.Type, erc.Object.Size, erc.ObjectGeneration, erc.ReferenceGeneration, erc.Count, erc.Size, erc.Object.Type); } } diff --git a/src/Microsoft.Diagnostics.ExtensionCommands/GCHeapStatCommand.cs b/src/Microsoft.Diagnostics.ExtensionCommands/GCHeapStatCommand.cs index a7c24db50a..7a3da01995 100644 --- a/src/Microsoft.Diagnostics.ExtensionCommands/GCHeapStatCommand.cs +++ b/src/Microsoft.Diagnostics.ExtensionCommands/GCHeapStatCommand.cs @@ -5,7 +5,9 @@ using System.Collections.Generic; using System.Linq; using Microsoft.Diagnostics.DebugServices; +using Microsoft.Diagnostics.ExtensionCommands.Output; using Microsoft.Diagnostics.Runtime; +using static Microsoft.Diagnostics.ExtensionCommands.Output.ColumnKind; namespace Microsoft.Diagnostics.ExtensionCommands { @@ -23,25 +25,29 @@ public class GCHeapStatCommand : CommandBase public override void Invoke() { - HeapInfo[] heaps = Runtime.Heap.SubHeaps.Select(h => GetHeapInfo(h)).ToArray(); bool printFrozen = heaps.Any(h => h.Frozen.Committed != 0); - - List<(int, string)> formats = new() + List formats = new() { - (8, "x"), (12, ""), (12, ""), (12, ""), (12, ""), (12, ""), (8, ""), (8, ""), (8, "") + Text.WithWidth(8), + IntegerWithoutCommas, + IntegerWithoutCommas, + IntegerWithoutCommas, + IntegerWithoutCommas, + IntegerWithoutCommas, + Text.WithWidth(8), + Text.WithWidth(8), + Text.WithWidth(8) }; if (printFrozen) { - formats.Insert(1, (12, "")); + formats.Insert(1, IntegerWithoutCommas); } - TableOutput output = new(Console, formats.ToArray()) - { - AlignLeft = true, - }; + Table output = new(Console, formats.ToArray()); + output.SetAlignment(Align.Left); // Write allocated WriteHeader(output, heaps, printFrozen); @@ -91,13 +97,13 @@ public override void Invoke() } total = GetTotal(heaps); - WriteRow(output, total, (info) => info.Committed, printFrozen); + WriteRow(output, total, (info) => info.Committed, printFrozen, printPercentage: false, footer: true); Console.WriteLine(); } - private static void WriteHeader(TableOutput output, HeapInfo[] heaps, bool printFrozen) + private static void WriteHeader(Table output, HeapInfo[] heaps, bool printFrozen) { - List row = new(8) { "Heap", "Gen0", "Gen1", "Gen2", "LOH", "POH" }; + List row = new(8) { "Heap", "Gen0", "Gen1", "Gen2", "LOH", "POH" }; if (printFrozen) { @@ -110,10 +116,10 @@ private static void WriteHeader(TableOutput output, HeapInfo[] heaps, bool print row.Insert(1, "EPH"); } - output.WriteRow(row.ToArray()); + output.WriteHeader(row.ToArray()); } - private static void WriteRow(TableOutput output, HeapInfo heapInfo, Func select, bool printFrozen, bool printPercentage = false) + private static void WriteRow(Table output, HeapInfo heapInfo, Func select, bool printFrozen, bool printPercentage = false, bool footer = false) { List row = new(11) { @@ -171,7 +177,14 @@ private static void WriteRow(TableOutput output, HeapInfo heapInfo, Func", obj.IsValid ? new DmlDumpObj(obj) : obj.Address, obj.Type?.Name ?? "", (isDependentHandleLink ? " (dependent handle)" : "")); + objectOutput.WriteRow("->", obj, obj.Type, (isDependentHandleLink ? " (dependent handle)" : "")); prevObj = link.Object; link = link.Next; diff --git a/src/Microsoft.Diagnostics.ExtensionCommands/GCToNativeCommand.cs b/src/Microsoft.Diagnostics.ExtensionCommands/GCToNativeCommand.cs index 1016dd685a..e5157d4d31 100644 --- a/src/Microsoft.Diagnostics.ExtensionCommands/GCToNativeCommand.cs +++ b/src/Microsoft.Diagnostics.ExtensionCommands/GCToNativeCommand.cs @@ -7,8 +7,10 @@ using System.Linq; using System.Text; using Microsoft.Diagnostics.DebugServices; +using Microsoft.Diagnostics.ExtensionCommands.Output; using Microsoft.Diagnostics.Runtime; using static Microsoft.Diagnostics.ExtensionCommands.NativeAddressHelper; +using static Microsoft.Diagnostics.ExtensionCommands.Output.ColumnKind; namespace Microsoft.Diagnostics.ExtensionCommands { @@ -99,6 +101,8 @@ public void PrintGCPointersToMemory(bool showAll, params string[] memoryTypes) foreach ((ClrSegment Segment, ulong Address, ulong Pointer, DescribedRegion MemoryRange) item in items) { + Console.CancellationToken.ThrowIfCancellationRequested(); + if (!segmentLists.TryGetValue(item.Segment, out List list)) { list = segmentLists[item.Segment] = new(); @@ -110,6 +114,8 @@ public void PrintGCPointersToMemory(bool showAll, params string[] memoryTypes) Console.WriteLine("Resolving object names..."); foreach (string type in memoryTypes) { + Console.CancellationToken.ThrowIfCancellationRequested(); + WriteHeader($" {type} Regions "); List addressesNotInObjects = new(); @@ -119,6 +125,8 @@ public void PrintGCPointersToMemory(bool showAll, params string[] memoryTypes) foreach (KeyValuePair> segEntry in segmentLists) { + Console.CancellationToken.ThrowIfCancellationRequested(); + ClrSegment seg = segEntry.Key; List pointers = segEntry.Value; pointers.Sort((x, y) => x.GCPointer.CompareTo(y.GCPointer)); @@ -133,6 +141,8 @@ public void PrintGCPointersToMemory(bool showAll, params string[] memoryTypes) while (index < pointers.Count && pointers[index].GCPointer < obj.Address) { + Console.CancellationToken.ThrowIfCancellationRequested(); + // If we "missed" the pointer then it's outside of an object range. addressesNotInObjects.Add(pointers[index].GCPointer); @@ -148,6 +158,8 @@ public void PrintGCPointersToMemory(bool showAll, params string[] memoryTypes) while (index < pointers.Count && obj.Address <= pointers[index].GCPointer && pointers[index].GCPointer < obj.Address + obj.Size) { + Console.CancellationToken.ThrowIfCancellationRequested(); + string typeName = obj.Type?.Name ?? $""; if (obj.IsFree) @@ -195,20 +207,20 @@ public void PrintGCPointersToMemory(bool showAll, params string[] memoryTypes) { Console.WriteLine($"All memory pointers:"); - IEnumerable<(ulong Pointer, ulong Size, ulong Object, string Type)> allPointers = unknownObjPointers.Select(unknown => (unknown.Pointer, 0ul, unknown.Object.Address, unknown.Object.Type?.Name ?? "")); - allPointers = allPointers.Concat(knownMemory.Values.Select(k => (k.Pointer, GetSize(sizeHints, k), k.Object.Address, k.Name))); + IEnumerable<(ulong Pointer, ulong Size, ClrObject Object, ClrType Type)> allPointers = unknownObjPointers.Select(unknown => (unknown.Pointer, 0ul, unknown.Object, unknown.Object.Type)); + allPointers = allPointers.Concat(knownMemory.Values.Select(k => (k.Pointer, GetSize(sizeHints, k), k.Object, k.Object.Type))); - TableOutput allOut = new(Console, (16, "x"), (16, "x"), (16, "x")) - { - Divider = " | " - }; + using BorderedTable allOut = new(Console, Pointer, ByteCount, DumpObj, TypeName); + + allOut.WriteHeader("Pointer", "Size", "Object", "Type"); - allOut.WriteRowWithSpacing('-', "Pointer", "Size", "Object", "Type"); - foreach ((ulong Pointer, ulong Size, ulong Object, string Type) entry in allPointers) + foreach ((ulong Pointer, ulong Size, ClrObject Object, ClrType Type) entry in allPointers) { + Console.CancellationToken.ThrowIfCancellationRequested(); + if (entry.Size == 0) { - allOut.WriteRow(entry.Pointer, "", entry.Object, entry.Type); + allOut.WriteRow(entry.Pointer, null, entry.Object, entry.Type); } else { @@ -225,38 +237,35 @@ public void PrintGCPointersToMemory(bool showAll, params string[] memoryTypes) // totals var knownMemorySummary = from known in knownMemory.Values - group known by known.Name into g - let Name = g.Key + group known by known.Object.Type into g + let Type = g.Key let Count = g.Count() let TotalSize = g.Sum(k => (long)GetSize(sizeHints, k)) - orderby TotalSize descending, Name ascending + orderby TotalSize descending, Type.Name ascending select new { - Name, + Type, Count, TotalSize, Pointer = g.Select(p => p.Pointer).FindMostCommonPointer() }; - int maxNameLen = Math.Min(80, knownMemory.Values.Max(r => r.Name.Length)); - - TableOutput summary = new(Console, (-maxNameLen, ""), (8, "n0"), (12, "n0"), (12, "n0"), (12, "x")) + Column typeNameColumn = TypeName.GetAppropriateWidth(knownMemory.Values.Select(r => r.Object.Type), 16); + using (BorderedTable summary = new(Console, typeNameColumn, Integer, HumanReadableSize, ByteCount, Pointer)) { - Divider = " | " - }; - - summary.WriteRowWithSpacing('-', "Type", "Count", "Size", "Size (bytes)", "RndPointer"); + summary.WriteHeader("Type", "Count", "Size", "Size (bytes)", "RndPointer"); - foreach (var item in knownMemorySummary) - { - summary.WriteRow(item.Name, item.Count, item.TotalSize.ConvertToHumanReadable(), item.TotalSize, item.Pointer); - } + foreach (var item in knownMemorySummary) + { + Console.CancellationToken.ThrowIfCancellationRequested(); - (int totalRegions, ulong totalBytes) = GetSizes(knownMemory, sizeHints); + summary.WriteRow(item.Type, item.Count, item.TotalSize, item.TotalSize, item.Pointer); + } - summary.WriteSpacer('-'); - summary.WriteRow("[TOTAL]", totalRegions, totalBytes.ConvertToHumanReadable(), totalBytes); + (int totalRegions, ulong totalBytes) = GetSizes(knownMemory, sizeHints); + summary.WriteFooter("[TOTAL]", totalRegions, totalBytes, totalBytes); + } - Console.WriteLine(""); + Console.WriteLine(); } @@ -277,17 +286,15 @@ orderby Count descending }; var unknownMem = unknownMemQuery.ToArray(); - int maxNameLen = Math.Min(80, unknownMem.Max(r => r.Name.Length)); - - TableOutput summary = new(Console, (-maxNameLen, ""), (8, "n0"), (12, "x")) - { - Divider = " | " - }; - summary.WriteRowWithSpacing('-', "Type", "Count", "RndPointer"); + Column typeNameColumn = TypeName.GetAppropriateWidth(unknownMem.Select(r => r.Name)); + using BorderedTable summary = new(Console, typeNameColumn, Integer, Pointer); + summary.WriteHeader("Type", "Count", "RndPointer"); foreach (var item in unknownMem) { + Console.CancellationToken.ThrowIfCancellationRequested(); + summary.WriteRow(item.Name, item.Count, item.Pointer); } } @@ -349,12 +356,14 @@ private void WriteHeader(string header) Console.WriteLine(header.PadRight(Width, '=')); } - private static string CollapseGenerics(string typeName) + private string CollapseGenerics(string typeName) { StringBuilder result = new(typeName.Length + 16); int nest = 0; for (int i = 0; i < typeName.Length; i++) { + Console.CancellationToken.ThrowIfCancellationRequested(); + if (typeName[i] == '<') { if (nest++ == 0) @@ -419,7 +428,6 @@ private sealed class KnownClrMemoryPointer private const string ExternalMemoryBlock = "System.Reflection.Internal.ExternalMemoryBlock"; private const string RuntimeParameterInfo = "System.Reflection.RuntimeParameterInfo"; - public string Name => Object.Type?.Name ?? ""; public ClrObject Object { get; } public ulong Pointer { get; } public ulong Size { get; } diff --git a/src/Microsoft.Diagnostics.ExtensionCommands/GCWhereCommand.cs b/src/Microsoft.Diagnostics.ExtensionCommands/GCWhereCommand.cs index fad8d35df1..96a61f3783 100644 --- a/src/Microsoft.Diagnostics.ExtensionCommands/GCWhereCommand.cs +++ b/src/Microsoft.Diagnostics.ExtensionCommands/GCWhereCommand.cs @@ -5,8 +5,9 @@ using System.Collections.Generic; using System.Linq; using Microsoft.Diagnostics.DebugServices; +using Microsoft.Diagnostics.ExtensionCommands.Output; using Microsoft.Diagnostics.Runtime; -using static Microsoft.Diagnostics.ExtensionCommands.TableOutput; +using static Microsoft.Diagnostics.ExtensionCommands.Output.ColumnKind; namespace Microsoft.Diagnostics.ExtensionCommands { @@ -40,13 +41,13 @@ public override void Invoke() return; } - (int, string) RangeFormat = (segments.Max(seg => RangeSizeForSegment(seg)), ""); - TableOutput output = new(Console, (16, "x"), (4, ""), (16, "x"), (10, ""), RangeFormat, RangeFormat, RangeFormat) - { - AlignLeft = true, - }; + Column objectRangeColumn = Range.WithDml(Dml.DumpHeap).GetAppropriateWidth(segments.Select(r => r.ObjectRange)); + Column committedColumn = Range.GetAppropriateWidth(segments.Select(r => r.CommittedMemory)); + Column reservedColumn = Range.GetAppropriateWidth(segments.Select(r => r.ReservedMemory)); + Table output = new(Console, Pointer, IntegerWithoutCommas.WithWidth(6).WithDml(Dml.DumpHeap), DumpHeap, Text.WithWidth(6), objectRangeColumn, committedColumn, reservedColumn); + output.SetAlignment(Align.Left); + output.WriteHeader("Address", "Heap", "Segment", "Generation", "Allocated", "Committed", "Reserved"); - output.WriteRow("Address", "Heap", "Segment", "Generation", "Allocated", "Committed", "Reserved"); foreach (ClrSegment segment in segments) { string generation; @@ -68,23 +69,16 @@ public override void Invoke() }; } - object addressColumn = segment.ObjectRange.Contains(address) ? new DmlListNearObj(address) : address; - output.WriteRow(addressColumn, segment.SubHeap.Index, segment.Address, generation, new DmlDumpHeap(FormatRange(segment.ObjectRange), segment.ObjectRange), FormatRange(segment.CommittedMemory), FormatRange(segment.ReservedMemory)); - } - } - - private static string FormatRange(MemoryRange range) => $"{range.Start:x}-{range.End:x}"; + if (segment.ObjectRange.Contains(address)) + { + output.Columns[0] = output.Columns[0].WithDml(Dml.ListNearObj); + } + else + { + output.Columns[0] = output.Columns[0].WithDml(null); + } - private static int RangeSizeForSegment(ClrSegment segment) - { - // segment.ObjectRange should always be less length than CommittedMemory - if (segment.CommittedMemory.Length > segment.ReservedMemory.Length) - { - return FormatRange(segment.CommittedMemory).Length; - } - else - { - return FormatRange(segment.ReservedMemory).Length; + output.WriteRow(address, segment.SubHeap, segment, generation, segment.ObjectRange, segment.CommittedMemory, segment.ReservedMemory); } } diff --git a/src/Microsoft.Diagnostics.ExtensionCommands/ListNearObjCommand.cs b/src/Microsoft.Diagnostics.ExtensionCommands/ListNearObjCommand.cs index f0bc90562e..1b4411925f 100644 --- a/src/Microsoft.Diagnostics.ExtensionCommands/ListNearObjCommand.cs +++ b/src/Microsoft.Diagnostics.ExtensionCommands/ListNearObjCommand.cs @@ -5,8 +5,9 @@ using System.Diagnostics; using System.Linq; using Microsoft.Diagnostics.DebugServices; +using Microsoft.Diagnostics.ExtensionCommands.Output; using Microsoft.Diagnostics.Runtime; -using static Microsoft.Diagnostics.ExtensionCommands.TableOutput; +using static Microsoft.Diagnostics.ExtensionCommands.Output.ColumnKind; namespace Microsoft.Diagnostics.ExtensionCommands { @@ -71,7 +72,9 @@ public override void Invoke() MemoryRange[] segAllocContexts = heap.EnumerateAllocationContexts().Where(context => segment.ObjectRange.Contains(context.Start)).ToArray(); int pointerColumnWidth = segAllocContexts.Length > 0 ? Math.Max(segAllocContexts.Max(r => FormatRange(r).Length), 16) : 16; - TableOutput output = new(Console, (-"Expected:".Length, ""), (pointerColumnWidth, "x16"), (20, ""), (0, "")); + Column kindColumn = Text.WithWidth("Expected:".Length).WithAlignment(Align.Left); + + Table output = new(Console, kindColumn, DumpObj.WithWidth(pointerColumnWidth), Text.WithWidth(32), TypeName); // Get current object, but objAddress may not point to an object. ClrObject curr = heap.GetObject(objAddress); @@ -99,7 +102,7 @@ public override void Invoke() if (prev.IsValid) { - expectedNextObject = Align(prev + prev.Size, segment); + expectedNextObject = AlignObj(prev + prev.Size, segment); } else { @@ -193,7 +196,7 @@ public override void Invoke() localConsistency = VerifyAndPrintObject(output, "Current:", heap, segment, curr) && localConsistency; // If curr is valid, we need to print and skip the allocation context - expectedNextObject = Align(curr + curr.Size, segment); + expectedNextObject = AlignObj(curr + curr.Size, segment); MemoryRange allocContextPlusGap = PrintGapIfExists(output, segment, segAllocContexts, new(curr, expectedNextObject)); if (allocContextPlusGap.End != 0) { @@ -278,12 +281,13 @@ private void CheckEndOfSegment(ClrSegment segment, ulong expectedNextObject, ulo } } - private MemoryRange PrintGapIfExists(TableOutput output, ClrSegment segment, MemoryRange[] segAllocContexts, MemoryRange objectDistance) + private MemoryRange PrintGapIfExists(Table output, ClrSegment segment, MemoryRange[] segAllocContexts, MemoryRange objectDistance) { // Print information about allocation context gaps between objects MemoryRange range = segAllocContexts.FirstOrDefault(ctx => objectDistance.Overlaps(ctx) || ctx.Contains(objectDistance.End)); if (range.Start != 0) { + output.Columns[1] = output.Columns[1].WithDml(null); output.WriteRow("Gap:", FormatRange(range), FormatSize(range.Length), "GC Allocation Context (expected gap in the heap)"); } @@ -296,12 +300,12 @@ private MemoryRange PrintGapIfExists(TableOutput output, ClrSegment segment, Mem } uint minObjectSize = (uint)MemoryService.PointerSize * 3; - return new(range.Start, range.End + Align(minObjectSize, segment)); + return new(range.Start, range.End + AlignObj(minObjectSize, segment)); } private static string FormatRange(MemoryRange range) => $"{range.Start:x}-{range.End:x}"; - private ulong Align(ulong size, ClrSegment seg) + private ulong AlignObj(ulong size, ClrSegment seg) { ulong AlignConst; ulong AlignLargeConst = 7; @@ -323,25 +327,28 @@ private ulong Align(ulong size, ClrSegment seg) return (size + AlignConst) & ~AlignConst; } - private bool VerifyAndPrintObject(TableOutput output, string which, ClrHeap heap, ClrSegment segment, ClrObject obj) + private bool VerifyAndPrintObject(Table output, string which, ClrHeap heap, ClrSegment segment, ClrObject obj) { bool isObjectValid = !heap.IsObjectCorrupted(obj, out ObjectCorruption corruption) && obj.IsValid; - // Here, isCorrupted may still be true, but it might not interfere with getting the type of the object. - // Since we know the information, we will print that out. - string typeName = obj.Type?.Name ?? GetErrorTypeName(obj); - // ClrObject.Size is not available if IsValid returns false string size = FormatSize(obj.IsValid ? obj.Size : 0); if (corruption is null) { - output.WriteRow(which, new DmlDumpObj(obj), size, typeName); + output.Columns[1] = output.Columns[1].WithDml(Dml.DumpObj); + output.WriteRow(which, obj, size, obj.Type); } else { - output.WriteRow(which, new DmlListNearObj(obj), size, typeName); + output.Columns[1] = output.Columns[1].WithDml(Dml.ListNearObj); + output.WriteRow(which, obj, size, obj.Type); + Console.Write($"Error Detected: {VerifyHeapCommand.GetObjectCorruptionMessage(MemoryService, heap, corruption)} "); - Console.WriteDmlExec("[verify heap]", $"!verifyheap -s {segment.Address:X}"); + if (Console.SupportsDml) + { + Console.WriteDmlExec("[verify heap]", $"!verifyheap -segment {segment.Address:X}"); + } + Console.WriteLine(); } @@ -349,17 +356,5 @@ private bool VerifyAndPrintObject(TableOutput output, string which, ClrHeap heap } private static string FormatSize(ulong size) => size > 0 ? $"{size:n0} (0x{size:x})" : ""; - - private string GetErrorTypeName(ClrObject obj) - { - if (!MemoryService.ReadPointer(obj.Address, out _)) - { - return $"[error reading mt at: {obj.Address:x}]"; - } - else - { - return $"Unknown"; - } - } } } diff --git a/src/Microsoft.Diagnostics.ExtensionCommands/MAddressCommand.cs b/src/Microsoft.Diagnostics.ExtensionCommands/MAddressCommand.cs index b57f14f2c1..fa221c96ef 100644 --- a/src/Microsoft.Diagnostics.ExtensionCommands/MAddressCommand.cs +++ b/src/Microsoft.Diagnostics.ExtensionCommands/MAddressCommand.cs @@ -5,7 +5,9 @@ using System.Collections.Generic; using System.Linq; using Microsoft.Diagnostics.DebugServices; +using Microsoft.Diagnostics.ExtensionCommands.Output; using static Microsoft.Diagnostics.ExtensionCommands.NativeAddressHelper; +using static Microsoft.Diagnostics.ExtensionCommands.Output.ColumnKind; namespace Microsoft.Diagnostics.ExtensionCommands { @@ -23,7 +25,7 @@ public sealed class MAddressCommand : CommandBase [Option(Name = SummaryFlag, Aliases = new string[] { "-stat", }, Help = "Only print summary table.")] public bool Summary { get; set; } - [Option(Name = ImagesFlag, Aliases = new string[] { "-i" }, Help = "Prints a summary table of image memory usage.")] + [Option(Name = ImagesFlag, Help = "Prints a summary table of image memory usage.")] public bool ShowImageTable { get; set; } [Option(Name = ReserveFlag, Help = "Include MEM_RESERVE regions in the output.")] @@ -59,8 +61,6 @@ public override void Invoke() DescribedRegion[] ranges = memoryRanges.ToArray(); - int nameSizeMax = ranges.Max(r => r.Name.Length); - // Tag reserved memory based on what's adjacent. if (TagReserveMemoryHeuristically) { @@ -69,26 +69,23 @@ public override void Invoke() if (!Summary && List is null) { - int kindSize = ranges.Max(r => r.Type.ToString().Length); - int stateSize = ranges.Max(r => r.State.ToString().Length); - int protectSize = ranges.Max(r => r.Protection.ToString().Length); + Column nameColumn = Text.GetAppropriateWidth(ranges.Select(r => r.Name)); + Column kindColumn = Column.ForEnum(); + Column stateColumn = Column.ForEnum(); - TableOutput output = new(Console, (nameSizeMax, ""), (12, "x"), (12, "x"), (12, ""), (kindSize, ""), (stateSize, ""), (protectSize, "")) - { - AlignLeft = true, - Divider = " | " - }; + // These are flags, so we need a column wide enough for that output instead of ForEnum + Column protectionColumn = Text.GetAppropriateWidth(ranges.Select(r => r.Protection)); + Column imageColumn = Image.GetAppropriateWidth(ranges.Select(r => r.Image)); + using BorderedTable output = new(Console, nameColumn, Pointer, Pointer, HumanReadableSize, kindColumn, stateColumn, protectionColumn, imageColumn); - output.WriteRowWithSpacing('-', "Memory Kind", "StartAddr", "EndAddr-1", "Size", "Type", "State", "Protect", "Image"); + output.WriteHeader("Memory Kind", "StartAddr", "EndAddr-1", "Size", "Type", "State", "Protect", "Image"); IOrderedEnumerable ordered = BySize ? ranges.OrderByDescending(r => r.Size).ThenBy(r => r.Start) : ranges.OrderBy(r => r.Start); foreach (DescribedRegion mem in ordered) { Console.CancellationToken.ThrowIfCancellationRequested(); - output.WriteRow(mem.Name, mem.Start, mem.End, mem.Size.ConvertToHumanReadable(), mem.Type, mem.State, mem.Protection, mem.Image); + output.WriteRow(mem.Name, mem.Start, mem.End, mem.Size, mem.Type, mem.State, mem.Protection, mem.Image); } - - output.WriteSpacer('-'); } if (ShowImageTable) @@ -103,29 +100,27 @@ orderby Size descending Size }; - int moduleLen = Math.Max(80, ranges.Max(r => r.Image?.Length ?? 0)); - - TableOutput output = new(Console, (moduleLen, ""), (8, "n0"), (12, ""), (24, "n0")) + using (BorderedTable output = new(Console, Image.GetAppropriateWidth(ranges.Select(r => r.Image), max: 80), Integer, HumanReadableSize, ByteCount)) { - Divider = " | " - }; + Console.CancellationToken.ThrowIfCancellationRequested(); - output.WriteRowWithSpacing('-', "Image", "Count", "Size", "Size (bytes)"); + output.WriteHeader("Image", "Count", "Size", "Size (bytes)"); - int count = 0; - long size = 0; - foreach (var item in imageGroups) - { - Console.CancellationToken.ThrowIfCancellationRequested(); + int count = 0; + long size = 0; + foreach (var item in imageGroups) + { + Console.CancellationToken.ThrowIfCancellationRequested(); - output.WriteRow(item.Image, item.Count, item.Size.ConvertToHumanReadable(), item.Size); - count += item.Count; - size += item.Size; + output.WriteRow(item.Image, item.Count, item.Size, item.Size); + count += item.Count; + size += item.Size; + } + + output.WriteFooter("[TOTAL]", count, size, size); } - output.WriteSpacer('-'); - output.WriteRow("[TOTAL]", count, size.ConvertToHumanReadable(), size); - WriteLine(""); + Console.WriteLine(); } @@ -144,8 +139,8 @@ orderby Size descending { Console.WriteLine($"{kind} Memory Regions:"); - TableOutput output = new(Console, (16, "x12"), (16, "n0"), (8, ""), (12, ""), (12, "")); - output.WriteRow("Base Address", "Size (bytes)", "Size", "Mem State", "Mem Type", "Mem Protect"); + Table output = new(Console, Pointer, ByteCount, HumanReadableSize, Column.ForEnum(), Column.ForEnum(), Column.ForEnum().WithWidth(-1)); + output.WriteHeader("Base Address", "Size (bytes)", "Size", "Mem State", "Mem Type", "Mem Protect"); ulong totalSize = 0; int count = 0; @@ -153,7 +148,7 @@ orderby Size descending IEnumerable matching = ranges.Where(r => r.Name.Equals(kind, StringComparison.OrdinalIgnoreCase)).OrderByDescending(s => s.Size); foreach (DescribedRegion region in matching) { - output.WriteRow(region.Start, region.Size, region.Size.ConvertToHumanReadable(), region.State, region.Type, region.Protection); + output.WriteRow(region.Start, region.Size, region.Size, region.State, region.Type, region.Protection); count++; totalSize += region.Size; @@ -181,12 +176,9 @@ orderby Size descending Size }; - TableOutput output = new(Console, (-nameSizeMax, ""), (8, "n0"), (12, ""), (24, "n0")) - { - Divider = " | " - }; - - output.WriteRowWithSpacing('-', "Memory Type", "Count", "Size", "Size (bytes)"); + Column nameColumn = Text.GetAppropriateWidth(ranges.Select(r => r.Name)); + using BorderedTable output = new(Console, nameColumn, Integer, HumanReadableSize, ByteCount); + output.WriteHeader("Memory Type", "Count", "Size", "Size (bytes)"); int count = 0; long size = 0; @@ -194,17 +186,16 @@ orderby Size descending { Console.CancellationToken.ThrowIfCancellationRequested(); - output.WriteRow(item.Name, item.Count, item.Size.ConvertToHumanReadable(), item.Size); + output.WriteRow(item.Name, item.Count, item.Size, item.Size); + count += item.Count; size += item.Size; } - output.WriteSpacer('-'); - output.WriteRow("[TOTAL]", count, size.ConvertToHumanReadable(), size); + output.WriteFooter("[TOTAL]", count, size, size); } } - [HelpInvoke] public void HelpInvoke() { diff --git a/src/Microsoft.Diagnostics.ExtensionCommands/Output/Align.cs b/src/Microsoft.Diagnostics.ExtensionCommands/Output/Align.cs new file mode 100644 index 0000000000..bcd1a06974 --- /dev/null +++ b/src/Microsoft.Diagnostics.ExtensionCommands/Output/Align.cs @@ -0,0 +1,12 @@ +// 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.ExtensionCommands.Output +{ + internal enum Align + { + Left, + Right, + Center + } +} diff --git a/src/Microsoft.Diagnostics.ExtensionCommands/Output/BorderedTable.cs b/src/Microsoft.Diagnostics.ExtensionCommands/Output/BorderedTable.cs new file mode 100644 index 0000000000..f3a9015e8d --- /dev/null +++ b/src/Microsoft.Diagnostics.ExtensionCommands/Output/BorderedTable.cs @@ -0,0 +1,125 @@ +// 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.Text; +using Microsoft.Diagnostics.DebugServices; + +namespace Microsoft.Diagnostics.ExtensionCommands.Output +{ + internal sealed class BorderedTable : Table, IDisposable + { + private bool _wroteAtLeastOneSpacer; + + public BorderedTable(IConsoleService console, params Column[] columns) + : base(console, columns) + { + _spacing = $" | "; + } + + public void Dispose() + { + WriteSpacer(); + } + + public override void WriteHeader(params string[] values) + { + IncreaseColumnWidth(values); + + WriteSpacer(); + WriteHeaderFooter(values, writeSides: true, writeNewline: true); + WriteSpacer(); + } + + public override void WriteFooter(params object[] values) + { + WriteSpacer(); + WriteHeaderFooter(values, writeSides: true, writeNewline: true); + } + + public override void WriteRow(params object[] values) + { + // Ensure the top of the table is written even if there's no header/footer. + if (!_wroteAtLeastOneSpacer) + { + WriteSpacer(); + } + + StringBuilder rowBuilder = _stringBuilderPool.Rent(); + rowBuilder.Append(Indent); + rowBuilder.Append(_spacing); + + WriteRowWorker(values, rowBuilder, _spacing, writeLine: false); + rowBuilder.Append(_spacing); + + FinishColumns(values.Length, rowBuilder); + + Console.WriteLine(rowBuilder.ToString()); + _stringBuilderPool.Return(rowBuilder); + } + + protected override void WriteHeaderFooter(object[] values, bool writeSides, bool writeNewline) + { + base.WriteHeaderFooter(values, writeSides, writeNewline: false); + + StringBuilder rowBuilder = _stringBuilderPool.Rent(); + FinishColumns(values.Length, rowBuilder); + + if (writeNewline) + { + rowBuilder.AppendLine(); + } + + Console.Write(rowBuilder.ToString()); + _stringBuilderPool.Return(rowBuilder); + } + + private void FinishColumns(int start, StringBuilder rowBuilder) + { + for (int i = start; i < Columns.Length; i++) + { + if (Columns[i].Width < 0) + { + break; + } + + rowBuilder.Append(' ', Columns[i].Width); + rowBuilder.Append(_spacing); + } + } + + private void WriteSpacer() + { + WriteBorder(" +-", '-', "-+ "); + _wroteAtLeastOneSpacer = true; + } + + private void WriteBorder(string left, char center, string right) + { + StringBuilder rowBuilder = _stringBuilderPool.Rent(); + rowBuilder.Append(Indent); + + rowBuilder.Append(left); + + for (int i = 0; i < Columns.Length; i++) + { + if (i != 0) + { + rowBuilder.Append(center, _spacing.Length); + } + + if (Columns[i].Width < 0) + { + break; + } + + rowBuilder.Append(center, Columns[i].Width); + } + + rowBuilder.Append(right); + Console.WriteLine(rowBuilder.ToString()); + + _stringBuilderPool.Return(rowBuilder); + } + } +} diff --git a/src/Microsoft.Diagnostics.ExtensionCommands/Output/Column.cs b/src/Microsoft.Diagnostics.ExtensionCommands/Output/Column.cs new file mode 100644 index 0000000000..6c37a534e4 --- /dev/null +++ b/src/Microsoft.Diagnostics.ExtensionCommands/Output/Column.cs @@ -0,0 +1,80 @@ +// 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.Collections.Generic; +using System.Text; + +namespace Microsoft.Diagnostics.ExtensionCommands.Output +{ + internal readonly struct Column + { + private static readonly StringBuilderPool s_stringBuilderPool = new(); + private static readonly Column s_enum = new(Align.Left, -1, new(), null); + + public readonly int Width; + public readonly Format Format; + public readonly Align Alignment; + public readonly DmlFormat Dml; + + public Column(Align alignment, int width, Format format, DmlFormat dml = null) + { + Alignment = alignment; + Width = width; + Format = format ?? throw new ArgumentNullException(nameof(format)); + Dml = dml; + } + + public readonly Column WithWidth(int width) => new(Alignment, width, Format, Dml); + internal readonly Column WithDml(DmlFormat dml) => new(Alignment, Width, Format, dml); + internal readonly Column WithAlignment(Align align) => new(align, Width, Format, Dml); + + public readonly Column GetAppropriateWidth(IEnumerable values, int min = -1, int max = -1) + { + int len = 0; + + StringBuilder sb = s_stringBuilderPool.Rent(); + + foreach (T value in values) + { + sb.Clear(); + Format.FormatValue(sb, value, -1, false); + len = Math.Max(len, sb.Length); + } + + s_stringBuilderPool.Return(sb); + + if (len < min) + { + len = min; + } + + if (max > 0 && len > max) + { + len = max; + } + + return WithWidth(len); + } + + internal static Column ForEnum() + where TEnum : struct + { + int len = 0; + foreach (TEnum t in Enum.GetValues(typeof(TEnum))) + { + len = Math.Max(len, t.ToString().Length); + } + + return s_enum.WithWidth(len); + } + + public override string ToString() + { + string format = Format?.GetType().Name ?? "null"; + string dml = Dml?.GetType().Name ?? "null"; + + return $"align:{Alignment} width:{Width} format:{format} dml:{dml}"; + } + } +} diff --git a/src/Microsoft.Diagnostics.ExtensionCommands/Output/ColumnKind.cs b/src/Microsoft.Diagnostics.ExtensionCommands/Output/ColumnKind.cs new file mode 100644 index 0000000000..aeaae671c7 --- /dev/null +++ b/src/Microsoft.Diagnostics.ExtensionCommands/Output/ColumnKind.cs @@ -0,0 +1,112 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; + +namespace Microsoft.Diagnostics.ExtensionCommands.Output +{ + internal static class ColumnKind + { + private static Column? s_pointer; + private static Column? s_text; + private static Column? s_hexOffset; + private static Column? s_hexValue; + private static Column? s_dumpObj; + private static Column? s_integer; + private static Column? s_dumpHeapMT; + private static Column? s_listNearObj; + private static Column? s_dumpDomain; + private static Column? s_thread; + private static Column? s_integerWithoutComma; + private static Column? s_humanReadable; + private static Column? s_range; + + // NOTE/BUGBUG: This assumes IntPtr.Size matches the target process, which it should not do + private static int PointerLength => IntPtr.Size * 2; + + /// + /// A pointer, displayed as hex. + /// + public static Column Pointer => s_pointer ??= new(Align.Right, PointerLength, Formats.Pointer); + + /// + /// Raw text which will not be truncated by default. + /// + public static Column Text => s_text ??= new(Align.Left, -1, Formats.Text); + + /// + /// A hex value, prefixed with 0x. + /// + public static Column HexValue => s_hexValue ??= new(Align.Right, PointerLength + 2, Formats.HexValue); + + /// + /// An offset (potentially negative), prefixed with 0x. For example: '0x20' or '-0x20'. + /// + public static Column HexOffset => s_hexOffset ??= new(Align.Right, 10, Formats.HexOffset); + + /// + /// An integer, with commas. i.e. i.ToString("n0") + /// + public static Column Integer => s_integer ??= new(Align.Right, 14, Formats.Integer); + + /// + /// An integer, without commas. + /// + public static Column IntegerWithoutCommas => s_integerWithoutComma ??= new(Align.Right, 10, Formats.IntegerWithoutCommas); + + /// + /// A count of bytes (size). + /// + public static Column ByteCount => Integer; + + /// + /// A human readable size count. e.g. "1.23mb" + /// + public static Column HumanReadableSize => s_humanReadable ??= new(Align.Right, 12, Formats.HumanReadableSize); + + /// + /// An object pointer, which we would like to link to !do if Dml is enabled. + /// + public static Column DumpObj => s_dumpObj ??= new(Align.Right, PointerLength, Formats.Pointer, Dml.DumpObj); + + /// + /// A link to any number of ClrMD objects (ClrSubHeap, ClrSegment, a MethodTable or ClrType, etc) which will + /// print an appropriate !dumpheap filter for, if dml is enabled. + /// + public static Column DumpHeap => s_dumpHeapMT ??= new(Align.Right, PointerLength, Formats.Pointer, Dml.DumpHeap); + + /// + /// A link to !dumpdomain for the given domain, if dml is enabled. This also puts the domain's name in the + /// hover text for the link. + /// + public static Column DumpDomain => s_dumpDomain ??= new(Align.Right, PointerLength, Formats.Pointer, Dml.DumpDomain); + + /// + /// The ClrThread address with a link to the OSThreadID to change threads (if dml is enabled). + /// + public static Column Thread => s_thread ??= new(Align.Right, PointerLength, Formats.Pointer, Dml.Thread); + + /// + /// A link to !listnearobj for the given ClrObject or address, if dml is enabled. + /// + public static Column ListNearObj => s_listNearObj ??= new(Align.Right, PointerLength, Formats.Pointer, Dml.ListNearObj); + + /// + /// The name of a given type. Note that types are always truncated by removing the beginning of the type's + /// name instead of truncating based on alignment. This ensures the most important part of the name (the + /// actual type name) is preserved instead of the namespace. + /// + public static Column TypeName => s_text ??= new(Align.Left, -1, Formats.TypeName); + + /// + /// A path to an image on disk. Note that images are always truncted by removing the beginning of the image's + /// path instead of the end, preserving the filename. + /// + public static Column Image => s_text ??= new(Align.Left, -1, Formats.Image); + + /// + /// A MemoryRange printed as "[start-end]". + /// + public static Column Range => s_range ??= new(Align.Left, PointerLength * 2 + 1, Formats.Range); + } +} diff --git a/src/Microsoft.Diagnostics.ExtensionCommands/Output/Dml.cs b/src/Microsoft.Diagnostics.ExtensionCommands/Output/Dml.cs new file mode 100644 index 0000000000..e309f40ae0 --- /dev/null +++ b/src/Microsoft.Diagnostics.ExtensionCommands/Output/Dml.cs @@ -0,0 +1,306 @@ +// 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; +using System.Text; +using Microsoft.Diagnostics.Runtime; + +namespace Microsoft.Diagnostics.ExtensionCommands.Output +{ + internal static class Dml + { + private static DmlDumpObject s_dumpObj; + private static DmlDumpHeap s_dumpHeap; + private static DmlBold s_bold; + private static DmlListNearObj s_listNearObj; + private static DmlDumpDomain s_dumpDomain; + private static DmlThread s_thread; + + /// + /// Runs !dumpobj on the given pointer or ClrObject. If a ClrObject is invalid, + /// this will instead link to !verifyobj. + /// + public static DmlFormat DumpObj => s_dumpObj ??= new(); + + /// + /// Marks the output in bold. + /// + public static DmlFormat Bold => s_bold ??= new(); + + /// + /// Dumps the heap. If given a ClrSegment, ClrSubHeap, or MemoryRange it will + /// just dump that particular section of the heap. + /// + public static DmlFormat DumpHeap => s_dumpHeap ??= new(); + + /// + /// Runs ListNearObj on the given address or ClrObject. + /// + public static DmlFormat ListNearObj => s_listNearObj ??= new(); + + /// + /// Runs !dumpdomain on the given doman, additionally it will put the domain + /// name as the hover text. + /// + public static DmlFormat DumpDomain => s_dumpDomain ??= new(); + + /// + /// Changes the debugger to the given thread. + /// + public static DmlFormat Thread => s_thread ??= new(); + + private sealed class DmlBold : DmlFormat + { + public override void FormatValue(StringBuilder sb, string outputText, object value) + { + sb.Append(""); + sb.Append(DmlEscape(outputText)); + sb.Append(""); + } + } + + private abstract class DmlExec : DmlFormat + { + public override void FormatValue(StringBuilder sb, string outputText, object value) + { + string command = GetCommand(outputText, value); + if (string.IsNullOrWhiteSpace(command)) + { + sb.Append(DmlEscape(outputText)); + return; + } + + sb.Append("'); + sb.Append(DmlEscape(outputText)); + sb.Append(""); + } + + protected abstract string GetCommand(string outputText, object value); + protected virtual string GetAltText(string outputText, object value) => null; + + protected static bool IsNullOrZeroValue(object obj, out string value) + { + if (obj is null) + { + value = null; + return true; + } + else if (TryGetPointerValue(obj, out ulong ul) && ul == 0) + { + value = "0"; + return true; + } + + value = null; + return false; + } + + protected static bool TryGetPointerValue(object value, out ulong ulVal) + { + if (value is ulong ul) + { + ulVal = ul; + return true; + } + else if (value is nint ni) + { + unchecked + { + ulVal = (ulong)ni; + } + return true; + } + else if (value is nuint nuint) + { + ulVal = nuint; + return true; + } + + ulVal = 0; + return false; + } + } + + private sealed class DmlThread : DmlExec + { + protected override string GetCommand(string outputText, object value) + { + if (value is uint id) + { + return $"~~[{id:x}]s"; + } + + if (value is ClrThread thread) + { + return $"~~[{thread.OSThreadId:x}]s"; + } + + return null; + } + } + + private class DmlDumpObject : DmlExec + { + protected override string GetCommand(string outputText, object value) + { + bool isValid = true; + if (value is ClrObject obj) + { + isValid = obj.IsValid; + } + + value = Format.Unwrap(value); + if (IsNullOrZeroValue(value, out string result)) + { + return result; + } + + return isValid ? $"!dumpobj /d {value:x}" : $"!verifyobj {value:x}"; + } + + protected override string GetAltText(string outputText, object value) + { + if (value is ClrObject obj) + { + if (obj.IsValid) + { + return obj.Type?.Name; + } + + return "Invalid Object"; + } + + return null; + } + } + + private sealed class DmlListNearObj : DmlDumpObject + { + protected override string GetCommand(string outputText, object value) + { + value = Format.Unwrap(value); + if (IsNullOrZeroValue(value, out string result)) + { + return result; + } + + return $"!listnearobj {value:x}"; + } + } + + private sealed class DmlDumpHeap : DmlExec + { + protected override string GetCommand(string outputText, object value) + { + if (value is null) + { + return null; + } + + if (TryGetMethodTableOrTypeHandle(value, out ulong mtOrTh)) + { + // !dumpheap will only work on a method table + if ((mtOrTh & 2) == 2) + { + // Can't use typehandles + return null; + } + else if ((mtOrTh & 1) == 1) + { + // Clear mark bit + value = mtOrTh & ~1ul; + } + + if (mtOrTh == 0) + { + return null; + } + + return $"!dumpheap -mt {value:x}"; + } + + if (value is ClrSegment seg) + { + return $"!dumpheap -segment {seg.Address:x}"; + } + + if (value is MemoryRange range) + { + return $"!dumpheap {range.Start:x} {range.End:x}"; + } + + if (value is ClrSubHeap subHeap) + { + return $"!dumpheap -heap {subHeap.Index}"; + } + + Debug.Fail($"Unknown cannot use type {value.GetType().FullName} with DumpObj"); + return null; + } + + private static bool TryGetMethodTableOrTypeHandle(object value, out ulong mtOrTh) + { + if (TryGetPointerValue(value, out mtOrTh)) + { + return true; + } + + if (value is ClrType type) + { + mtOrTh = type.MethodTable; + return true; + } + + mtOrTh = 0; + return false; + } + + protected override string GetAltText(string outputText, object value) + { + if (value is ClrType type) + { + return type.Name; + } + + return null; + } + } + + private sealed class DmlDumpDomain : DmlExec + { + protected override string GetCommand(string outputText, object value) + { + value = Format.Unwrap(value); + if (IsNullOrZeroValue(value, out string result)) + { + return result; + } + + return $"!dumpdomain /d {value:x}"; + } + + protected override string GetAltText(string outputText, object value) + { + if (value is ClrAppDomain domain) + { + return domain.Name; + } + + return null; + } + } + } +} diff --git a/src/Microsoft.Diagnostics.ExtensionCommands/Output/DmlFormat.cs b/src/Microsoft.Diagnostics.ExtensionCommands/Output/DmlFormat.cs new file mode 100644 index 0000000000..07bb1c2c0d --- /dev/null +++ b/src/Microsoft.Diagnostics.ExtensionCommands/Output/DmlFormat.cs @@ -0,0 +1,36 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Text; +using System.Xml.Linq; + +namespace Microsoft.Diagnostics.ExtensionCommands.Output +{ + internal abstract class DmlFormat + { + // intentionally not shared with Format + private static readonly StringBuilderPool s_stringBuilderPool = new(); + + public virtual string FormatValue(string outputText, object value) + { + StringBuilder sb = s_stringBuilderPool.Rent(); + + FormatValue(sb, outputText, value); + string result = sb.ToString(); + s_stringBuilderPool.Return(sb); + return result; + } + + public abstract void FormatValue(StringBuilder sb, string outputText, object value); + + protected static string DmlEscape(string text) + { + if (string.IsNullOrWhiteSpace(text)) + { + return text; + } + + return new XText(text).ToString(); + } + } +} diff --git a/src/Microsoft.Diagnostics.ExtensionCommands/Output/Format.cs b/src/Microsoft.Diagnostics.ExtensionCommands/Output/Format.cs new file mode 100644 index 0000000000..1ed4a4e075 --- /dev/null +++ b/src/Microsoft.Diagnostics.ExtensionCommands/Output/Format.cs @@ -0,0 +1,130 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Diagnostics; +using System.Text; +using Microsoft.Diagnostics.Runtime; + +namespace Microsoft.Diagnostics.ExtensionCommands.Output +{ + internal class Format + { + private static StringBuilderPool s_stringBuilderPool = new(); + + /// + /// Returns true if a format of this type should never be truncated. If true, + /// DEBUG builds of SOS Assert.Fail if attempting to truncate the value of the + /// column. In release builds, we will simply not truncate the value, resulting + /// in a jagged looking table, but usable output. + /// + public bool CanTruncate { get; protected set; } + + public Format() { } + public Format(bool canTruncate) => CanTruncate = canTruncate; + + // Unwraps an object to get at what should be formatted. + internal static object Unwrap(object value) + { + return value switch + { + ClrObject obj => obj.Address, + ClrAppDomain domain => domain.Address, + ClrType type => type.MethodTable, + ClrSegment seg => seg.Address, + ClrThread thread => thread.Address, + ClrSubHeap subHeap => subHeap.Index, + _ => value + }; + } + + public virtual string FormatValue(object value, int maxLength, bool truncateBegin) + { + StringBuilder sb = s_stringBuilderPool.Rent(); + + FormatValue(sb, value, maxLength, truncateBegin); + string result = sb.ToString(); + + s_stringBuilderPool.Return(sb); + return TruncateString(result, maxLength, truncateBegin); + } + + public virtual int FormatValue(StringBuilder sb, object value, int maxLength, bool truncateBegin) + { + int currLength = sb.Length; + sb.Append(value); + TruncateStringBuilder(sb, maxLength, sb.Length - currLength, truncateBegin); + + return sb.Length - currLength; + } + + protected string TruncateString(string result, int maxLength, bool truncateBegin) + { + if (maxLength >= 0 && result.Length > maxLength) + { + if (CanTruncate) + { + if (maxLength <= 3) + { + result = new string('.', maxLength); + } + else if (truncateBegin) + { + result = "..." + result.Substring(result.Length - (maxLength - 3)); + } + else + { + result = result.Substring(0, maxLength - 3) + "..."; + } + } + else + { + Debug.Fail("Tried to truncate a column we should never truncate."); + } + } + + Debug.Assert(maxLength < 0 || result.Length <= maxLength); + return result; + } + + protected void TruncateStringBuilder(StringBuilder result, int maxLength, int lengthWritten, bool truncateBegin) + { + Debug.Assert(lengthWritten >= 0); + + if (maxLength >= 0 && lengthWritten > maxLength) + { + if (CanTruncate) + { + if (truncateBegin) + { + int start = result.Length - lengthWritten; + int wrote; + for (wrote = 0; wrote < 3 && wrote < maxLength; wrote++) + { + result[start + wrote] = '.'; + } + + int gap = lengthWritten - maxLength; + for (; wrote < maxLength; wrote++) + { + result[start + wrote] = result[start + wrote + gap]; + } + + result.Length = start + maxLength; + } + else + { + result.Length = result.Length - lengthWritten + maxLength; + for (int i = 0; i < maxLength && i < 3; i++) + { + result[result.Length - i - 1] = '.'; + } + } + } + else + { + Debug.Fail("Tried to truncate a column we should never truncate."); + } + } + } + } +} diff --git a/src/Microsoft.Diagnostics.ExtensionCommands/Output/Formats.cs b/src/Microsoft.Diagnostics.ExtensionCommands/Output/Formats.cs new file mode 100644 index 0000000000..2ef5090eea --- /dev/null +++ b/src/Microsoft.Diagnostics.ExtensionCommands/Output/Formats.cs @@ -0,0 +1,244 @@ +// 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.Collections.Generic; +using System.Linq; +using System.Text; +using Microsoft.Diagnostics.Runtime; + +namespace Microsoft.Diagnostics.ExtensionCommands.Output +{ + internal static class Formats + { + private static HexValueFormat s_hexOffsetFormat; + private static HexValueFormat s_hexValueFormat; + private static Format s_text; + private static IntegerFormat s_integerFormat; + private static TypeOrImageFormat s_typeNameFormat; + private static TypeOrImageFormat s_imageFormat; + private static IntegerFormat s_integerWithoutCommaFormat; + private static HumanReadableFormat s_humanReadableFormat; + private static RangeFormat s_range; + + static Formats() + { + int pointerSize = IntPtr.Size; + Pointer = new IntegerFormat(pointerSize == 4 ? "x8" : "x12"); + } + + public static Format Pointer { get; } + + public static Format HexOffset => s_hexOffsetFormat ??= new(printPrefix: true, signed: true); + public static Format HexValue => s_hexValueFormat ??= new(printPrefix: true, signed: false); + public static Format Integer => s_integerFormat ??= new("n0"); + public static Format IntegerWithoutCommas => s_integerWithoutCommaFormat ??= new(""); + public static Format Text => s_text ??= new(true); + public static Format TypeName => s_typeNameFormat ??= new(type: true); + public static Format Image => s_imageFormat ??= new(type: false); + public static Format HumanReadableSize => s_humanReadableFormat ??= new(); + public static Format Range => s_range ??= new(); + + private sealed class IntegerFormat : Format + { + private readonly string _format; + + public IntegerFormat(string format) + { + _format = "{0:" + format + "}"; + } + + public override int FormatValue(StringBuilder result, object value, int maxLength, bool truncateBegin) + { + value = Unwrap(value); + + int startLength = result.Length; + switch (value) + { + case null: + break; + + default: + result.AppendFormat(_format, value); + break; + } + + TruncateStringBuilder(result, maxLength, result.Length - startLength, truncateBegin); + return result.Length - startLength; + } + } + + /// + /// Unlike plain text, this Format always truncates the beginning of the type name or image path, + /// as the most important part is at the end. + /// + private sealed class TypeOrImageFormat : Format + { + private const string UnknownTypeName = "Unknown"; + private readonly bool _type; + + public TypeOrImageFormat(bool type) + : base(canTruncate: true) + { + _type = type; + } + + public override int FormatValue(StringBuilder sb, object value, int maxLength, bool truncateBegin) + { + int startLength = sb.Length; + + if (!_type) + { + sb.Append(value); + } + else + { + if (value is null) + { + sb.Append(UnknownTypeName); + } + else if (value is ClrType type) + { + string typeName = type.Name; + if (!string.IsNullOrWhiteSpace(typeName)) + { + sb.Append(typeName); + } + else + { + string module = type.Module?.Name; + if (!string.IsNullOrWhiteSpace(module)) + { + try + { + module = System.IO.Path.GetFileNameWithoutExtension(module); + sb.Append(module); + sb.Append('!'); + } + catch (ArgumentException) + { + } + } + + sb.Append(UnknownTypeName); + if (type.MethodTable != 0) + { + sb.Append($" (MethodTable: "); + sb.AppendFormat("{0:x12}", type.MethodTable); + sb.Append(')'); + } + } + } + else + { + sb.Append(value); + } + } + + TruncateStringBuilder(sb, maxLength, sb.Length - startLength, truncateBegin: true); + return sb.Length - startLength; + } + } + + private sealed class HumanReadableFormat : Format + { + public override int FormatValue(StringBuilder sb, object value, int maxLength, bool truncateBegin) + { + string humanReadable = value switch + { + null => null, + int i => ((long)i).ConvertToHumanReadable(), + uint ui => ((ulong)ui).ConvertToHumanReadable(), + long l => l.ConvertToHumanReadable(), + ulong ul => ul.ConvertToHumanReadable(), + float f => ((double)f).ConvertToHumanReadable(), + double d => d.ConvertToHumanReadable(), + nuint nu => ((ulong)nu).ConvertToHumanReadable(), + nint ni => ((long)ni).ConvertToHumanReadable(), + string s => s, + _ => throw new NotSupportedException($"Cannot convert '{value.GetType().FullName}' to a human readable size.") + }; + + if (!string.IsNullOrWhiteSpace(humanReadable)) + { + return base.FormatValue(sb, humanReadable, maxLength, truncateBegin); + } + + return 0; + } + } + + private sealed class HexValueFormat : Format + { + public bool PrintPrefix { get; } + public bool Signed { get; } + + public HexValueFormat(bool printPrefix, bool signed) + { + PrintPrefix = printPrefix; + Signed = signed; + } + + private string GetStringValue(long offset) + { + if (Signed) + { + if (PrintPrefix) + { + return offset < 0 ? $"-0x{Math.Abs(offset):x2}" : $"0x{offset:x2}"; + } + else + { + return offset < 0 ? $"-{Math.Abs(offset):x2}" : $"{offset:x2}"; + } + } + + return PrintPrefix ? $"0x{offset:x2}" : offset.ToString("x2"); + } + + private string GetHexOffsetString(object value) + { + return value switch + { + null => "", + string s => s, + nint ni => GetStringValue(ni), + nuint nui => PrintPrefix ? $"0x{nui:x2}" : "{nui:x2}", + ulong ul => PrintPrefix ? $"0x{ul:x2}" : ul.ToString("x2"), + long l => GetStringValue(l), + int i => GetStringValue(i), + uint u => PrintPrefix ? $"0x{u:x2}" : u.ToString("x2"), + IEnumerable bytes => (PrintPrefix ? "0x" : "") + string.Join("", bytes.Select(b => b.ToString("x2"))), + _ => throw new InvalidOperationException($"Cannot convert value of type {value.GetType().FullName} to a HexOffset") + }; + } + + public override int FormatValue(StringBuilder sb, object value, int maxLength, bool truncateBegin) + { + int startLength = sb.Length; + sb.Append(GetHexOffsetString(value)); + TruncateStringBuilder(sb, maxLength, sb.Length - startLength, truncateBegin); + + return sb.Length - startLength; + } + } + + private sealed class RangeFormat : Format + { + public override int FormatValue(StringBuilder sb, object value, int maxLength, bool truncateBegin) + { + int startLength = sb.Length; + if (value is MemoryRange range) + { + sb.AppendFormat("{0:x}", range.Start); + sb.Append('-'); + sb.AppendFormat("{0:x}", range.End); + + return sb.Length - startLength; + } + + return base.FormatValue(sb, value, maxLength, truncateBegin); + } + } + } +} diff --git a/src/Microsoft.Diagnostics.ExtensionCommands/Output/StringBuilderPool.cs b/src/Microsoft.Diagnostics.ExtensionCommands/Output/StringBuilderPool.cs new file mode 100644 index 0000000000..902ab05116 --- /dev/null +++ b/src/Microsoft.Diagnostics.ExtensionCommands/Output/StringBuilderPool.cs @@ -0,0 +1,45 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Text; + +namespace Microsoft.Diagnostics.ExtensionCommands.Output +{ + internal sealed class StringBuilderPool + { + private StringBuilder _stringBuilder; + private readonly int _initialCapacity; + + public StringBuilderPool(int initialCapacity = 64) + { + _initialCapacity = initialCapacity > 0 ? initialCapacity : 0; + } + + // This code all assumes SOS runs single threaded. We would want to change this + // code to use Interlocked.Exchange if that ever changes. + public StringBuilder Rent() + { + StringBuilder sb = _stringBuilder; + _stringBuilder = null; + + if (sb is null) + { + sb = new StringBuilder(_initialCapacity); + } + else + { + sb.Clear(); + } + + return sb; + } + + public void Return(StringBuilder sb) + { + if (sb.Capacity < 1024) + { + _stringBuilder = sb; + } + } + } +} diff --git a/src/Microsoft.Diagnostics.ExtensionCommands/Output/Table.cs b/src/Microsoft.Diagnostics.ExtensionCommands/Output/Table.cs new file mode 100644 index 0000000000..71bcddc9dc --- /dev/null +++ b/src/Microsoft.Diagnostics.ExtensionCommands/Output/Table.cs @@ -0,0 +1,240 @@ +// 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; +using System.Linq; +using System.Text; +using Microsoft.Diagnostics.DebugServices; + +namespace Microsoft.Diagnostics.ExtensionCommands.Output +{ + internal class Table + { + protected readonly StringBuilderPool _stringBuilderPool = new(); + protected string _spacing = " "; + protected static readonly Column s_headerColumn = new(Align.Center, -1, Formats.Text, Dml.Bold); + + public string Indent { get; set; } = ""; + + public IConsoleService Console { get; } + + public int TotalWidth => 1 * (Columns.Length - 1) + Columns.Sum(c => Math.Abs(c.Width)); + + public Column[] Columns { get; set; } + + public Table(IConsoleService console, params Column[] columns) + { + Columns = columns.ToArray(); + Console = console; + } + + public void SetAlignment(Align align) + { + for (int i = 0; i < Columns.Length; i++) + { + Columns[i] = Columns[i].WithAlignment(align); + } + } + + public virtual void WriteHeader(params string[] values) + { + IncreaseColumnWidth(values); + WriteHeaderFooter(values); + } + + public virtual void WriteFooter(params object[] values) + { + WriteHeaderFooter(values); + } + + protected void IncreaseColumnWidth(string[] values) + { + // Increase column width if too small + for (int i = 0; i < Columns.Length && i < values.Length; i++) + { + if (Columns.Length >= 0 && values[i].Length > Columns.Length) + { + if (Columns[i].Width != -1 && Columns[i].Width < values[i].Length) + { + Columns[i] = Columns[i].WithWidth(values[i].Length); + } + } + } + } + + public virtual void WriteRow(params object[] values) + { + StringBuilder rowBuilder = _stringBuilderPool.Rent(); + rowBuilder.Append(Indent); + + WriteRowWorker(values, rowBuilder, _spacing); + + _stringBuilderPool.Return(rowBuilder); + } + + protected void WriteRowWorker(object[] values, StringBuilder rowBuilder, string spacing, bool writeLine = true) + { + bool isRowBuilderDml = false; + + for (int i = 0; i < values.Length; i++) + { + if (i != 0) + { + rowBuilder.Append(spacing); + } + + Column column = i < Columns.Length ? Columns[i] : ColumnKind.Text; + + bool isColumnDml = Console.SupportsDml && column.Dml is not null; + if (isRowBuilderDml != isColumnDml) + { + WriteAndClearRowBuilder(rowBuilder, isRowBuilderDml); + isRowBuilderDml = isColumnDml; + } + + Append(column, rowBuilder, values[i]); + } + + if (writeLine) + { + rowBuilder.AppendLine(); + } + + WriteAndClearRowBuilder(rowBuilder, isRowBuilderDml); + } + + private void WriteAndClearRowBuilder(StringBuilder rowBuilder, bool dml) + { + if (rowBuilder.Length != 0) + { + if (dml) + { + Console.WriteDml(rowBuilder.ToString()); + } + else + { + Console.Write(rowBuilder.ToString()); + } + + rowBuilder.Clear(); + } + } + + private void Append(Column column, StringBuilder sb, object value) + { + DmlFormat dml = null; + if (Console.SupportsDml) + { + dml = column.Dml; + } + + // Efficient case + if (dml is null && column.Alignment == Align.Left) + { + int written = column.Format.FormatValue(sb, value, column.Width, column.Alignment == Align.Left); + Debug.Assert(written >= 0); + if (written < column.Width) + { + sb.Append(' ', column.Width - written); + } + + return; + } + + string toWrite = column.Format.FormatValue(value, column.Width, column.Alignment == Align.Left); + int displayLength = toWrite.Length; + if (dml is not null) + { + toWrite = dml.FormatValue(toWrite, value); + } + + if (column.Width < 0) + { + sb.Append(toWrite); + } + else + { + if (column.Alignment == Align.Left) + { + sb.Append(toWrite); + if (displayLength < column.Width) + { + sb.Append(' ', column.Width - displayLength); + } + + return; + } + else if (column.Alignment == Align.Right) + { + sb.Append(' ', column.Width - displayLength); + sb.Append(toWrite); + } + else + { + Debug.Assert(column.Alignment == Align.Center); + + int remainder = column.Width - displayLength; + int right = remainder >> 1; + int left = right + (remainder % 2); + + sb.Append(' ', left); + sb.Append(toWrite); + sb.Append(' ', right); + } + } + } + + protected virtual void WriteHeaderFooter(object[] values, bool writeSides = false, bool writeNewline = true) + { + StringBuilder rowBuilder = _stringBuilderPool.Rent(); + rowBuilder.Append(Indent); + + if (writeSides) + { + rowBuilder.Append(_spacing); + } + + for (int i = 0; i < values.Length; i++) + { + if (i != 0) + { + rowBuilder.Append(_spacing); + } + + Column curr = i < Columns.Length ? Columns[i] : s_headerColumn; + if (Console.SupportsDml) + { + curr = curr.WithDml(Dml.Bold); + } + else + { + curr = curr.WithDml(null); + } + + Append(curr, rowBuilder, values[i]); + } + + if (writeSides) + { + rowBuilder.Append(_spacing); + } + + if (writeNewline) + { + rowBuilder.AppendLine(); + } + + if (Console.SupportsDml) + { + Console.WriteDml(rowBuilder.ToString()); + } + else + { + Console.Write(rowBuilder.ToString()); + } + + _stringBuilderPool.Return(rowBuilder); + } + } +} diff --git a/src/Microsoft.Diagnostics.ExtensionCommands/SimulateGCHeapCorruption.cs b/src/Microsoft.Diagnostics.ExtensionCommands/SimulateGCHeapCorruption.cs index 2158d8ead6..2105875b9d 100644 --- a/src/Microsoft.Diagnostics.ExtensionCommands/SimulateGCHeapCorruption.cs +++ b/src/Microsoft.Diagnostics.ExtensionCommands/SimulateGCHeapCorruption.cs @@ -5,9 +5,10 @@ using System.Collections.Generic; using System.Linq; using Microsoft.Diagnostics.DebugServices; +using Microsoft.Diagnostics.ExtensionCommands.Output; using Microsoft.Diagnostics.Runtime; -using static Microsoft.Diagnostics.ExtensionCommands.TableOutput; +using static Microsoft.Diagnostics.ExtensionCommands.Output.ColumnKind; namespace Microsoft.Diagnostics.ExtensionCommands { @@ -59,12 +60,12 @@ private void List() } else { - TableOutput output = new(Console, (12, "x12"), (12, "x12"), (16, "x"), (16, "x"), (0, "")); - output.WriteRow("Object", "ModifiedAddr", "Old Value", "New Value", "Expected Failure"); + Table output = new(Console, DumpObj, Pointer, HexValue, HexValue, Text); + output.WriteHeader("Object", "ModifiedAddr", "Old Value", "New Value", "Expected Failure"); foreach (Change change in _changes) { - output.WriteRow(new DmlDumpObj(change.Object), change.AddressModified, change.OriginalValue.Reverse(), change.NewValue.Reverse(), change.ExpectedFailure); + output.WriteRow(change.Object, change.AddressModified, change.OriginalValue.Reverse(), change.NewValue.Reverse(), change.ExpectedFailure); } } @@ -120,7 +121,7 @@ private void Corrupt() ClrObject[] withRefs = FindObjectsWithReferences().Take(3).ToArray(); if (withRefs.Length >= 1) { - (ulong Object, ulong FirstReference) entry = GetFirstReference(withRefs[0]); + (ClrObject Object, ulong FirstReference) entry = GetFirstReference(withRefs[0]); WriteValue(ObjectCorruptionKind.InvalidObjectReference, entry.Object, entry.FirstReference, 0xcccccccc); } if (withRefs.Length >= 2) @@ -128,13 +129,13 @@ private void Corrupt() ulong free = Runtime.Heap.EnumerateObjects().FirstOrDefault(f => f.IsFree); if (free != 0) { - (ulong Object, ulong FirstReference) entry = GetFirstReference(withRefs[1]); + (ClrObject Object, ulong FirstReference) entry = GetFirstReference(withRefs[1]); WriteValue(ObjectCorruptionKind.FreeObjectReference, entry.Object, entry.FirstReference, free); } } if (withRefs.Length >= 3) { - (ulong Object, ulong FirstReference) entry = GetFirstReference(withRefs[2]); + (ClrObject Object, ulong FirstReference) entry = GetFirstReference(withRefs[2]); WriteValue(ObjectCorruptionKind.ObjectReferenceNotPointerAligned, entry.Object, entry.FirstReference, (byte)1); } @@ -152,7 +153,7 @@ private void Corrupt() List(); } - private static (ulong Object, ulong FirstReference) GetFirstReference(ClrObject obj) + private static (ClrObject Object, ulong FirstReference) GetFirstReference(ClrObject obj) { return (obj, obj.EnumerateReferenceAddresses().First()); } @@ -217,7 +218,7 @@ private IEnumerable FindArrayObjects() } } - private unsafe void WriteValue(ObjectCorruptionKind kind, ulong obj, ulong address, T value) + private unsafe void WriteValue(ObjectCorruptionKind kind, ClrObject obj, ulong address, T value) where T : unmanaged { byte[] old = new byte[sizeof(T)]; @@ -246,7 +247,7 @@ private unsafe void WriteValue(ObjectCorruptionKind kind, ulong obj, ulong ad private sealed class Change { - public ulong Object { get; set; } + public ClrObject Object { get; set; } public ulong AddressModified { get; set; } public byte[] OriginalValue { get; set; } public byte[] NewValue { get; set; } diff --git a/src/Microsoft.Diagnostics.ExtensionCommands/SizeStatsCommand.cs b/src/Microsoft.Diagnostics.ExtensionCommands/SizeStatsCommand.cs index 5208edaa48..b8f67a7a5f 100644 --- a/src/Microsoft.Diagnostics.ExtensionCommands/SizeStatsCommand.cs +++ b/src/Microsoft.Diagnostics.ExtensionCommands/SizeStatsCommand.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Linq; using Microsoft.Diagnostics.DebugServices; +using Microsoft.Diagnostics.ExtensionCommands.Output; using Microsoft.Diagnostics.Runtime; namespace Microsoft.Diagnostics.ExtensionCommands @@ -78,23 +79,32 @@ private void SizeStats(Generation requestedGen, bool isFree) Console.WriteLine($"Size Statistics for {requestedGen.ToString().ToLowerInvariant()} {freeStr}objects"); Console.WriteLine(); - TableOutput output = new(Console, (16, "n0"), (16, "n0"), (16, "n0"), (16, "n0")); - output.WriteRow("Size", "Count", "Cumulative Size", "Cumulative Count"); - - IEnumerable<(ulong Size, ulong Count)> sorted = from i in stats orderby i.Key ascending select (i.Key, i.Value); ulong cumulativeSize = 0; ulong cumulativeCount = 0; + Table output = null; foreach ((ulong size, ulong count) in sorted) { Console.CancellationToken.ThrowIfCancellationRequested(); + if (output is null) + { + output = new(Console, ColumnKind.ByteCount, ColumnKind.Integer, ColumnKind.Integer, ColumnKind.Integer); + output.WriteHeader("Size", "Count", "Cumulative Size", "Cumulative Count"); + } + + output.WriteRow(size, count, cumulativeSize, cumulativeCount); + cumulativeSize += size * count; cumulativeCount += count; - output.WriteRow(size, count, cumulativeSize, cumulativeCount); + } + + if (output is null) + { + Console.WriteLine("(none)"); } Console.WriteLine(); diff --git a/src/Microsoft.Diagnostics.ExtensionCommands/TableOutput.cs b/src/Microsoft.Diagnostics.ExtensionCommands/TableOutput.cs deleted file mode 100644 index 3037306841..0000000000 --- a/src/Microsoft.Diagnostics.ExtensionCommands/TableOutput.cs +++ /dev/null @@ -1,311 +0,0 @@ -// 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.Collections.Generic; -using System.Linq; -using System.Text; -using Microsoft.Diagnostics.DebugServices; -using Microsoft.Diagnostics.Runtime; - -namespace Microsoft.Diagnostics.ExtensionCommands -{ - internal sealed class TableOutput - { - private readonly StringBuilder _rowBuilder = new(260); - private readonly char _spacing = ' '; - - public string Divider { get; set; } = " "; - - public string Indent { get; set; } = ""; - - public bool AlignLeft { get; set; } - - public int ColumnCount => _formats.Length; - - public IConsoleService Console { get; } - - public int TotalWidth => 1 * (_formats.Length - 1) + _formats.Sum(c => Math.Abs(c.width)); - - private readonly (int width, string format)[] _formats; - - public TableOutput(IConsoleService console, params (int width, string format)[] columns) - { - _formats = columns.ToArray(); - Console = console; - } - - public void WriteSpacer(char spacer) - { - Console.WriteLine(new string(spacer, Divider.Length * (_formats.Length - 1) + _formats.Sum(c => Math.Abs(c.width)))); - } - - public void WriteRow(params object[] columns) - { - _rowBuilder.Clear(); - _rowBuilder.Append(Indent); - - for (int i = 0; i < columns.Length; i++) - { - if (i != 0) - { - _rowBuilder.Append(_spacing); - } - - (int width, string format) = i < _formats.Length ? _formats[i] : default; - FormatColumn(_spacing, columns[i], _rowBuilder, width, format); - } - - Console.WriteLine(_rowBuilder.ToString()); - } - - public void WriteRowWithSpacing(char spacing, params object[] columns) - { - _rowBuilder.Clear(); - _rowBuilder.Append(Indent); - - for (int i = 0; i < columns.Length; i++) - { - if (i != 0) - { - _rowBuilder.Append(spacing, Divider.Length); - } - - (int width, string format) = i < _formats.Length ? _formats[i] : default; - - FormatColumn(spacing, columns[i], _rowBuilder, width, format); - } - - Console.WriteLine(_rowBuilder.ToString()); - } - - private void FormatColumn(char spacing, object value, StringBuilder sb, int width, string format) - { - string action = null; - string text; - if (value is DmlExec dml) - { - value = dml.Text; - if (Console.SupportsDml) - { - action = dml.Action; - } - } - - if (string.IsNullOrWhiteSpace(format)) - { - text = value?.ToString(); - } - else - { - text = Format(value, format); - } - - AddValue(spacing, sb, width, text ?? "", action); - } - - private void AddValue(char spacing, StringBuilder sb, int width, string value, string action) - { - bool leftAlign = AlignLeft ? width > 0 : width < 0; - width = Math.Abs(width); - - if (width == 0) - { - if (string.IsNullOrWhiteSpace(action)) - { - sb.Append(value); - } - else - { - WriteAndClear(sb); - Console.WriteDmlExec(value, action); - } - } - else if (value.Length > width) - { - if (!string.IsNullOrWhiteSpace(action)) - { - WriteAndClear(sb); - } - - if (width <= 3) - { - sb.Append(value, 0, width); - } - else if (leftAlign) - { - value = value.Substring(0, width - 3); - sb.Append(value); - sb.Append("..."); - } - else - { - value = value.Substring(value.Length - (width - 3)); - sb.Append("..."); - sb.Append(value); - } - - if (!string.IsNullOrWhiteSpace(action)) - { - WriteDmlExecAndClear(sb, action); - } - } - else if (leftAlign) - { - if (!string.IsNullOrWhiteSpace(action)) - { - WriteAndClear(sb); - Console.WriteDmlExec(value, action); - } - else - { - sb.Append(value); - } - - int remaining = width - value.Length; - if (remaining > 0) - { - sb.Append(spacing, remaining); - } - } - else - { - int remaining = width - value.Length; - if (remaining > 0) - { - sb.Append(spacing, remaining); - } - - if (!string.IsNullOrWhiteSpace(action)) - { - WriteAndClear(sb); - Console.WriteDmlExec(value, action); - } - else - { - sb.Append(value); - } - } - } - - private void WriteDmlExecAndClear(StringBuilder sb, string action) - { - Console.WriteDmlExec(sb.ToString(), action); - sb.Clear(); - } - - private void WriteAndClear(StringBuilder sb) - { - Console.Write(sb.ToString()); - sb.Clear(); - } - - private static string Format(object obj, string format) - { - if (obj is null) - { - return null; - } - - if (obj is Enum) - { - return obj.ToString(); - } - - return obj switch - { - nint ni => ni.ToString(format), - ulong ul => ul.ToString(format), - long l => l.ToString(format), - uint ui => ui.ToString(format), - int i => i.ToString(format), - nuint uni => ((ulong)uni).ToString(format), - StringBuilder sb => sb.ToString(), - IEnumerable bytes => string.Join("", bytes.Select(b => b.ToString("x2"))), - string s => s, - _ => throw new NotImplementedException(obj.GetType().ToString()), - }; - } - - public class DmlExec - { - public object Text { get; } - public string Action { get; } - - public DmlExec(object text, string action) - { - Text = text; - Action = action; - } - } - - public sealed class DmlDumpObj : DmlExec - { - public DmlDumpObj(ulong address) - : base(address, address != 0 ? $"!dumpobj /d {address:x}" : "") - { - } - } - - public sealed class DmlDumpMT : DmlExec - { - public DmlDumpMT(ulong address) - : base(address, address != 0 ? $"!dumpmt /d {address:x}" : "") - { - } - } - - public sealed class DmlDumpDomain : DmlExec - { - public DmlDumpDomain(ulong address) - : base(address, address != 0 ? $"!dumpdomain /d {address:x}" : "") - { - } - } - - public sealed class DmlListNearObj : DmlExec - { - public DmlListNearObj(ulong address) - : base(address, address != 0 ? $"!sos listnearobj {address:x}" : "") - { - } - } - - public sealed class DmlVerifyObj : DmlExec - { - public DmlVerifyObj(ulong address) - : base(address, address != 0 ? $"!verifyobj /d {address:x}" : "") - { - } - } - - public sealed class DmlDumpHeap : DmlExec - { - public DmlDumpHeap(string text, MemoryRange range) - : base(text, $"!dumpheap {range.Start:x} {range.End:x}") - { - } - - public DmlDumpHeap(ulong methodTable) - : base (methodTable, methodTable != 0 ? $"!dumpheap -mt {methodTable:x}" : "") - { - } - } - - public sealed class DmlVerifyHeap : DmlExec - { - public DmlVerifyHeap(string text, ClrSegment what) - : base(text, $"!verifyheap -segment {what.Address}") - { - } - } - - public sealed class DmlDumpHeapSegment : DmlExec - { - public DmlDumpHeapSegment(ClrSegment seg) - : base(seg?.Address ?? 0, seg != null ? $"!dumpheap -segment {seg.Address:x}" : "") - { - } - } - } -} diff --git a/src/Microsoft.Diagnostics.ExtensionCommands/ThreadPoolCommand.cs b/src/Microsoft.Diagnostics.ExtensionCommands/ThreadPoolCommand.cs index 8736bcc4fb..85f7c4d973 100644 --- a/src/Microsoft.Diagnostics.ExtensionCommands/ThreadPoolCommand.cs +++ b/src/Microsoft.Diagnostics.ExtensionCommands/ThreadPoolCommand.cs @@ -5,8 +5,9 @@ using System.Collections.Generic; using System.Linq; using Microsoft.Diagnostics.DebugServices; +using Microsoft.Diagnostics.ExtensionCommands.Output; using Microsoft.Diagnostics.Runtime; -using static Microsoft.Diagnostics.ExtensionCommands.TableOutput; +using static Microsoft.Diagnostics.ExtensionCommands.Output.ColumnKind; namespace Microsoft.Diagnostics.ExtensionCommands { @@ -32,7 +33,7 @@ public override void Invoke() } else { - TableOutput output = new(Console, (17, "")); + Table output = new(Console, Text.WithWidth(17), Text); output.WriteRow("CPU utilization:", $"{threadPool.CpuUtilization}%"); output.WriteRow("Workers Total:", threadPool.ActiveWorkerThreads + threadPool.IdleWorkerThreads + threadPool.RetiredWorkerThreads); output.WriteRow("Workers Running:", threadPool.ActiveWorkerThreads); @@ -72,10 +73,12 @@ public override void Invoke() bool usingPortableCompletionPorts = threadPool.Portable && (usePortableIOField is null || usePortableIOField.Read(usePortableIOField.Type.Module.AppDomain)); if (!usingPortableCompletionPorts) { - output = new(Console, (17, "")); + output.Columns[0] = output.Columns[0].WithWidth(19); output.WriteRow("Completion Total:", threadPool.TotalCompletionPorts); output.WriteRow("Completion Free:", threadPool.FreeCompletionPorts); output.WriteRow("Completion MaxFree:", threadPool.MaxFreeCompletionPorts); + + output.Columns[0] = output.Columns[0].WithWidth(25); output.WriteRow("Completion Current Limit:", threadPool.CompletionPortCurrentLimit); output.WriteRow("Completion Min Limit:", threadPool.MinCompletionPorts); output.WriteRow("Completion Max Limit:", threadPool.MaxCompletionPorts); @@ -87,10 +90,10 @@ public override void Invoke() HillClimbingLogEntry[] hcl = threadPool.EnumerateHillClimbingLog().ToArray(); if (hcl.Length > 0) { - output = new(Console, (10, ""), (19, ""), (12, "n0"), (12, "n0")); + output = new(Console, Text.WithWidth(10).WithAlignment(Align.Right), Column.ForEnum(), Integer, Integer, Text.WithAlignment(Align.Right)); Console.WriteLine("Hill Climbing Log:"); - output.WriteRow("Time", "Transition", "#New Threads", "#Samples", "Throughput"); + output.WriteHeader("Time", "Transition", "#New Threads", "#Samples", "Throughput"); int end = hcl.Last().TickCount; foreach (HillClimbingLogEntry entry in hcl) @@ -113,7 +116,7 @@ public override void Invoke() private void DumpWorkItems() { - TableOutput output = null; + Table output = null; ClrType workQueueType = Runtime.BaseClassLibrary.GetTypeByName("System.Threading.ThreadPoolWorkQueue"); ClrType workStealingQueueType = Runtime.BaseClassLibrary.GetTypeByName("System.Threading.ThreadPoolWorkQueue+WorkStealingQueue"); @@ -178,19 +181,16 @@ private void DumpWorkItems() } } - private void WriteEntry(ref TableOutput output, ClrObject entry, bool isHighPri) + private void WriteEntry(ref Table output, ClrObject entry, bool isHighPri) { if (output is null) { - output = new(Console, (17, ""), (16, "x12")) - { - AlignLeft = true, - }; - - output.WriteRow("Queue", "Object", "Type"); + output = new(Console, Text.WithWidth(17), DumpObj, TypeName); + output.SetAlignment(Align.Left); + output.WriteHeader("Queue", "Object", "Type"); } - output.WriteRow(isHighPri ? "[Global high-pri]" : "[Global]", new DmlDumpObj(entry), entry.Type?.Name); + output.WriteRow(isHighPri ? "[Global high-pri]" : "[Global]", entry, entry.Type); if (entry.IsDelegate) { ClrDelegate del = entry.AsDelegate(); @@ -230,11 +230,17 @@ private IEnumerable EnumerateConcurrentQueue(ClrObject concurrentQueu } } - if (!curr.TryReadObjectField("_nextSegment", out curr)) + if (!curr.TryReadObjectField("_nextSegment", out ClrObject next)) { - Console.WriteLineError($"Error: Type '{slots.Type?.Name}' does not contain a '_nextSegment' field."); + if (curr.Type is not null && curr.Type.GetFieldByName("_nextSegment") == null) + { + Console.WriteLineError($"Error: Type '{curr.Type?.Name}' does not contain a '_nextSegment' field."); + } + break; } + + curr = next; } } } diff --git a/src/Microsoft.Diagnostics.ExtensionCommands/VerifyHeapCommand.cs b/src/Microsoft.Diagnostics.ExtensionCommands/VerifyHeapCommand.cs index e866709598..e5229cbf32 100644 --- a/src/Microsoft.Diagnostics.ExtensionCommands/VerifyHeapCommand.cs +++ b/src/Microsoft.Diagnostics.ExtensionCommands/VerifyHeapCommand.cs @@ -1,12 +1,11 @@ // 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.Collections.Generic; using System.Diagnostics; -using System.Linq; using Microsoft.Diagnostics.DebugServices; +using Microsoft.Diagnostics.ExtensionCommands.Output; using Microsoft.Diagnostics.Runtime; -using static Microsoft.Diagnostics.ExtensionCommands.TableOutput; +using static Microsoft.Diagnostics.ExtensionCommands.Output.ColumnKind; namespace Microsoft.Diagnostics.ExtensionCommands { @@ -69,7 +68,7 @@ private void VerifyHeap(IEnumerable objects, bool verifySyncTable) objects = EnumerateWithCount(objects); int errors = 0; - TableOutput output = null; + Table output = null; ClrHeap heap = Runtime.Heap; // Verify heap @@ -128,7 +127,7 @@ private void VerifyHeap(IEnumerable objects, bool verifySyncTable) } } - private void WriteError(ref TableOutput output, ClrHeap heap, ObjectCorruption corruption) + private void WriteError(ref Table output, ClrHeap heap, ObjectCorruption corruption) { string message = GetObjectCorruptionMessage(MemoryService, heap, corruption); WriteRow(ref output, heap, corruption, message); @@ -145,7 +144,7 @@ internal static string GetObjectCorruptionMessage(IMemoryService memory, ClrHeap ObjectCorruptionKind.ObjectNotPointerAligned => $"Object {obj.Address:x} is not pointer aligned", // Object failures - ObjectCorruptionKind.ObjectTooLarge => $"Object {obj.Address:x} is too large, size={obj.Size:x}, segmentEnd: {ValueWithError(heap.GetSegmentByAddress(obj)?.End)}", + ObjectCorruptionKind.ObjectTooLarge => $"Object {obj.Address:x} is too large, size={obj.Size:x}, segmentEnd: {heap.GetSegmentByAddress(obj)?.End.ToString("x") ?? "???"}", ObjectCorruptionKind.InvalidMethodTable => $"Object {obj.Address:x} has an invalid method table {ReadPointerWithError(memory, obj):x}", ObjectCorruptionKind.InvalidThinlock => $"Object {obj.Address:x} has an invalid thin lock", ObjectCorruptionKind.SyncBlockMismatch => GetSyncBlockFailureMessage(corruption), @@ -167,42 +166,37 @@ internal static string GetObjectCorruptionMessage(IMemoryService memory, ClrHeap return message; } - private void WriteRow(ref TableOutput output, ClrHeap heap, ObjectCorruption corruption, string message) + private void WriteRow(ref Table output, ClrHeap heap, ObjectCorruption corruption, string message) { if (output is null) { if (heap.IsServer) { - output = new(Console, (-4, ""), (-12, "x12"), (-12, "x12"), (32, ""), (0, "")) - { - AlignLeft = true, - }; + output = new(Console, IntegerWithoutCommas.WithWidth(4), Pointer, ListNearObj, Column.ForEnum(), Text); + output.SetAlignment(Align.Left); - output.WriteRow("Heap", "Segment", "Object", "Failure", ""); + output.WriteHeader("Heap", "Segment", "Object", "Failure", "Reason"); } else { - output = new(Console, (-12, "x12"), (-12, "x12"), (22, ""), (0, "")) - { - AlignLeft = true, - }; + output = new(Console, Pointer, ListNearObj, Column.ForEnum(), Text); + output.SetAlignment(Align.Left); - output.WriteRow("Segment", "Object", "Failure", ""); + output.WriteHeader("Segment", "Object", "Failure", "Reason"); } } - ClrSegment segment = heap.GetSegmentByAddress(corruption.Object); - object[] columns = new object[output.ColumnCount]; + object[] columns = new object[output.Columns.Length]; int i = 0; if (heap.IsServer) { - columns[i++] = ValueWithError(segment?.SubHeap.Index, format: "", error: ""); + columns[i++] = (object)segment?.SubHeap.Index ?? "???"; } - columns[i++] = ValueWithError(segment?.Address, format: "x12", error: ""); - columns[i++] = new DmlExec(corruption.Object.Address, $"!ListNearObj {corruption.Object.Address:x}"); + columns[i++] = (object)segment ?? "???"; + columns[i++] = corruption.Object; columns[i++] = corruption.Kind; columns[i++] = message; @@ -244,26 +238,6 @@ private static string GetSyncBlockFailureMessage(ObjectCorruption corruption) return result; } - private static string ValueWithError(int? value, string format = "x", string error = "???") - { - if (value.HasValue) - { - return value.Value.ToString(format); - } - - return error; - } - - private static string ValueWithError(ulong? value, string format = "x", string error = "???") - { - if (value.HasValue) - { - return value.Value.ToString(format); - } - - return error; - } - private static string ReadPointerWithError(IMemoryService memory, ulong address) { if (memory.ReadPointer(address, out ulong value)) diff --git a/src/Microsoft.Diagnostics.ExtensionCommands/VerifyObjectCommand.cs b/src/Microsoft.Diagnostics.ExtensionCommands/VerifyObjectCommand.cs index 818532cef1..f952aca361 100644 --- a/src/Microsoft.Diagnostics.ExtensionCommands/VerifyObjectCommand.cs +++ b/src/Microsoft.Diagnostics.ExtensionCommands/VerifyObjectCommand.cs @@ -5,7 +5,9 @@ using System.Collections.Generic; using System.Linq; using Microsoft.Diagnostics.DebugServices; +using Microsoft.Diagnostics.ExtensionCommands.Output; using Microsoft.Diagnostics.Runtime; +using static Microsoft.Diagnostics.ExtensionCommands.Output.ColumnKind; namespace Microsoft.Diagnostics.ExtensionCommands { @@ -36,18 +38,15 @@ public override void Invoke() } ObjectCorruption[] corruption = corruptionEnum.OrderBy(r => r.Offset).ToArray(); - int offsetColWidth = Math.Max(6, corruption.Max(r => r.Offset.ToSignedHexString().Length)); - int kindColWidth = Math.Max(5, corruption.Max(ce => ce.Kind.ToString().Length)); - TableOutput output = new(Console, (offsetColWidth, ""), (kindColWidth, "")) - { - AlignLeft = true, - }; + Column offsetColumn = HexOffset.WithAlignment(Align.Left); + offsetColumn = offsetColumn.GetAppropriateWidth(corruption.Select(r => r.Offset)); - output.WriteRow("Offset", "Issue", "Description"); + Table output = new(Console, offsetColumn, Column.ForEnum(), Text); + output.WriteHeader("Offset", "Issue", "Description"); foreach (ObjectCorruption oc in corruption) { - output.WriteRow(oc.Offset.ToSignedHexString(), oc.Kind, VerifyHeapCommand.GetObjectCorruptionMessage(Memory, Runtime.Heap, oc)); + output.WriteRow(oc.Offset, oc.Kind, VerifyHeapCommand.GetObjectCorruptionMessage(Memory, Runtime.Heap, oc)); } Console.WriteLine(); diff --git a/src/SOS/SOS.Extensions/ConsoleServiceFromDebuggerServices.cs b/src/SOS/SOS.Extensions/ConsoleServiceFromDebuggerServices.cs index 9fceefd687..77bc7744e3 100644 --- a/src/SOS/SOS.Extensions/ConsoleServiceFromDebuggerServices.cs +++ b/src/SOS/SOS.Extensions/ConsoleServiceFromDebuggerServices.cs @@ -30,8 +30,15 @@ public ConsoleServiceFromDebuggerServices(DebuggerServices debuggerServices) public void WriteDmlExec(string text, string cmd) { - string dml = $"{DmlEscape(text)}"; - WriteDml(dml); + if (!SupportsDml || string.IsNullOrWhiteSpace(cmd)) + { + Write(text); + } + else + { + string dml = $"{DmlEscape(text)}"; + WriteDml(dml); + } } public bool SupportsDml => _supportsDml ??= _debuggerServices.SupportsDml; @@ -42,6 +49,6 @@ public void WriteDmlExec(string text, string cmd) #endregion - private static string DmlEscape(string text) => new XText(text).ToString(); + private static string DmlEscape(string text) => string.IsNullOrWhiteSpace(text) ? text : new XText(text).ToString(); } } diff --git a/src/SOS/SOS.UnitTests/Scripts/ConcurrentDictionaries.script b/src/SOS/SOS.UnitTests/Scripts/ConcurrentDictionaries.script index 3472a84454..9d402ecbf3 100644 --- a/src/SOS/SOS.UnitTests/Scripts/ConcurrentDictionaries.script +++ b/src/SOS/SOS.UnitTests/Scripts/ConcurrentDictionaries.script @@ -21,7 +21,7 @@ VERIFY: is not referencing an object # Checks on ConcurrentDictionary SOSCOMMAND: DumpHeap -stat -type System.Collections.Concurrent.ConcurrentDictionary< SOSCOMMAND: DumpHeap -mt ^() .*System.Collections.Concurrent.ConcurrentDictionary[^+] -EXTCOMMAND: dcd ^()\s+\s+\d+ +EXTCOMMAND: dcd \n\s*()\s+\s+\d+ VERIFY: 2 items VERIFY: Key: 2 EXTCOMMAND: dumparray Key: 1\s+Value: dumparray () @@ -31,7 +31,7 @@ VERIFY: Number of elements 4 # Checks on ConcurrentDictionary SOSCOMMAND: DumpHeap -stat -type System.Collections.Concurrent.ConcurrentDictionary< SOSCOMMAND: DumpHeap -mt ^() .*System.Collections.Concurrent.ConcurrentDictionary[^+] -EXTCOMMAND: dcd ^()\s+\s+\d+ +EXTCOMMAND: dcd \n\s*()\s+\s+\d+ VERIFY: 3 items VERIFY: Key: 0\s+Value: 1 VERIFY: Key: 31\s+Value: 17 @@ -40,7 +40,7 @@ VERIFY: Key: 1521482\s+Value: 512487 # Checks on ConcurrentDictionary SOSCOMMAND: DumpHeap -stat -type System.Collections.Concurrent.ConcurrentDictionary< SOSCOMMAND: DumpHeap -mt ^() .*System.Collections.Concurrent.ConcurrentDictionary[^+] -EXTCOMMAND: dcd ^()\s+\s+\d+ +EXTCOMMAND: dcd \n\s*()\s+\s+\d+ VERIFY: 3 items VERIFY: Key: "String true"\s+Value: True VERIFY: Key: "String false"\s+Value: False @@ -49,7 +49,7 @@ VERIFY: Key: "SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS # Checks on ConcurrentDictionary SOSCOMMAND: DumpHeap -stat -type System.Collections.Concurrent.ConcurrentDictionary< SOSCOMMAND: DumpHeap -mt ^() .*System.Collections.Concurrent.ConcurrentDictionary[^+] -EXTCOMMAND: dcd ^()\s+\s+\d+ +EXTCOMMAND: dcd \n\s*()\s+\s+\d+ VERIFY: 2 items VERIFY: Key: dumpvc \s+Value: null VERIFY: Key: dumpvc \s+Value: dumpobj @@ -66,7 +66,7 @@ ENDIF:32BIT # Checks on ConcurrentDictionary SOSCOMMAND: DumpHeap -stat -type System.Collections.Concurrent.ConcurrentDictionary< SOSCOMMAND: DumpHeap -mt ^() .*System.Collections.Concurrent.ConcurrentDictionary[^+] -EXTCOMMAND: dcd ^()\s+\s+\d+ +EXTCOMMAND: dcd \n\s*()\s+\s+\d+ VERIFY: 1 items VERIFY: Key: 0\s+Value: dumpvc SOSCOMMAND: dumpvc dumpvc ( ) From 68a08ef66c0e76036cb3f41e8035922b7c150722 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Thu, 27 Apr 2023 14:01:24 +0000 Subject: [PATCH 039/111] Update dependencies from https://github.com/dotnet/source-build-reference-packages build 20230426.1 (#3858) [main] Update dependencies from dotnet/source-build-reference-packages --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 73323ab041..574a33298e 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -47,9 +47,9 @@ https://github.com/dotnet/runtime a64420c79cb63c485138f4f1352b8730f27d7b19 - + https://github.com/dotnet/source-build-reference-packages - 4bf273ec25cc3983d6a5991cf0a4aa082cb255a5 + 9bd919efa1924f2684e63079a9e1106a4ce52b11 diff --git a/eng/Versions.props b/eng/Versions.props index 0d42902a28..09a46dde7b 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -66,7 +66,7 @@ 7.0.0-beta.22316.2 10.0.18362 13.0.1 - 8.0.0-alpha.1.23225.2 + 8.0.0-alpha.1.23226.1 1.2.0-beta-23165-02 From ddbcaa3164f2947e5a41db7317442c7a9a88643d Mon Sep 17 00:00:00 2001 From: Mike McLaughlin Date: Fri, 28 Apr 2023 10:36:38 -0700 Subject: [PATCH 040/111] Deal with 8.0 DAC passing bigger thread context to data target's GetThreadContext() (#3856) --- src/SOS/SOS.Hosting/CorDebugDataTargetWrapper.cs | 6 +++--- src/SOS/SOS.Hosting/DataTargetWrapper.cs | 2 +- src/SOS/SOS.Hosting/DbgEng/DebugAdvanced.cs | 4 ++-- src/SOS/SOS.Hosting/LLDBServices.cs | 2 +- src/SOS/SOS.Hosting/SOSHost.cs | 8 ++++---- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/SOS/SOS.Hosting/CorDebugDataTargetWrapper.cs b/src/SOS/SOS.Hosting/CorDebugDataTargetWrapper.cs index d229f23f82..5e69c47532 100644 --- a/src/SOS/SOS.Hosting/CorDebugDataTargetWrapper.cs +++ b/src/SOS/SOS.Hosting/CorDebugDataTargetWrapper.cs @@ -143,7 +143,7 @@ private int GetThreadContext( IntPtr self, uint threadId, uint contextFlags, - uint contextSize, + int contextSize, IntPtr context) { byte[] registerContext; @@ -157,7 +157,7 @@ private int GetThreadContext( } try { - Marshal.Copy(registerContext, 0, context, (int)contextSize); + Marshal.Copy(registerContext, 0, context, Math.Min(registerContext.Length, contextSize)); } catch (Exception ex) when (ex is ArgumentOutOfRangeException or ArgumentNullException) { @@ -246,7 +246,7 @@ private delegate int GetThreadContextDelegate( [In] IntPtr self, [In] uint threadId, [In] uint contextFlags, - [In] uint contextSize, + [In] int contextSize, [Out] IntPtr context); #endregion diff --git a/src/SOS/SOS.Hosting/DataTargetWrapper.cs b/src/SOS/SOS.Hosting/DataTargetWrapper.cs index 301fdaab50..303e88d825 100644 --- a/src/SOS/SOS.Hosting/DataTargetWrapper.cs +++ b/src/SOS/SOS.Hosting/DataTargetWrapper.cs @@ -231,7 +231,7 @@ private int GetThreadContext( } try { - Marshal.Copy(registerContext, 0, context, contextSize); + Marshal.Copy(registerContext, 0, context, Math.Min(registerContext.Length, contextSize)); } catch (Exception ex) when (ex is ArgumentOutOfRangeException or ArgumentNullException) { diff --git a/src/SOS/SOS.Hosting/DbgEng/DebugAdvanced.cs b/src/SOS/SOS.Hosting/DbgEng/DebugAdvanced.cs index 83958ee622..5ac7000357 100644 --- a/src/SOS/SOS.Hosting/DbgEng/DebugAdvanced.cs +++ b/src/SOS/SOS.Hosting/DbgEng/DebugAdvanced.cs @@ -24,13 +24,13 @@ internal DebugAdvanced(DebugClient client, SOSHost soshost) private delegate int GetThreadContextDelegate( [In] IntPtr self, [In] IntPtr context, - [In] uint contextSize); + [In] int contextSize); [UnmanagedFunctionPointer(CallingConvention.Winapi)] private delegate int SetThreadContextDelegate( [In] IntPtr self, [In] IntPtr context, - [In] uint contextSize); + [In] int contextSize); #endregion } diff --git a/src/SOS/SOS.Hosting/LLDBServices.cs b/src/SOS/SOS.Hosting/LLDBServices.cs index 30ea3dbb8d..5ac39d92a0 100644 --- a/src/SOS/SOS.Hosting/LLDBServices.cs +++ b/src/SOS/SOS.Hosting/LLDBServices.cs @@ -443,7 +443,7 @@ private delegate int GetThreadContextBySystemIdDelegate( IntPtr self, uint threadId, uint contextFlags, - uint contextSize, + int contextSize, IntPtr context); [UnmanagedFunctionPointer(CallingConvention.Winapi)] diff --git a/src/SOS/SOS.Hosting/SOSHost.cs b/src/SOS/SOS.Hosting/SOSHost.cs index 4dadf27fa4..03d011d0da 100644 --- a/src/SOS/SOS.Hosting/SOSHost.cs +++ b/src/SOS/SOS.Hosting/SOSHost.cs @@ -575,7 +575,7 @@ internal static unsafe int GetSymbolPath( internal int GetThreadContext( IntPtr self, IntPtr context, - uint contextSize) + int contextSize) { IThread thread = ContextService.GetCurrentThread(); if (thread is not null) @@ -589,7 +589,7 @@ internal int GetThreadContextBySystemId( IntPtr self, uint threadId, uint contextFlags, - uint contextSize, + int contextSize, IntPtr context) { byte[] registerContext; @@ -603,7 +603,7 @@ internal int GetThreadContextBySystemId( } try { - Marshal.Copy(registerContext, 0, context, (int)contextSize); + Marshal.Copy(registerContext, 0, context, Math.Min(registerContext.Length, contextSize)); } catch (Exception ex) when (ex is ArgumentOutOfRangeException or ArgumentNullException) { @@ -615,7 +615,7 @@ internal int GetThreadContextBySystemId( internal static int SetThreadContext( IntPtr self, IntPtr context, - uint contextSize) + int contextSize) { return DebugClient.NotImplemented; } From c22d6c5612daab1320a22c6c58572bc8e1474ce0 Mon Sep 17 00:00:00 2001 From: kkeirstead <85592574+kkeirstead@users.noreply.github.com> Date: Tue, 2 May 2023 09:55:11 -0700 Subject: [PATCH 041/111] Enable UpDownCounter For Dotnet-Counters and Dotnet-Monitor (#3849) * Use value from UDC event payload. * Adding support for UpDownCounter reporting a value instead of a rate * Check for payload version, don't attempt to parse if version 0 * Don't get rate for updowncounter payload --- .../Counters/CounterPayload.cs | 12 +++++ .../Counters/TraceEventExtensions.cs | 46 ++++++++++++++++++- src/Tools/dotnet-counters/CounterMonitor.cs | 40 ++++++++++++++++ 3 files changed, 97 insertions(+), 1 deletion(-) diff --git a/src/Microsoft.Diagnostics.Monitoring.EventPipe/Counters/CounterPayload.cs b/src/Microsoft.Diagnostics.Monitoring.EventPipe/Counters/CounterPayload.cs index 18eb5264e3..99e3030081 100644 --- a/src/Microsoft.Diagnostics.Monitoring.EventPipe/Counters/CounterPayload.cs +++ b/src/Microsoft.Diagnostics.Monitoring.EventPipe/Counters/CounterPayload.cs @@ -86,6 +86,17 @@ public GaugePayload(string providerName, string name, string displayName, string } } + internal class UpDownCounterPayload : CounterPayload + { + public UpDownCounterPayload(string providerName, string name, string displayName, string displayUnits, string metadata, double value, DateTime timestamp) : + base(providerName, name, metadata, value, timestamp, "Metric", EventType.UpDownCounter) + { + // In case these properties are not provided, set them to appropriate values. + string counterName = string.IsNullOrEmpty(displayName) ? name : displayName; + DisplayName = !string.IsNullOrEmpty(displayUnits) ? $"{counterName} ({displayUnits})" : counterName; + } + } + internal class CounterEndedPayload : CounterPayload { public CounterEndedPayload(string providerName, string name, DateTime timestamp) @@ -144,6 +155,7 @@ internal enum EventType : int Rate, Gauge, Histogram, + UpDownCounter, Error, CounterEnded } diff --git a/src/Microsoft.Diagnostics.Monitoring.EventPipe/Counters/TraceEventExtensions.cs b/src/Microsoft.Diagnostics.Monitoring.EventPipe/Counters/TraceEventExtensions.cs index eedc106d18..347a4e11f2 100644 --- a/src/Microsoft.Diagnostics.Monitoring.EventPipe/Counters/TraceEventExtensions.cs +++ b/src/Microsoft.Diagnostics.Monitoring.EventPipe/Counters/TraceEventExtensions.cs @@ -90,6 +90,10 @@ public static bool TryGetCounterPayload(this TraceEvent traceEvent, CounterFilte { HandleCounterRate(traceEvent, filter, sessionId, out payload); } + else if (traceEvent.EventName == "UpDownCounterRateValuePublished") + { + HandleUpDownCounterValue(traceEvent, filter, sessionId, out payload); + } else if (traceEvent.EventName == "TimeSeriesLimitReached") { HandleTimeSeriesLimitReached(traceEvent, sessionId, out payload); @@ -183,7 +187,47 @@ private static void HandleCounterRate(TraceEvent traceEvent, CounterFilter filte else { // for observable instruments we assume the lack of data is meaningful and remove it from the UI - // this happens when the ObservableCounter callback function throws an exception. + // this happens when the ObservableCounter callback function throws an exception + // or when the ObservableCounter doesn't include a measurement for a particular set of tag values. + payload = new CounterEndedPayload(meterName, instrumentName, traceEvent.TimeStamp); + } + } + + private static void HandleUpDownCounterValue(TraceEvent traceEvent, CounterFilter filter, string sessionId, out ICounterPayload payload) + { + payload = null; + + string payloadSessionId = (string)traceEvent.PayloadValue(0); + + if (payloadSessionId != sessionId || traceEvent.Version < 1) // Version 1 added the value field. + { + return; + } + + string meterName = (string)traceEvent.PayloadValue(1); + //string meterVersion = (string)obj.PayloadValue(2); + string instrumentName = (string)traceEvent.PayloadValue(3); + string unit = (string)traceEvent.PayloadValue(4); + string tags = (string)traceEvent.PayloadValue(5); + //string rateText = (string)traceEvent.PayloadValue(6); // Not currently using rate for UpDownCounters. + string valueText = (string)traceEvent.PayloadValue(7); + + if (!filter.IsIncluded(meterName, instrumentName)) + { + return; + } + + if (double.TryParse(valueText, NumberStyles.Number | NumberStyles.Float, CultureInfo.InvariantCulture, out double value)) + { + // UpDownCounter reports the value, not the rate - this is different than how Counter behaves. + payload = new UpDownCounterPayload(meterName, instrumentName, null, unit, tags, value, traceEvent.TimeStamp); + + } + else + { + // for observable instruments we assume the lack of data is meaningful and remove it from the UI + // this happens when the ObservableUpDownCounter callback function throws an exception + // or when the ObservableUpDownCounter doesn't include a measurement for a particular set of tag values. payload = new CounterEndedPayload(meterName, instrumentName, traceEvent.TimeStamp); } } diff --git a/src/Tools/dotnet-counters/CounterMonitor.cs b/src/Tools/dotnet-counters/CounterMonitor.cs index 928664d33e..a017074386 100644 --- a/src/Tools/dotnet-counters/CounterMonitor.cs +++ b/src/Tools/dotnet-counters/CounterMonitor.cs @@ -88,6 +88,10 @@ private void DynamicAllMonitor(TraceEvent obj) { HandleCounterRate(obj); } + else if (obj.EventName == "UpDownCounterRateValuePublished") + { + HandleUpDownCounterValue(obj); + } else if (obj.EventName == "TimeSeriesLimitReached") { HandleTimeSeriesLimitReached(obj); @@ -198,6 +202,42 @@ private void HandleGauge(TraceEvent obj) } } + private void HandleUpDownCounterValue(TraceEvent obj) + { + if (obj.Version < 1) // Version 1 added the value field. + { + return; + } + + string sessionId = (string)obj.PayloadValue(0); + string meterName = (string)obj.PayloadValue(1); + //string meterVersion = (string)obj.PayloadValue(2); + string instrumentName = (string)obj.PayloadValue(3); + string unit = (string)obj.PayloadValue(4); + string tags = (string)obj.PayloadValue(5); + //string rateText = (string)obj.PayloadValue(6); // Not currently using rate for UpDownCounters. + string valueText = (string)obj.PayloadValue(7); + if (sessionId != _metricsEventSourceSessionId) + { + return; + } + MeterInstrumentEventObserved(meterName, obj.TimeStamp); + + // the value might be an empty string indicating no measurement was provided this collection interval + if (double.TryParse(valueText, NumberStyles.Number | NumberStyles.Float, CultureInfo.InvariantCulture, out double value)) + { + // UpDownCounter reports the value, not the rate - this is different than how Counter behaves, and is thus treated as a gauge. + CounterPayload payload = new GaugePayload(meterName, instrumentName, null, unit, tags, value, obj.TimeStamp); + _renderer.CounterPayloadReceived(payload, _pauseCmdSet); + } + else + { + // for observable instruments we assume the lack of data is meaningful and remove it from the UI + CounterPayload payload = new RatePayload(meterName, instrumentName, null, unit, tags, 0, _interval, obj.TimeStamp); + _renderer.CounterStopped(payload); + } + } + private void HandleHistogram(TraceEvent obj) { string sessionId = (string)obj.PayloadValue(0); From f8d156b65ee81b87bd996b4b48db9e637634b3a0 Mon Sep 17 00:00:00 2001 From: Grisha Kotler Date: Wed, 3 May 2023 01:49:57 +0300 Subject: [PATCH 042/111] dotnet-stack: Fix parsing of thread names (#3860) --- src/Tools/dotnet-stack/ReportCommand.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Tools/dotnet-stack/ReportCommand.cs b/src/Tools/dotnet-stack/ReportCommand.cs index 324c299532..76ca818ead 100644 --- a/src/Tools/dotnet-stack/ReportCommand.cs +++ b/src/Tools/dotnet-stack/ReportCommand.cs @@ -121,7 +121,11 @@ private static async Task Report(CancellationToken ct, IConsole console, in // Thread id is in the frame name as "Thread ()" string template = "Thread ("; string threadFrame = stackSource.GetFrameName(stackSource.GetFrameIndex(stackIndex), false); - int threadId = int.Parse(threadFrame.Substring(template.Length, threadFrame.Length - (template.Length + 1))); + + // we are looking for the first index of ) because + // we need to handle a thread name like: Thread (4008) (.NET IO ThreadPool Worker) + int firstIndex = threadFrame.IndexOf(')'); + int threadId = int.Parse(threadFrame.AsSpan(template.Length, firstIndex - template.Length)); if (samplesForThread.TryGetValue(threadId, out List samples)) { From eb32ee27a1f0b1aaf36416b211237068b68e386f Mon Sep 17 00:00:00 2001 From: Lee Culver Date: Mon, 8 May 2023 15:50:30 -0700 Subject: [PATCH 043/111] Fix issue with !sos maddress (#3868) Previous refactoring accidently eliminated the case where the CLR region perfectly overlapped the memory region. --- .../NativeAddressHelper.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Microsoft.Diagnostics.ExtensionCommands/NativeAddressHelper.cs b/src/Microsoft.Diagnostics.ExtensionCommands/NativeAddressHelper.cs index 9658d026e3..a8e46ed7c3 100644 --- a/src/Microsoft.Diagnostics.ExtensionCommands/NativeAddressHelper.cs +++ b/src/Microsoft.Diagnostics.ExtensionCommands/NativeAddressHelper.cs @@ -262,8 +262,11 @@ private DescribedRegion[] EnumerateAddressSpaceWorker(bool tagClrMemoryRanges, b region.ClrMemoryKind = mem.Kind; } } + else + { + SetRegionKindWithWarning(mem, region); + } } - } } } From b3c2ec6061bef75f167911899ec5264133c4cff3 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Tue, 9 May 2023 09:25:26 -0700 Subject: [PATCH 044/111] [main] Update dependencies from dotnet/symstore (#3863) * Update dependencies from https://github.com/dotnet/symstore build 20230501.1 Microsoft.SymbolStore From Version 1.0.422401 -> To Version 1.0.425101 * Update dependencies from https://github.com/dotnet/symstore build 20230508.1 Microsoft.SymbolStore From Version 1.0.422401 -> To Version 1.0.425801 --------- Co-authored-by: dotnet-maestro[bot] --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 574a33298e..2d4c708469 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -1,8 +1,8 @@ - + https://github.com/dotnet/symstore - 219e980f2eb48497d727d9fa86892ea54fff4fbb + 037b99d1cc7e4c2e6931e66ce44fdb3b8467f2de https://github.com/microsoft/clrmd diff --git a/eng/Versions.props b/eng/Versions.props index 09a46dde7b..fb04d11035 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -16,7 +16,7 @@ - 1.0.422401 + 1.0.425801 8.0.0-preview.3.23155.1 8.0.0-preview.3.23155.1 From 3828c5daa7ee4e009ca06b5341e5e55dbb0fdff8 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Tue, 9 May 2023 09:25:50 -0700 Subject: [PATCH 045/111] [main] Update dependencies from dotnet/source-build-reference-packages (#3861) * Update dependencies from https://github.com/dotnet/source-build-reference-packages build 20230428.2 Microsoft.SourceBuild.Intermediate.source-build-reference-packages From Version 8.0.0-alpha.1.23226.1 -> To Version 8.0.0-alpha.1.23228.2 * Update dependencies from https://github.com/dotnet/source-build-reference-packages build 20230501.2 Microsoft.SourceBuild.Intermediate.source-build-reference-packages From Version 8.0.0-alpha.1.23226.1 -> To Version 8.0.0-alpha.1.23251.2 * Update dependencies from https://github.com/dotnet/source-build-reference-packages build 20230503.2 Microsoft.SourceBuild.Intermediate.source-build-reference-packages From Version 8.0.0-alpha.1.23226.1 -> To Version 8.0.0-alpha.1.23253.2 * Update dependencies from https://github.com/dotnet/source-build-reference-packages build 20230508.2 Microsoft.SourceBuild.Intermediate.source-build-reference-packages From Version 8.0.0-alpha.1.23226.1 -> To Version 8.0.0-alpha.1.23258.2 --------- Co-authored-by: dotnet-maestro[bot] --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 2d4c708469..6aa8402f8f 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -47,9 +47,9 @@ https://github.com/dotnet/runtime a64420c79cb63c485138f4f1352b8730f27d7b19 - + https://github.com/dotnet/source-build-reference-packages - 9bd919efa1924f2684e63079a9e1106a4ce52b11 + c896aec98150aae68c90b0579a24babc864ceb88 diff --git a/eng/Versions.props b/eng/Versions.props index fb04d11035..25c6257251 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -66,7 +66,7 @@ 7.0.0-beta.22316.2 10.0.18362 13.0.1 - 8.0.0-alpha.1.23226.1 + 8.0.0-alpha.1.23258.2 1.2.0-beta-23165-02 From 3d54f36223c4c303e83b88cb75371bdd9f3e275a Mon Sep 17 00:00:00 2001 From: Thays Grazia Date: Tue, 9 May 2023 18:00:25 -0300 Subject: [PATCH 046/111] fix implementation of RegisterForRuntimeStartupRemotePort and CreateCoreDbgRemotePort (#3869) --- src/dbgshim/dbgshim.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/dbgshim/dbgshim.cpp b/src/dbgshim/dbgshim.cpp index a68d1ad650..2b5411da32 100644 --- a/src/dbgshim/dbgshim.cpp +++ b/src/dbgshim/dbgshim.cpp @@ -2159,6 +2159,7 @@ CLRCreateInstance( HRESULT CreateCoreDbgRemotePort(HMODULE hDBIModule, DWORD portId, LPCSTR assemblyBasePath, IUnknown **ppCordb) { + PUBLIC_CONTRACT; HRESULT hr = S_OK; FPCreateRemoteCordbObject fpCreate = @@ -2181,6 +2182,7 @@ RegisterForRuntimeStartupRemotePort( _In_ LPCSTR assemblyBasePath, _Out_ IUnknown ** ppCordb) { + PUBLIC_CONTRACT; HRESULT hr = S_OK; HMODULE hMod = NULL; From ffe62ebd7183df83057ec0d06a0314c3afeea8db Mon Sep 17 00:00:00 2001 From: Lee Culver Date: Wed, 10 May 2023 09:39:40 -0700 Subject: [PATCH 047/111] Add static variable names to !gcroot (#3872) Static variables can be opaque to the user when looking at !gcroot, since they show up as a pinned handle to an object array. It's also difficult to distinguish things _other_ than static variables which follow the same pattern. This change adds the static variable name to the output of !gcroot to help distinguish these differences. - Remove "this will take a while" warning output from !dumpheap -short. - Added StaticVariableService to resolve the address/objects of static variables. This can be a relatively expensive operation, so it's important to cache the result. - Updated GCRootCommand with the heuristic. --- .../DumpHeapCommand.cs | 13 +++ .../GCRootCommand.cs | 62 ++++++++++-- .../PathToCommand.cs | 2 +- .../StaticVariableService.cs | 99 +++++++++++++++++++ 4 files changed, 169 insertions(+), 7 deletions(-) create mode 100644 src/Microsoft.Diagnostics.ExtensionCommands/StaticVariableService.cs diff --git a/src/Microsoft.Diagnostics.ExtensionCommands/DumpHeapCommand.cs b/src/Microsoft.Diagnostics.ExtensionCommands/DumpHeapCommand.cs index c62435f1d3..2f8c47256b 100644 --- a/src/Microsoft.Diagnostics.ExtensionCommands/DumpHeapCommand.cs +++ b/src/Microsoft.Diagnostics.ExtensionCommands/DumpHeapCommand.cs @@ -72,6 +72,14 @@ public override void Invoke() ParseArguments(); IEnumerable objectsToPrint = FilteredHeap.EnumerateFilteredObjects(Console.CancellationToken); + + bool? liveObjectWarning = null; + if ((Live || Dead) && Short) + { + liveObjectWarning = LiveObjects.PrintWarning; + LiveObjects.PrintWarning = false; + } + if (Live) { objectsToPrint = objectsToPrint.Where(LiveObjects.IsLive); @@ -148,6 +156,11 @@ public override void Invoke() } DumpHeap.PrintHeap(objectsToPrint, displayKind, StatOnly, printFragmentation); + + if (liveObjectWarning is bool original) + { + LiveObjects.PrintWarning = original; + } } private void ParseArguments() diff --git a/src/Microsoft.Diagnostics.ExtensionCommands/GCRootCommand.cs b/src/Microsoft.Diagnostics.ExtensionCommands/GCRootCommand.cs index 210d0f73ea..7260a22eef 100644 --- a/src/Microsoft.Diagnostics.ExtensionCommands/GCRootCommand.cs +++ b/src/Microsoft.Diagnostics.ExtensionCommands/GCRootCommand.cs @@ -26,6 +26,9 @@ public class GCRootCommand : CommandBase [ServiceImport] public RootCacheService RootCache { get; set; } + [ServiceImport] + public StaticVariableService StaticVariables { get; set; } + [ServiceImport] public ManagedFileLineService FileLineService { get; set; } @@ -143,7 +146,7 @@ private int PrintOlderGenerationRoots(GCRoot gcroot, int gen) } Console.WriteLine($" {objAddress:x}"); - PrintPath(Console, RootCache, Runtime.Heap, path); + PrintPath(Console, RootCache, StaticVariables, Runtime.Heap, path); Console.WriteLine(); count++; @@ -216,11 +219,11 @@ private int PrintNonStackRoots(GCRoot gcroot) private void PrintPath(ClrRoot root, GCRoot.ChainLink link) { PrintRoot(root); - PrintPath(Console, RootCache, Runtime.Heap, link); + PrintPath(Console, RootCache, StaticVariables, Runtime.Heap, link); Console.WriteLine(); } - public static void PrintPath(IConsoleService console, RootCacheService rootCache, ClrHeap heap, GCRoot.ChainLink link) + public static void PrintPath(IConsoleService console, RootCacheService rootCache, StaticVariableService statics, ClrHeap heap, GCRoot.ChainLink link) { Table objectOutput = new(console, Text.WithWidth(2), DumpObj, TypeName, Text) { @@ -229,13 +232,60 @@ public static void PrintPath(IConsoleService console, RootCacheService rootCache objectOutput.SetAlignment(Align.Left); + bool first = true; + bool isPossibleStatic = true; + + ClrObject firstObj = default; + ulong prevObj = 0; while (link != null) { - bool isDependentHandleLink = rootCache.IsDependentHandleLink(prevObj, link.Object); ClrObject obj = heap.GetObject(link.Object); - objectOutput.WriteRow("->", obj, obj.Type, (isDependentHandleLink ? " (dependent handle)" : "")); + // Check whether this link is a dependent handle + string extraText = ""; + bool isDependentHandleLink = rootCache.IsDependentHandleLink(prevObj, link.Object); + if (isDependentHandleLink) + { + extraText = "(dependent handle)"; + } + + // Print static variable info. In all versions of the runtime, static variables are stored in + // a pinned object array. We check if the first link in the chain is an object[], and if so we + // check if the second object's address is the location of a static variable. We could further + // narrow this by checking the root type, but that needlessly complicates this code...we can't + // get false positives or negatives here (as nothing points to static variable object[] other + // than the root). + if (first) + { + firstObj = obj; + isPossibleStatic = firstObj.IsValid && firstObj.IsArray && firstObj.Type.Name == "System.Object[]"; + first = false; + } + else if (isPossibleStatic) + { + if (statics is not null && !isDependentHandleLink) + { + foreach (ClrReference reference in firstObj.EnumerateReferencesWithFields(carefully: false, considerDependantHandles: false)) + { + if (reference.Object == obj) + { + ulong address = firstObj + (uint)reference.Offset; + + if (statics.TryGetStaticByAddress(address, out ClrStaticField field)) + { + extraText = $"(static variable: {field.Type?.Name ?? "Unknown"}.{field.Name})"; + break; + } + } + } + } + + // only the first object[] in the chain is possible to be the static array + isPossibleStatic = false; + } + + objectOutput.WriteRow("->", obj, obj.Type, extraText); prevObj = link.Object; link = link.Next; @@ -322,7 +372,7 @@ private static string NameForHandle(ClrHandleKind handleKind) ClrHandleKind.SizedRef => "sized ref handle", ClrHandleKind.WeakWinRT => "weak WinRT handle", _ => handleKind.ToString() - }; ; + }; } private string GetFrameOutput(ClrStackFrame currFrame) diff --git a/src/Microsoft.Diagnostics.ExtensionCommands/PathToCommand.cs b/src/Microsoft.Diagnostics.ExtensionCommands/PathToCommand.cs index e4c2254fa6..e63940d3be 100644 --- a/src/Microsoft.Diagnostics.ExtensionCommands/PathToCommand.cs +++ b/src/Microsoft.Diagnostics.ExtensionCommands/PathToCommand.cs @@ -58,7 +58,7 @@ public override void Invoke() GCRoot.ChainLink path = gcroot.FindPathFrom(sourceObj); if (path is not null) { - GCRootCommand.PrintPath(Console, RootCache, heap, path); + GCRootCommand.PrintPath(Console, RootCache, null, heap, path); } else { diff --git a/src/Microsoft.Diagnostics.ExtensionCommands/StaticVariableService.cs b/src/Microsoft.Diagnostics.ExtensionCommands/StaticVariableService.cs new file mode 100644 index 0000000000..a9e03d4ecc --- /dev/null +++ b/src/Microsoft.Diagnostics.ExtensionCommands/StaticVariableService.cs @@ -0,0 +1,99 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Collections.Generic; +using Microsoft.Diagnostics.DebugServices; +using Microsoft.Diagnostics.Runtime; + +namespace Microsoft.Diagnostics.ExtensionCommands +{ + [ServiceExport(Scope = ServiceScope.Runtime)] + public class StaticVariableService + { + private Dictionary _fields; + private IEnumerator<(ulong Address, ClrStaticField Static)> _enumerator; + + [ServiceImport] + public ClrRuntime Runtime { get; set; } + + /// + /// Returns the static field at the given address. + /// + /// The address of the static field. Note that this is not a pointer to + /// an object, but rather a pointer to where the CLR runtime tracks the static variable's + /// location. In all versions of the runtime, address will live in the middle of a pinned + /// object[]. + /// The field corresponding to the given address. Non-null if return + /// is true. + /// True if the address corresponded to a static variable, false otherwise. + public bool TryGetStaticByAddress(ulong address, out ClrStaticField field) + { + if (_fields is null) + { + _fields = new(); + _enumerator = EnumerateStatics().GetEnumerator(); + } + + if (_fields.TryGetValue(address, out field)) + { + return true; + } + + // pay for play lookup + if (_enumerator is not null) + { + do + { + _fields[_enumerator.Current.Address] = _enumerator.Current.Static; + if (_enumerator.Current.Address == address) + { + field = _enumerator.Current.Static; + return true; + } + } while (_enumerator.MoveNext()); + + _enumerator = null; + } + + return false; + } + + public IEnumerable<(ulong Address, ClrStaticField Static)> EnumerateStatics() + { + ClrAppDomain shared = Runtime.SharedDomain; + + foreach (ClrModule module in Runtime.EnumerateModules()) + { + foreach ((ulong mt, _) in module.EnumerateTypeDefToMethodTableMap()) + { + ClrType type = Runtime.GetTypeByMethodTable(mt); + if (type is null) + { + continue; + } + + foreach (ClrStaticField stat in type.StaticFields) + { + foreach (ClrAppDomain domain in Runtime.AppDomains) + { + ulong address = stat.GetAddress(domain); + if (address != 0) + { + yield return (address, stat); + } + } + + if (shared is not null) + { + ulong address = stat.GetAddress(shared); + if (address != 0) + { + yield return (address, stat); + } + } + } + } + } + } + } +} From 4f2e6dc67c76c934a61b266184b4cb5f4395690f Mon Sep 17 00:00:00 2001 From: Lee Culver Date: Wed, 10 May 2023 09:41:20 -0700 Subject: [PATCH 048/111] Fix issue with nint/nuint formatting (#3871) * Fix integer formatting StringBuilder.Format doesn't respect "x" when with nint/nuint. * Update Formats.cs --- .../Output/Formats.cs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/Microsoft.Diagnostics.ExtensionCommands/Output/Formats.cs b/src/Microsoft.Diagnostics.ExtensionCommands/Output/Formats.cs index 2ef5090eea..1fdc488e69 100644 --- a/src/Microsoft.Diagnostics.ExtensionCommands/Output/Formats.cs +++ b/src/Microsoft.Diagnostics.ExtensionCommands/Output/Formats.cs @@ -58,6 +58,17 @@ public override int FormatValue(StringBuilder result, object value, int maxLengt case null: break; + case nuint nui: + result.AppendFormat(_format, (ulong)nui); + break; + + case nint ni: + unchecked + { + result.AppendFormat(_format, (ulong)ni); + } + break; + default: result.AppendFormat(_format, value); break; From 3ae4837a4b444695fc8732d4c6d77af4a1f56f3e Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Sat, 13 May 2023 13:31:49 +0000 Subject: [PATCH 049/111] [main] Update dependencies from microsoft/clrmd (#3864) [main] Update dependencies from microsoft/clrmd --- eng/Version.Details.xml | 8 ++++---- eng/Versions.props | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 6aa8402f8f..9873e27ca1 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -4,13 +4,13 @@ https://github.com/dotnet/symstore 037b99d1cc7e4c2e6931e66ce44fdb3b8467f2de - + https://github.com/microsoft/clrmd - 80b19b666752ae64301e33f819c39d4279ec0727 + c2d1067aae54add30ada9c6f9adf2fa24ef48ab4 - + https://github.com/microsoft/clrmd - 80b19b666752ae64301e33f819c39d4279ec0727 + c2d1067aae54add30ada9c6f9adf2fa24ef48ab4 diff --git a/eng/Versions.props b/eng/Versions.props index 25c6257251..669b399bec 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -45,7 +45,7 @@ 5.0.0 6.0.0 - 3.0.0-beta.23219.1 + 3.0.0-beta.23262.1 16.9.0-beta1.21055.5 3.0.7 6.0.0 From e641da7bb2718fac5d2158cceddb5dcfe8cd7053 Mon Sep 17 00:00:00 2001 From: Juan Hoyos <19413848+hoyosjs@users.noreply.github.com> Date: Mon, 15 May 2023 17:13:41 -0700 Subject: [PATCH 050/111] Update DumpAsync to allow method table and object address to not have 0x prefix (#3876) * Update DumpAsync to allow method table and object address to not have 0x prefix * Specify null-return OK --- .../DumpAsyncCommand.cs | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/src/Microsoft.Diagnostics.ExtensionCommands/DumpAsyncCommand.cs b/src/Microsoft.Diagnostics.ExtensionCommands/DumpAsyncCommand.cs index 7e80e59d18..0acbca362e 100644 --- a/src/Microsoft.Diagnostics.ExtensionCommands/DumpAsyncCommand.cs +++ b/src/Microsoft.Diagnostics.ExtensionCommands/DumpAsyncCommand.cs @@ -52,13 +52,24 @@ public sealed class DumpAsyncCommand : ExtensionCommandBase [ServiceImport(Optional = true)] public ClrRuntime? Runtime { get; set; } + /// Gets whether to only show stacks that include the object with the specified address. [Option(Name = "--address", Aliases = new string[] { "-addr" }, Help = "Only show stacks that include the object with the specified address.")] - public ulong? ObjectAddress { get; set; } + public string? ObjectAddress + { + get => _objectAddress?.ToString(); + set => _objectAddress = ParseAddress(value); + } + private ulong? _objectAddress; /// Gets whether to only show stacks that include objects with the specified method table. [Option(Name = "--methodtable", Aliases = new string[] { "-mt" }, Help = "Only show stacks that include objects with the specified method table.")] - public ulong? MethodTableAddress { get; set; } + public string? MethodTableAddress + { + get => _methodTableAddress?.ToString(); + set => _methodTableAddress = ParseAddress(value); + } + private ulong? _methodTableAddress; /// Gets whether to only show stacks that include objects whose type includes the specified name in its name. [Option(Name = "--type", Help = "Only show stacks that include objects whose type includes the specified name in its name.")] @@ -532,14 +543,14 @@ string Describe(ClrObject obj) // Determines whether the specified object is of interest to the user based on their criteria provided as command arguments. bool IncludeInOutput(ClrObject obj) { - if (ObjectAddress is ulong addr && obj.Address != addr) + if (_objectAddress is ulong addr && obj.Address != addr) { return false; } if (obj.Type is not null) { - if (MethodTableAddress is ulong mt && obj.Type.MethodTable != mt) + if (_methodTableAddress is ulong mt && obj.Type.MethodTable != mt) { return false; } From 2cebd1f767f71e69c77ace437145b2b1e5991819 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Tue, 16 May 2023 13:48:56 +0000 Subject: [PATCH 051/111] Update dependencies from https://github.com/dotnet/symstore build 20230515.1 (#3879) [main] Update dependencies from dotnet/symstore --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 9873e27ca1..939c7001e7 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -1,8 +1,8 @@ - + https://github.com/dotnet/symstore - 037b99d1cc7e4c2e6931e66ce44fdb3b8467f2de + 72212ba2f73877c1bf08a1c5bfbae5501e459e8a https://github.com/microsoft/clrmd diff --git a/eng/Versions.props b/eng/Versions.props index 669b399bec..d69ae5f48a 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -16,7 +16,7 @@ - 1.0.425801 + 1.0.426501 8.0.0-preview.3.23155.1 8.0.0-preview.3.23155.1 From 70ce5f7ca0c6ec81b3b9c25c28a074359c437b89 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Tue, 16 May 2023 14:30:45 +0000 Subject: [PATCH 052/111] [main] Update dependencies from dotnet/source-build-reference-packages (#3870) [main] Update dependencies from dotnet/source-build-reference-packages --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 939c7001e7..dd1dfa94df 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -47,9 +47,9 @@ https://github.com/dotnet/runtime a64420c79cb63c485138f4f1352b8730f27d7b19 - + https://github.com/dotnet/source-build-reference-packages - c896aec98150aae68c90b0579a24babc864ceb88 + e2e64d25662c00a35726d3c52f969a50edaa4f48 diff --git a/eng/Versions.props b/eng/Versions.props index d69ae5f48a..b03d8a0e1b 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -66,7 +66,7 @@ 7.0.0-beta.22316.2 10.0.18362 13.0.1 - 8.0.0-alpha.1.23258.2 + 8.0.0-alpha.1.23265.3 1.2.0-beta-23165-02 From 05aecef20c6f07e01c5508b1b05538ebe781c524 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Wed, 17 May 2023 13:57:59 +0000 Subject: [PATCH 053/111] Update dependencies from https://github.com/dotnet/source-build-reference-packages build 20230516.4 (#3881) [main] Update dependencies from dotnet/source-build-reference-packages --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index dd1dfa94df..84602c8166 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -47,9 +47,9 @@ https://github.com/dotnet/runtime a64420c79cb63c485138f4f1352b8730f27d7b19 - + https://github.com/dotnet/source-build-reference-packages - e2e64d25662c00a35726d3c52f969a50edaa4f48 + fd98754b692a1a8da2aaadd28ce3952578d9d9ad diff --git a/eng/Versions.props b/eng/Versions.props index b03d8a0e1b..926f61bd0c 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -66,7 +66,7 @@ 7.0.0-beta.22316.2 10.0.18362 13.0.1 - 8.0.0-alpha.1.23265.3 + 8.0.0-alpha.1.23266.4 1.2.0-beta-23165-02 From dc4d075439b2af65d9305d11e1e779e504fa779b Mon Sep 17 00:00:00 2001 From: Mike McLaughlin Date: Wed, 17 May 2023 16:49:25 -0700 Subject: [PATCH 054/111] Fix native build broken by glibc dependencies. Fix latest 8.0 runtime testing. (#3878) * Fix native build Update dependencies from https://github.com/dotnet/arcade build 20230424.1 Microsoft.DotNet.Arcade.Sdk , Microsoft.DotNet.CodeAnalysis From Version 8.0.0-beta.23168.1 -> To Version 8.0.0-beta.23224.1 Dependency coherency updates Microsoft.SourceLink.GitHub From Version 1.2.0-beta-23165-02 -> To Version 8.0.0-beta.23218.3 (parent: Microsoft.DotNet.Arcade.Sdk Update dependencies from https://github.com/dotnet/arcade build 20230505.2 Microsoft.DotNet.Arcade.Sdk , Microsoft.DotNet.CodeAnalysis From Version 8.0.0-beta.23168.1 -> To Version 8.0.0-beta.23255.2 Dependency coherency updates Microsoft.SourceLink.GitHub From Version 1.2.0-beta-23165-02 -> To Version 8.0.0-beta.23218.3 (parent: Microsoft.DotNet.Arcade.Sdk Update dependencies from https://github.com/dotnet/source-build-reference-packages build 20230512.1 Microsoft.SourceBuild.Intermediate.source-build-reference-packages From Version 8.0.0-alpha.1.23258.2 -> To Version 8.0.0-alpha.1.23262.1 Update dependencies from https://github.com/dotnet/arcade build 20230512.5 Microsoft.DotNet.Arcade.Sdk , Microsoft.DotNet.CodeAnalysis From Version 8.0.0-beta.23168.1 -> To Version 8.0.0-beta.23262.5 Dependency coherency updates Microsoft.SourceLink.GitHub From Version 1.2.0-beta-23165-02 -> To Version 8.0.0-beta.23218.3 (parent: Microsoft.DotNet.Arcade.Sdk Update dependencies from https://github.com/dotnet/installer build 20230514.2 Microsoft.Dotnet.Sdk.Internal From Version 8.0.100-preview.3.23156.1 -> To Version 8.0.100-preview.5.23264.2 Update dependencies from https://github.com/dotnet/runtime build 20230515.1 Microsoft.NETCore.App.Runtime.win-x64 , VS.Redist.Common.NetCore.SharedFramework.x64.8.0 From Version 8.0.0-preview.3.23155.1 -> To Version 8.0.0-preview.5.23265.1 Update dependencies from https://github.com/dotnet/aspnetcore build 20230515.1 Microsoft.AspNetCore.App.Ref , Microsoft.AspNetCore.App.Ref.Internal From Version 8.0.0-preview.4.23213.2 -> To Version 8.0.0-preview.5.23265.1 * Fix PR test legs --- Build.cmd | 2 +- build.sh | 2 +- diagnostics-codeql.yml | 231 +++--- diagnostics.yml | 708 ++++++++++-------- eng/CIBuild.cmd | 3 - eng/Version.Details.xml | 32 +- eng/Versions.props | 22 +- eng/build.ps1 | 2 +- eng/build.sh | 50 +- eng/ci-prepare-artifacts.cmd | 2 +- eng/cibuild.sh | 43 -- eng/common/cross/build-rootfs.sh | 166 ++-- eng/common/cross/toolchain.cmake | 52 +- eng/common/native/init-compiler.sh | 2 +- eng/common/templates/job/job.yml | 17 +- .../templates/steps/component-governance.yml | 13 + eng/common/tools.ps1 | 28 +- eng/common/tools.sh | 35 +- eng/docker-build.sh | 79 -- eng/{ => pipelines}/build.yml | 136 ++-- eng/pipelines/pipeline-resources.yml | 61 ++ eng/{ => pipelines}/prepare-release.yml | 0 global.json | 4 +- .../ClrMDHelper.cs | 36 +- .../DumpGenCommand.cs | 28 +- .../DumpStackObjectsCommand.cs | 2 +- .../GCGeneration.cs | 3 +- .../Unix/Debugger.Tests.Config.txt | 12 +- .../Windows/Debugger.Tests.Config.txt | 14 +- src/SOS/SOS.UnitTests/SOS.cs | 10 +- src/SOS/SOS.UnitTests/SOSRunner.cs | 4 + src/SOS/SOS.UnitTests/Scripts/DumpGen.script | 2 +- src/SOS/lldbplugin/CMakeLists.txt | 10 +- 33 files changed, 1018 insertions(+), 793 deletions(-) delete mode 100644 eng/CIBuild.cmd delete mode 100755 eng/cibuild.sh create mode 100644 eng/common/templates/steps/component-governance.yml delete mode 100755 eng/docker-build.sh rename eng/{ => pipelines}/build.yml (68%) create mode 100644 eng/pipelines/pipeline-resources.yml rename eng/{ => pipelines}/prepare-release.yml (100%) diff --git a/Build.cmd b/Build.cmd index 3de9ae405f..0a7b2aa973 100644 --- a/Build.cmd +++ b/Build.cmd @@ -1,3 +1,3 @@ @echo off -powershell -ExecutionPolicy ByPass -NoProfile -command "& """%~dp0eng\build.ps1""" -restore %*" +powershell -ExecutionPolicy ByPass -NoProfile -command "& """%~dp0eng\build.ps1""" -restore -build %*" exit /b %ErrorLevel% diff --git a/build.sh b/build.sh index 58a2abb50f..75055e9c92 100755 --- a/build.sh +++ b/build.sh @@ -13,4 +13,4 @@ while [[ -h $source ]]; do done scriptroot="$( cd -P "$( dirname "$source" )" && pwd )" -"$scriptroot/eng/build.sh" --restore $@ +"$scriptroot/eng/build.sh" --restore --build $@ diff --git a/diagnostics-codeql.yml b/diagnostics-codeql.yml index ee506ce6de..5cacd47b62 100644 --- a/diagnostics-codeql.yml +++ b/diagnostics-codeql.yml @@ -28,125 +28,128 @@ variables: - name: skipComponentGovernanceDetection value: true -stages: -- stage: build - displayName: Build and Test Diagnostics - jobs: - - template: /eng/build.yml - parameters: - name: Windows - osGroup: Windows_NT - isCodeQLRun: true - strategy: - matrix: - Build_Release: - _BuildConfig: Release - _BuildArch: x64 - Build_Release_x86: - _BuildConfig: Release - _BuildArch: x86 - Build_Release_arm: - _BuildConfig: Release - _BuildArch: arm - Build_Release_arm64: - _BuildConfig: Release - _BuildArch: arm64 +extends: + template: /eng/pipelines/pipeline-resources.yml + parameters: + stages: + - stage: build + displayName: Build and Test Diagnostics + jobs: + - template: /eng/pipelines/build.yml + parameters: + name: Windows + osGroup: Windows_NT + isCodeQLRun: true + strategy: + matrix: + Build_Release: + _BuildConfig: Release + _BuildArch: x64 + Build_Release_x86: + _BuildConfig: Release + _BuildArch: x86 + Build_Release_arm: + _BuildConfig: Release + _BuildArch: arm + Build_Release_arm64: + _BuildConfig: Release + _BuildArch: arm64 - - template: /eng/build.yml - parameters: - name: CentOS_7 - osGroup: Linux - dockerImage: mcr.microsoft.com/dotnet-buildtools/prereqs:centos-7-3e800f1-20190501005343 - isCodeQLRun: true - strategy: - matrix: - Build_Release: - _BuildConfig: Release - _BuildArch: x64 + - template: /eng/pipelines/build.yml + parameters: + name: Linux_x64 + osGroup: Linux + nativeBuildContainer: linux_x64 + isCodeQLRun: true + strategy: + matrix: + Build_Release: + _BuildConfig: Release + _BuildArch: x64 - - template: /eng/build.yml - parameters: - name: Alpine3_13 - osGroup: Linux - dockerImage: mcr.microsoft.com/dotnet-buildtools/prereqs:alpine-3.13-WithNode-20210910135845-c401c85 - isCodeQLRun: true - strategy: - matrix: - Build_Release: - _BuildConfig: Release - _BuildArch: x64 + - template: /eng/pipelines/build.yml + parameters: + name: Linux_musl + osGroup: Linux + nativeBuildContainer: linux_musl_x64 + isCodeQLRun: true + strategy: + matrix: + Build_Release: + _BuildConfig: Release + _BuildArch: x64 - - template: /eng/build.yml - parameters: - name: MacOS - osGroup: MacOS - isCodeQLRun: true - strategy: - matrix: - Build_Release: - _BuildConfig: Release - _BuildArch: x64 + - template: /eng/pipelines/build.yml + parameters: + name: MacOS + osGroup: MacOS + isCodeQLRun: true + strategy: + matrix: + Build_Release: + _BuildConfig: Release + _BuildArch: x64 - - template: /eng/build.yml - parameters: - name: MacOS_arm64 - osGroup: MacOS_cross - crossbuild: true - isCodeQLRun: true - strategy: - matrix: - Build_Release: - _BuildConfig: Release - _BuildArch: arm64 + - template: /eng/pipelines/build.yml + parameters: + name: MacOS_arm64 + osGroup: MacOS_cross + crossBuild: true + isCodeQLRun: true + strategy: + matrix: + Build_Release: + _BuildConfig: Release + _BuildArch: arm64 - - template: /eng/build.yml - parameters: - name: Linux_arm - osGroup: Linux - dockerImage: mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-16.04-cross-20210719121212-8a8d3be - crossrootfsDir: '/crossrootfs/arm' - isCodeQLRun: true - strategy: - matrix: - Build_Release: - _BuildConfig: Release - _BuildArch: arm + - template: /eng/pipelines/build.yml + parameters: + name: Linux_arm + osGroup: Linux + nativeBuildContainer: linux_arm + crossBuild: true + isCodeQLRun: true + strategy: + matrix: + Build_Release: + _BuildConfig: Release + _BuildArch: arm - - template: /eng/build.yml - parameters: - name: Linux_arm64 - osGroup: Linux - dockerImage: mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-16.04-cross-arm64-20210719121212-8a8d3be - crossrootfsDir: '/crossrootfs/arm64' - isCodeQLRun: true - strategy: - matrix: - Build_Release: - _BuildConfig: Release - _BuildArch: arm64 + - template: /eng/pipelines/build.yml + parameters: + name: Linux_arm64 + osGroup: Linux + nativeBuildContainer: linux_arm64 + crossBuild: true + isCodeQLRun: true + strategy: + matrix: + Build_Release: + _BuildConfig: Release + _BuildArch: arm64 - - template: /eng/build.yml - parameters: - name: Linux_musl_arm - osGroup: Linux - dockerImage: mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-16.04-cross-arm-alpine-20210923140502-78f7860 - crossrootfsDir: '/crossrootfs/arm' - isCodeQLRun: true - strategy: - matrix: - Build_Release: - _BuildConfig: Release - _BuildArch: arm + - template: /eng/pipelines/build.yml + parameters: + name: Linux_musl_arm + osGroup: Linux + nativeBuildContainer: linux_musl_arm + crossBuild: true + isCodeQLRun: true + strategy: + matrix: + Build_Release: + _BuildConfig: Release + _BuildArch: arm - - template: /eng/build.yml - parameters: - name: Linux_musl_arm64 - osGroup: Linux - dockerImage: mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-16.04-cross-arm64-alpine-20210923140502-78f7860 - crossrootfsDir: '/crossrootfs/arm64' - isCodeQLRun: true - strategy: - matrix: - Build_Release: - _BuildConfig: Release - _BuildArch: arm64 \ No newline at end of file + - template: /eng/pipelines/build.yml + parameters: + name: Linux_musl_arm64 + osGroup: Linux + nativeBuildContainer: linux_musl_arm64 + crossBuild: true + isCodeQLRun: true + strategy: + matrix: + Build_Release: + _BuildConfig: Release + _BuildArch: arm64 diff --git a/diagnostics.yml b/diagnostics.yml index df452f23b1..e8c56ccaa8 100644 --- a/diagnostics.yml +++ b/diagnostics.yml @@ -70,344 +70,420 @@ variables: - name: RuntimeFeedBase64SasToken value: $(dotnetclimsrc-read-sas-token-base64) -stages: - - stage: build - displayName: Build and Test Diagnostics - jobs: +extends: + template: /eng/pipelines/pipeline-resources.yml + parameters: + stages: + - stage: build + displayName: Build and Test Diagnostics + jobs: - ############################ - # # - # Source Build legs # - # # - ############################ + ############################ + # # + # Source Build legs # + # # + ############################ - - template: /eng/common/templates/job/source-build.yml - parameters: - platform: - name: Complete - buildScript: ./eng/common/build.sh + - template: /eng/common/templates/job/source-build.yml + parameters: + platform: + name: Complete + buildScript: ./eng/common/build.sh - ############################ - # # - # Build legs # - # # - ############################ + ############################ + # # + # Build legs # + # # + ############################ - - template: /eng/build.yml - parameters: - name: Windows - osGroup: Windows_NT - strategy: - matrix: - Build_Debug: - _BuildConfig: Debug - _BuildArch: x64 - Build_Release: - _BuildConfig: Release - _BuildArch: x64 - _PublishArtifacts: bin - Build_Release_x86: - _BuildConfig: Release - _BuildArch: x86 - _PublishArtifacts: bin/Windows_NT.x86.Release - ${{ if ne(variables['System.TeamProject'], 'public') }}: - Build_Release_arm: - _BuildConfig: Release - _BuildArch: arm - _PublishArtifacts: bin/Windows_NT.arm.Release - Build_Release_arm64: - _BuildConfig: Release - _BuildArch: arm64 - _PublishArtifacts: bin/Windows_NT.arm64.Release + - template: /eng/pipelines/build.yml + parameters: + name: Windows + osGroup: Windows_NT + strategy: + matrix: + Build_Debug: + _BuildConfig: Debug + _BuildArch: x64 + Build_Release: + _BuildConfig: Release + _BuildArch: x64 + _PublishArtifacts: bin + Build_Release_x86: + _BuildConfig: Release + _BuildArch: x86 + _PublishArtifacts: bin/Windows_NT.x86.Release + ${{ if ne(variables['System.TeamProject'], 'public') }}: + Build_Release_arm: + _BuildConfig: Release + _BuildArch: arm + _PublishArtifacts: bin/Windows_NT.arm.Release + Build_Release_arm64: + _BuildConfig: Release + _BuildArch: arm64 + _PublishArtifacts: bin/Windows_NT.arm64.Release - - template: /eng/build.yml - parameters: - name: CentOS_7 - osGroup: Linux - dockerImage: mcr.microsoft.com/dotnet-buildtools/prereqs:centos-7 - requiresCapPtraceContainer: true - buildAndSkipTest: true - strategy: - matrix: - Build_Debug: - _BuildConfig: Debug - _BuildArch: x64 - _PublishArtifacts: bin/Linux.x64.Debug - Build_Release: - _BuildConfig: Release - _BuildArch: x64 - _PublishArtifacts: bin/Linux.x64.Release + - template: /eng/pipelines/build.yml + parameters: + name: Linux_x64 + osGroup: Linux + nativeBuildContainer: linux_x64 + buildOnly: true + strategy: + matrix: + Build_Release: + _BuildConfig: Release + _BuildArch: x64 + _PublishArtifacts: bin/Linux.x64.Release + ${{ if in(variables['Build.Reason'], 'PullRequest') }}: + Build_Debug: + _BuildConfig: Debug + _BuildArch: x64 + _PublishArtifacts: bin/Linux.x64.Debug - - template: /eng/build.yml - parameters: - name: Alpine3_13 - osGroup: Linux - dockerImage: mcr.microsoft.com/dotnet-buildtools/prereqs:alpine-3.13-WithNode - artifactsTargetPath: bin/Linux-musl.x64.Release - requiresCapPtraceContainer: true - strategy: - matrix: - Build_Release: - _BuildConfig: Release - _BuildArch: x64 - _PublishArtifacts: bin/Linux.x64.Release - ${{ if in(variables['Build.Reason'], 'PullRequest') }}: - Build_Debug: - _BuildConfig: Debug - _BuildArch: x64 + - template: /eng/pipelines/build.yml + parameters: + name: Linux_musl + osGroup: Linux + osSuffix: -musl + nativeBuildContainer: linux_musl_x64 + buildOnly: true + strategy: + matrix: + Build_Release: + _BuildConfig: Release + _BuildArch: x64 + _PublishArtifacts: bin/Linux.x64.Release + _ArtifactsTargetPath: bin/Linux-musl.x64.Release + ${{ if in(variables['Build.Reason'], 'PullRequest') }}: + Build_Debug: + _BuildConfig: Debug + _BuildArch: x64 + _PublishArtifacts: bin/Linux.x64.Debug + _ArtifactsTargetPath: bin/Linux-musl.x64.Debug - - template: /eng/build.yml - parameters: - name: MacOS - osGroup: MacOS - strategy: - matrix: - Build_Release: - _BuildConfig: Release - _BuildArch: x64 - _PublishArtifacts: bin/OSX.x64.Release - ${{ if in(variables['Build.Reason'], 'PullRequest') }}: - Build_Debug: - _BuildConfig: Debug - _BuildArch: x64 + - template: /eng/pipelines/build.yml + parameters: + name: MacOS + osGroup: MacOS + strategy: + matrix: + Build_Release: + _BuildConfig: Release + _BuildArch: x64 + _PublishArtifacts: bin/OSX.x64.Release + ${{ if in(variables['Build.Reason'], 'PullRequest') }}: + Build_Debug: + _BuildConfig: Debug + _BuildArch: x64 - - template: /eng/build.yml - parameters: - name: MacOS_arm64 - osGroup: MacOS_cross - crossbuild: true - buildAndSkipTest: true - strategy: - matrix: - Build_Release: - _BuildConfig: Release - _BuildArch: arm64 - _PublishArtifacts: bin/OSX.arm64.Release - ${{ if in(variables['Build.Reason'], 'PullRequest') }}: - Build_Debug: - _BuildConfig: Debug - _BuildArch: arm64 + - template: /eng/pipelines/build.yml + parameters: + name: MacOS_arm64 + osGroup: MacOS_cross + crossBuild: true + buildOnly: true + strategy: + matrix: + Build_Release: + _BuildConfig: Release + _BuildArch: arm64 + _PublishArtifacts: bin/OSX.arm64.Release + ${{ if in(variables['Build.Reason'], 'PullRequest') }}: + Build_Debug: + _BuildConfig: Debug + _BuildArch: arm64 - - ${{ if ne(variables['System.TeamProject'], 'public') }}: - - template: /eng/build.yml - parameters: - name: Linux_arm - osGroup: Linux - dockerImage: mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-18.04-cross - crossrootfsDir: '/crossrootfs/arm' - buildAndSkipTest: true - strategy: - matrix: - Build_Release: - _BuildConfig: Release - _BuildArch: arm - _PublishArtifacts: bin/Linux.arm.Release + - ${{ if ne(variables['System.TeamProject'], 'public') }}: + - template: /eng/pipelines/build.yml + parameters: + name: Linux_arm + osGroup: Linux + nativeBuildContainer: linux_arm + crossBuild: true + buildOnly: true + strategy: + matrix: + Build_Release: + _BuildConfig: Release + _BuildArch: arm + _PublishArtifacts: bin/Linux.arm.Release - - template: /eng/build.yml - parameters: - name: Linux_arm64 - osGroup: Linux - dockerImage: mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-18.04-cross-arm64 - crossrootfsDir: '/crossrootfs/arm64' - buildAndSkipTest: true - strategy: - matrix: - Build_Release: - _BuildConfig: Release - _BuildArch: arm64 - _PublishArtifacts: bin/Linux.arm64.Release + - template: /eng/pipelines/build.yml + parameters: + name: Linux_arm64 + osGroup: Linux + nativeBuildContainer: linux_arm64 + crossBuild: true + buildOnly: true + strategy: + matrix: + Build_Release: + _BuildConfig: Release + _BuildArch: arm64 + _PublishArtifacts: bin/Linux.arm64.Release - - template: /eng/build.yml - parameters: - name: Linux_musl_arm - osGroup: Linux - dockerImage: mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-18.04-cross-arm-alpine - crossrootfsDir: '/crossrootfs/arm' - artifactsTargetPath: bin/Linux-musl.arm.Release - buildAndSkipTest: true - strategy: - matrix: - Build_Release: - _BuildConfig: Release - _BuildArch: arm - _PublishArtifacts: bin/Linux.arm.Release + - template: /eng/pipelines/build.yml + parameters: + name: Linux_musl_arm + osGroup: Linux + osSuffix: -musl + nativeBuildContainer: linux_musl_arm + crossBuild: true + buildOnly: true + strategy: + matrix: + Build_Release: + _BuildConfig: Release + _BuildArch: arm + _PublishArtifacts: bin/Linux.arm.Release + _ArtifactsTargetPath: bin/Linux-musl.arm.Release - - template: /eng/build.yml - parameters: - name: Linux_musl_arm64 - osGroup: Linux - dockerImage: mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-18.04-cross-arm64-alpine - crossrootfsDir: '/crossrootfs/arm64' - artifactsTargetPath: bin/Linux-musl.arm64.Release - buildAndSkipTest: true - strategy: - matrix: - Build_Release: - _BuildConfig: Release - _BuildArch: arm64 - _PublishArtifacts: bin/Linux.arm64.Release + - template: /eng/pipelines/build.yml + parameters: + name: Linux_musl_arm64 + osGroup: Linux + osSuffix: -musl + nativeBuildContainer: linux_musl_arm64 + crossBuild: true + buildOnly: true + strategy: + matrix: + Build_Release: + _BuildConfig: Release + _BuildArch: arm64 + _PublishArtifacts: bin/Linux.arm64.Release + _ArtifactsTargetPath: bin/Linux-musl.arm64.Release - ############################ - # # - # Test only legs # - # # - ############################ + ############################ + # # + # Test only legs # + # # + ############################ - - template: /eng/build.yml - parameters: - name: Debian_Bullseye - osGroup: Linux - dockerImage: mcr.microsoft.com/dotnet-buildtools/prereqs:debian-11-amd64 - dependsOn: CentOS_7 - testOnly: true - strategy: - matrix: - Build_Debug: - _BuildConfig: Debug - _BuildArch: x64 + - template: /eng/pipelines/build.yml + parameters: + name: Ubuntu_20_04 + osGroup: Linux + container: test_ubuntu_20_04 + dependsOn: Linux_x64 + testOnly: true + strategy: + matrix: + Build_Release: + _BuildConfig: Release + _BuildArch: x64 + ${{ if in(variables['Build.Reason'], 'PullRequest') }}: + Build_Debug: + _BuildConfig: Debug + _BuildArch: x64 -# - template: /eng/build.yml -# parameters: -# name: Fedora_34 -# osGroup: Linux -# dockerImage: mcr.microsoft.com/dotnet-buildtools/prereqs:fedora-34-helix -# dependsOn: CentOS_7 -# testOnly: true -# requiresCapPtraceContainer: true -# strategy: -# matrix: -# Build_Debug: -# _BuildConfig: Debug -# _BuildArch: x64 + - template: /eng/pipelines/build.yml + parameters: + name: Alpine3_13 + osGroup: Linux + osSuffix: -musl + container: test_linux_musl_x64 + dependsOn: Linux_musl + testOnly: true + strategy: + matrix: + Build_Release: + _BuildConfig: Release + _BuildArch: x64 + ${{ if in(variables['Build.Reason'], 'PullRequest') }}: + Build_Debug: + _BuildConfig: Debug + _BuildArch: x64 -# - template: /eng/build.yml -# parameters: -# name: OpenSuse_15_2 -# osGroup: Linux -# dockerImage: mcr.microsoft.com/dotnet-buildtools/prereqs:opensuse-15.2-helix-amd64 -# dependsOn: CentOS_7 -# testOnly: true -# strategy: -# matrix: -# Build_Debug: -# _BuildConfig: Debug -# _BuildArch: x64 + - ${{ if ne(variables['System.TeamProject'], 'public') }}: + - template: /eng/pipelines/build.yml + parameters: + name: Debian_Bullseye + osGroup: Linux + container: test_debian_11_amd64 + dependsOn: Linux_x64 + testOnly: true + strategy: + matrix: + Build_Release: + _BuildConfig: Release + _BuildArch: x64 + ${{ if in(variables['Build.Reason'], 'PullRequest') }}: + Build_Debug: + _BuildConfig: Debug + _BuildArch: x64 - - template: /eng/build.yml - parameters: - name: Ubuntu_18_04 - osGroup: Linux - dockerImage: mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-18.04 - dependsOn: CentOS_7 - testOnly: true - strategy: - matrix: - Build_Debug: - _BuildConfig: Debug - _BuildArch: x64 + - template: /eng/pipelines/build.yml + parameters: + name: Fedora_36 + osGroup: Linux + container: test_fedora_36 + dependsOn: Linux_x64 + testOnly: true + strategy: + matrix: + Build_Release: + _BuildConfig: Release + _BuildArch: x64 + ${{ if in(variables['Build.Reason'], 'PullRequest') }}: + Build_Debug: + _BuildConfig: Debug + _BuildArch: x64 - # Download, sign, package and publish - - ${{ if notin(variables['Build.Reason'], 'PullRequest') }}: - - template: /eng/common/templates/job/job.yml - parameters: - name: Sign_Package_Publish - displayName: Sign, Package, and Generate BAR Manifests - dependsOn: - - Windows - - CentOS_7 - - Alpine3_13 - - MacOS - - MacOS_arm64 - - Linux_arm - - Linux_arm64 - - Linux_musl_arm - - Linux_musl_arm64 - condition: succeeded() - pool: - name: NetCore1ESPool-Internal - demands: ImageOverride -equals windows.vs2022.amd64 - enablePublishUsingPipelines: true - enableMicrobuild: true - artifacts: - publish: - logs: - name: Logs_Packaging_Signing - steps: - - task: DownloadBuildArtifacts@0 - displayName: 'Download release builds' - inputs: - downloadPath: '$(Build.ArtifactStagingDirectory)/__download__' - artifactName: Build_Release - checkDownloadedFiles: true - - task: CopyFiles@2 - displayName: 'Binplace Product' - inputs: - sourceFolder: $(Build.ArtifactStagingDirectory)/__download__/Build_Release - targetFolder: '$(Build.SourcesDirectory)/artifacts/' + #- template: /eng/pipelines/build.yml + # parameters: + # name: OpenSuse_15_2 + # osGroup: Linux + # container: test_opensuse_15_2 + # dependsOn: Linux_x64 + # testOnly: true + # strategy: + # matrix: + # Build_Release: + # _BuildConfig: Release + # _BuildArch: x64 + # ${{ if in(variables['Build.Reason'], 'PullRequest') }}: + # Build_Debug: + # _BuildConfig: Debug + # _BuildArch: x64 - # Windows x64 download. Everything under "bin" is published for the Windows x64 build. - # Create nuget packages, sign binaries and publish to blob feed - - script: $(Build.SourcesDirectory)\eng\ci-prepare-artifacts.cmd $(_InternalBuildArgs) - displayName: Package, Sign, and Publish - continueOnError: false + #- template: /eng/pipelines/build.yml + # parameters: + # name: Ubuntu_18_04 + # osGroup: Linux + # container: test_ubuntu_18_04 + # dependsOn: Linux_x64 + # testOnly: true + # strategy: + # matrix: + # Build_Release: + # _BuildConfig: Release + # _BuildArch: x64 + # ${{ if in(variables['Build.Reason'], 'PullRequest') }}: + # Build_Debug: + # _BuildConfig: Debug + # _BuildArch: x64 + + #- template: /eng/pipelines/build.yml + # parameters: + # name: Ubuntu_22_04 + # osGroup: Linux + # container: test_ubuntu_22_04 + # dependsOn: Linux_x64 + # testOnly: true + # strategy: + # matrix: + # Build_Release: + # _BuildConfig: Release + # _BuildArch: x64 + # ${{ if in(variables['Build.Reason'], 'PullRequest') }}: + # Build_Debug: + # _BuildConfig: Debug + # _BuildArch: x64 + + # Download, sign, package and publish + - ${{ if notin(variables['Build.Reason'], 'PullRequest') }}: + - template: /eng/common/templates/job/job.yml + parameters: + name: Sign_Package_Publish + displayName: Sign, Package, and Generate BAR Manifests + dependsOn: + - Windows + - MacOS + - MacOS_arm64 + - Linux_x64 + - Linux_musl + - Linux_arm + - Linux_arm64 + - Linux_musl_arm + - Linux_musl_arm64 condition: succeeded() + pool: + name: NetCore1ESPool-Internal + demands: ImageOverride -equals windows.vs2022.amd64 + enablePublishUsingPipelines: true + enableMicrobuild: true + artifacts: + publish: + logs: + name: Logs_Packaging_Signing + steps: + - task: DownloadBuildArtifacts@0 + displayName: 'Download release builds' + inputs: + downloadPath: '$(Build.ArtifactStagingDirectory)/__download__' + artifactName: Build_Release + checkDownloadedFiles: true + - task: CopyFiles@2 + displayName: 'Binplace Product' + inputs: + sourceFolder: $(Build.ArtifactStagingDirectory)/__download__/Build_Release + targetFolder: '$(Build.SourcesDirectory)/artifacts/' - # Publish package and log build artifacts - - task: PublishBuildArtifacts@1 - displayName: Publish Package Artifacts - inputs: - publishLocation: Container - pathtoPublish: '$(Build.SourcesDirectory)/artifacts/packages' - artifactName: Packages - continueOnError: true - condition: always() + # Windows x64 download. Everything under "bin" is published for the Windows x64 build. + # Create nuget packages, sign binaries and publish to blob feed + - script: $(Build.SourcesDirectory)\eng\ci-prepare-artifacts.cmd $(_InternalBuildArgs) + displayName: Package, Sign, and Publish + continueOnError: false + condition: succeeded() - - task: PublishBuildArtifacts@1 - displayName: Publish Bundled Tools - inputs: - publishLocation: Container - pathtoPublish: '$(Build.SourcesDirectory)/artifacts/bundledtools' - artifactName: BundledTools - continueOnError: true - condition: always() + # Publish package and log build artifacts + - task: PublishBuildArtifacts@1 + displayName: Publish Package Artifacts + inputs: + publishLocation: Container + pathtoPublish: '$(Build.SourcesDirectory)/artifacts/packages' + artifactName: Packages + continueOnError: true + condition: always() - - template: /eng/common/templates/job/publish-build-assets.yml - parameters: - configuration: Release - dependsOn: Sign_Package_Publish - publishUsingPipelines: true - pool: - name: NetCore1ESPool-Internal - demands: ImageOverride -equals windows.vs2022.amd64 + - task: PublishBuildArtifacts@1 + displayName: Publish Bundled Tools + inputs: + publishLocation: Container + pathtoPublish: '$(Build.SourcesDirectory)/artifacts/bundledtools' + artifactName: BundledTools + continueOnError: true + condition: always() - - ${{ if and(ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}: - - template: /eng/common/templates/post-build/post-build.yml - parameters: - # This is to enable SDL runs part of Post-Build Validation Stage. - # as well as NuGet, SourceLink, and signing validation. - # The variables get imported from group dotnet-diagnostics-sdl-params - publishingInfraVersion: 3 - enableSourceLinkValidation: true - enableSigningValidation: false - enableSymbolValidation: false - enableNugetValidation: true - symbolPublishingAdditionalParameters: '/p:PublishSpecialClrFiles=false' - publishInstallersAndChecksums: true - SDLValidationParameters: - enable: true - continueOnError: true - params: ' -SourceToolsList @("policheck","credscan") - -TsaInstanceURL $(_TsaInstanceURL) - -TsaProjectName $(_TsaProjectName) - -TsaNotificationEmail $(_TsaNotificationEmail) - -TsaCodebaseAdmin $(_TsaCodebaseAdmin) - -TsaBugAreaPath $(_TsaBugAreaPath) - -TsaIterationPath $(_TsaIterationPath) - -TsaRepositoryName "diagnostics" - -TsaCodebaseName "diagnostics" - -TsaPublish $True' - artifactNames: - - 'Packages' + - template: /eng/common/templates/job/publish-build-assets.yml + parameters: + configuration: Release + dependsOn: Sign_Package_Publish + publishUsingPipelines: true + pool: + name: NetCore1ESPool-Internal + demands: ImageOverride -equals windows.vs2022.amd64 + + - ${{ if and(ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}: + - template: /eng/common/templates/post-build/post-build.yml + parameters: + # This is to enable SDL runs part of Post-Build Validation Stage. + # as well as NuGet, SourceLink, and signing validation. + # The variables get imported from group dotnet-diagnostics-sdl-params + publishingInfraVersion: 3 + enableSourceLinkValidation: true + enableSigningValidation: false + enableSymbolValidation: false + enableNugetValidation: true + symbolPublishingAdditionalParameters: '/p:PublishSpecialClrFiles=false' + publishInstallersAndChecksums: true + SDLValidationParameters: + enable: true + continueOnError: true + params: ' -SourceToolsList @("policheck","credscan") + -TsaInstanceURL $(_TsaInstanceURL) + -TsaProjectName $(_TsaProjectName) + -TsaNotificationEmail $(_TsaNotificationEmail) + -TsaCodebaseAdmin $(_TsaCodebaseAdmin) + -TsaBugAreaPath $(_TsaBugAreaPath) + -TsaIterationPath $(_TsaIterationPath) + -TsaRepositoryName "diagnostics" + -TsaCodebaseName "diagnostics" + -TsaPublish $True' + artifactNames: + - 'Packages' - # This sets up the bits to do a Release. - - template: /eng/prepare-release.yml + # This sets up the bits to do a Release. + - template: /eng/pipelines/prepare-release.yml diff --git a/eng/CIBuild.cmd b/eng/CIBuild.cmd deleted file mode 100644 index df9ae6479c..0000000000 --- a/eng/CIBuild.cmd +++ /dev/null @@ -1,3 +0,0 @@ -@echo off -powershell -ExecutionPolicy ByPass -NoProfile -command "& """%~dp0build.ps1""" -restore -ci -prepareMachine %*" -exit /b %ErrorLevel% diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 84602c8166..fc47a40c7a 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -14,47 +14,47 @@ - + https://github.com/dotnet/arcade - b12f035e893c34ec2c965d75f6e21b7a2667e98d + 1aff4eb33aa7cbf26ccd9fc43c17cb609a14dad4 - + https://github.com/dotnet/arcade - b12f035e893c34ec2c965d75f6e21b7a2667e98d + 1aff4eb33aa7cbf26ccd9fc43c17cb609a14dad4 https://github.com/dotnet/arcade ccfe6da198c5f05534863bbb1bff66e830e0c6ab - + https://github.com/dotnet/installer - 51e06f6931e859f56564556fa6ba519761fa7141 + 8488614afec7497b9e74b47c976af2a97506bb96 - + https://github.com/dotnet/aspnetcore - 68ae6b0d8aa2f4a0ff189d5cedc741e32cc643d2 + dba677f5fbf85666aac3009b16e5c05d93ec63ca - + https://github.com/dotnet/aspnetcore - 68ae6b0d8aa2f4a0ff189d5cedc741e32cc643d2 + dba677f5fbf85666aac3009b16e5c05d93ec63ca - + https://github.com/dotnet/runtime - a64420c79cb63c485138f4f1352b8730f27d7b19 + 4c0f2e7bd4cb86917e362052e0642df600984b6c - + https://github.com/dotnet/runtime - a64420c79cb63c485138f4f1352b8730f27d7b19 + 4c0f2e7bd4cb86917e362052e0642df600984b6c https://github.com/dotnet/source-build-reference-packages fd98754b692a1a8da2aaadd28ce3952578d9d9ad - + https://github.com/dotnet/sourcelink - 3f43bf1b2dead2cb51f20dc47f6dfd7981248820 + 47c52dd2ebf9edfd40abdcff999c13eb461f6ce2 diff --git a/eng/Versions.props b/eng/Versions.props index 926f61bd0c..3bc41fd550 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -18,24 +18,24 @@ 1.0.426501 - 8.0.0-preview.3.23155.1 - 8.0.0-preview.3.23155.1 + 8.0.0-preview.5.23265.1 + 8.0.0-preview.5.23265.1 - 8.0.0-preview.4.23213.2 - 8.0.0-preview.4.23213.2 + 8.0.0-preview.5.23265.1 + 8.0.0-preview.5.23265.1 - 8.0.100-preview.3.23156.1 + 8.0.100-preview.5.23264.2 - 6.0.14 + 6.0.16 $(MicrosoftNETCoreApp60Version) - 7.0.3 + 7.0.5 $(MicrosoftNETCoreApp70Version) $(MicrosoftNETCoreApp60Version) - 7.0.2 - 8.0.0-preview.2.23127.4 + $(MicrosoftNETCoreApp70Version) + 8.0.0-preview.5.23260.3 @@ -61,13 +61,13 @@ 4.7.2 4.7.1 2.0.3 - 8.0.0-beta.23168.1 + 8.0.0-beta.23262.5 1.2.0-beta.406 7.0.0-beta.22316.2 10.0.18362 13.0.1 8.0.0-alpha.1.23266.4 - 1.2.0-beta-23165-02 + 8.0.0-beta.23218.3 3.11.0 diff --git a/eng/build.ps1 b/eng/build.ps1 index b107d42088..6bf2d4f694 100644 --- a/eng/build.ps1 +++ b/eng/build.ps1 @@ -59,7 +59,7 @@ if ($cleanupprivatebuild) { # Install sdk for building, restore and build managed components. if (-not $skipmanaged) { - Invoke-Expression "& `"$engroot\common\build.ps1`" -build -configuration $configuration -verbosity $verbosity /p:BuildArch=$architecture /p:TestArchitectures=$architecture $remainingargs" + Invoke-Expression "& `"$engroot\common\build.ps1`" -configuration $configuration -verbosity $verbosity /p:BuildArch=$architecture /p:TestArchitectures=$architecture $remainingargs" if ($lastExitCode -ne 0) { exit $lastExitCode } diff --git a/eng/build.sh b/eng/build.sh index 92bef5bea0..ae11013d07 100755 --- a/eng/build.sh +++ b/eng/build.sh @@ -41,14 +41,14 @@ usage_list+=("-test: run xunit tests") handle_arguments() { - lowerI="$(echo "$1" | tr "[:upper:]" "[:lower:]")" + lowerI="$(echo "${1/--/-}" | tr "[:upper:]" "[:lower:]")" case "$lowerI" in architecture|-architecture|-a) __BuildArch="$(echo "$2" | tr "[:upper:]" "[:lower:]")" __ShiftArgs=1 ;; - -binarylog|-bl|-clean|-integrationtest|-pack|-performancetest|-pipelineslog|-pl|-preparemachine|-publish|-r|-rebuild|-restore|-sign|-sb) + -binarylog|-bl|-clean|-integrationtest|-pack|-performancetest|-pipelineslog|-pl|-preparemachine|-publish|-r|-rebuild|-build|-restore|-sign|-sb) __ManagedBuildArgs="$__ManagedBuildArgs $1" ;; @@ -63,10 +63,6 @@ handle_arguments() { __ShiftArgs=1 ;; - -clean|-binarylog|-bl|-pipelineslog|-pl|-restore|-r|-rebuild|-pack|-integrationtest|-performancetest|-sign|-publish|-preparemachine|-sb) - __ManagedBuildArgs="$__ManagedBuildArgs $1" - ;; - -dotnetruntimeversion) __DotnetRuntimeVersion="$2" __ShiftArgs=1 @@ -148,11 +144,32 @@ fi # if [[ "$__ManagedBuild" == 1 ]]; then + echo "Commencing managed build for $__BuildType in $__RootBinDir/bin" - "$__RepoRootDir/eng/common/build.sh" --build --configuration "$__BuildType" $__CommonMSBuildArgs $__ManagedBuildArgs $__UnprocessedBuildArgs + "$__RepoRootDir/eng/common/build.sh" --configuration "$__BuildType" $__CommonMSBuildArgs $__ManagedBuildArgs $__UnprocessedBuildArgs + if [ "$?" != 0 ]; then exit 1 fi + + echo "Generating Version Source File" + __GenerateVersionLog="$__LogsDir/GenerateVersion.binlog" + + "$__RepoRootDir/eng/common/msbuild.sh" \ + $__RepoRootDir/eng/CreateVersionFile.proj \ + /bl:$__GenerateVersionLog \ + /t:GenerateVersionFiles \ + /restore \ + /p:GenerateVersionSourceFile=true \ + /p:NativeVersionSourceFile="$__ArtifactsIntermediatesDir/_version.c" \ + /p:Configuration="$__BuildType" \ + /p:Platform="$__BuildArch" \ + $__UnprocessedBuildArgs + + if [ $? != 0 ]; then + echo "Generating Version Source File FAILED" + exit 1 + fi fi # @@ -198,25 +215,6 @@ fi # Build native components # if [[ "$__NativeBuild" == 1 ]]; then - echo "Generating Version Source File" - __GenerateVersionLog="$__LogsDir/GenerateVersion.binlog" - - "$__RepoRootDir/eng/common/msbuild.sh" \ - $__RepoRootDir/eng/CreateVersionFile.proj \ - /bl:$__GenerateVersionLog \ - /t:GenerateVersionFiles \ - /restore \ - /p:GenerateVersionSourceFile=true \ - /p:NativeVersionSourceFile="$__ArtifactsIntermediatesDir/_version.c" \ - /p:Configuration="$__BuildType" \ - /p:Platform="$__BuildArch" \ - $__UnprocessedBuildArgs - - if [ $? != 0 ]; then - echo "Generating Version Source File FAILED" - exit 1 - fi - build_native "$__TargetOS" "$__BuildArch" "$__RepoRootDir" "$__IntermediatesDir" "install" "$__ExtraCmakeArgs" "diagnostic component" | tee "$__LogsDir"/make.log if [ "$?" != 0 ]; then diff --git a/eng/ci-prepare-artifacts.cmd b/eng/ci-prepare-artifacts.cmd index 5632c47db3..af95f7c3aa 100644 --- a/eng/ci-prepare-artifacts.cmd +++ b/eng/ci-prepare-artifacts.cmd @@ -9,7 +9,7 @@ powershell -ExecutionPolicy ByPass -NoProfile -command "& """%~dp0common\Build.p if NOT '%ERRORLEVEL%' == '0' goto ExitWithCode echo Creating bundles -powershell -ExecutionPolicy ByPass -NoProfile -command "& """%~dp0Build.ps1""" %_commonArgs% -bundletools %*" +powershell -ExecutionPolicy ByPass -NoProfile -command "& """%~dp0Build.ps1""" %_commonArgs% -build -bundletools %*" if NOT '%ERRORLEVEL%' == '0' goto ExitWithCode echo Creating dbgshim packages diff --git a/eng/cibuild.sh b/eng/cibuild.sh deleted file mode 100755 index cb0000ebc1..0000000000 --- a/eng/cibuild.sh +++ /dev/null @@ -1,43 +0,0 @@ -#!/usr/bin/env bash -# Copyright (c) .NET Foundation and contributors. All rights reserved. -# Licensed under the MIT license. See LICENSE file in the project root for full license information. - -source="${BASH_SOURCE[0]}" - -# resolve $SOURCE until the file is no longer a symlink -while [[ -h $source ]]; do - scriptroot="$( cd -P "$( dirname "$source" )" && pwd )" - source="$(readlink "$source")" - - # if $source was a relative symlink, we need to resolve it relative to the path where - # the symlink file was located - [[ $source != /* ]] && source="$scriptroot/$source" -done - -scriptroot="$( cd -P "$( dirname "$source" )" && pwd )" - -# Fix any CI lab docker image problems - -__osname=$(uname -s) -if [ "$__osname" == "Linux" ]; then - if [ -e /etc/os-release ]; then - source /etc/os-release - if [[ $ID == "ubuntu" ]]; then - if [[ $VERSION_ID == "18.04" ]]; then - # Fix the CI lab's ubuntu 18.04 docker image: install curl. - sudo apt-get update - sudo apt-get install -y curl - fi - fi - elif [ -e /etc/redhat-release ]; then - __redhatRelease=$( "$__ApkKeysDir/alpine-devel@lists.alpinelinux.org-$id.rsa.pub" + done + + if [[ "$__SkipSigCheck" == "1" ]]; then + __ApkSignatureArg="--allow-untrusted" + else + __ApkSignatureArg="--keys-dir $__ApkKeysDir" + fi + # initialize DB "$__ApkToolsDir/apk.static" \ -X "http://dl-cdn.alpinelinux.org/alpine/$version/main" \ -X "http://dl-cdn.alpinelinux.org/alpine/$version/community" \ - -U --allow-untrusted --root "$__RootfsDir" --arch "$__AlpineArch" --initdb add + -U $__ApkSignatureArg --root "$__RootfsDir" --arch "$__AlpineArch" --initdb add if [[ "$__AlpineLlvmLibsLookup" == 1 ]]; then __AlpinePackages+=" $("$__ApkToolsDir/apk.static" \ -X "http://dl-cdn.alpinelinux.org/alpine/$version/main" \ -X "http://dl-cdn.alpinelinux.org/alpine/$version/community" \ - -U --allow-untrusted --root "$__RootfsDir" --arch "$__AlpineArch" \ + -U $__ApkSignatureArg --root "$__RootfsDir" --arch "$__AlpineArch" \ search 'llvm*-libs' | sort | tail -1 | sed 's/-[^-]*//2g')" fi @@ -438,7 +494,7 @@ if [[ "$__CodeName" == "alpine" ]]; then "$__ApkToolsDir/apk.static" \ -X "http://dl-cdn.alpinelinux.org/alpine/$version/main" \ -X "http://dl-cdn.alpinelinux.org/alpine/$version/community" \ - -U --allow-untrusted --root "$__RootfsDir" --arch "$__AlpineArch" \ + -U $__ApkSignatureArg --root "$__RootfsDir" --arch "$__AlpineArch" \ add $__AlpinePackages rm -r "$__ApkToolsDir" @@ -512,69 +568,61 @@ elif [[ "$__CodeName" == "illumos" ]]; then elif [[ "$__CodeName" == "haiku" ]]; then JOBS=${MAXJOBS:="$(getconf _NPROCESSORS_ONLN)"} - echo "Building Haiku sysroot for x86_64" + echo "Building Haiku sysroot for $__HaikuArch" mkdir -p "$__RootfsDir/tmp" - cd "$__RootfsDir/tmp" - git clone -b hrev56235 https://review.haiku-os.org/haiku - git clone -b btrev43195 https://review.haiku-os.org/buildtools - cd "$__RootfsDir/tmp/buildtools" && git checkout 7487388f5110021d400b9f3b88e1a7f310dc066d - - # Fetch some unmerged patches - cd "$__RootfsDir/tmp/haiku" - ## Add development build profile (slimmer than nightly) - git fetch origin refs/changes/64/4164/1 && git -c commit.gpgsign=false cherry-pick FETCH_HEAD - - # Build jam - cd "$__RootfsDir/tmp/buildtools/jam" - make - - # Configure cross tools - echo "Building cross-compiler" - mkdir -p "$__RootfsDir/generated" - cd "$__RootfsDir/generated" - "$__RootfsDir/tmp/haiku/configure" -j"$JOBS" --sysroot "$__RootfsDir" --cross-tools-source "$__RootfsDir/tmp/buildtools" --build-cross-tools x86_64 - - # Build Haiku packages - echo "Building Haiku" - echo 'HAIKU_BUILD_PROFILE = "development-raw" ;' > UserProfileConfig - "$__RootfsDir/tmp/buildtools/jam/jam0" -j"$JOBS" -q 'package' 'Haiku' - - BaseUrl="https://depot.haiku-os.org/__api/v2/pkg/get-pkg" - - # Download additional packages - echo "Downloading additional required packages" + pushd "$__RootfsDir/tmp" + + mkdir "$__RootfsDir/tmp/download" + + echo "Downloading Haiku package tool" + git clone https://github.com/haiku/haiku-toolchains-ubuntu --depth 1 $__RootfsDir/tmp/script + wget -O "$__RootfsDir/tmp/download/hosttools.zip" $($__RootfsDir/tmp/script/fetch.sh --hosttools) + unzip -o "$__RootfsDir/tmp/download/hosttools.zip" -d "$__RootfsDir/tmp/bin" + + DepotBaseUrl="https://depot.haiku-os.org/__api/v2/pkg/get-pkg" + HpkgBaseUrl="https://eu.hpkg.haiku-os.org/haiku/master/$__HaikuArch/current" + + # Download Haiku packages + echo "Downloading Haiku packages" read -ra array <<<"$__HaikuPackages" for package in "${array[@]}"; do echo "Downloading $package..." # API documented here: https://github.com/haiku/haikudepotserver/blob/master/haikudepotserver-api2/src/main/resources/api2/pkg.yaml#L60 # The schema here: https://github.com/haiku/haikudepotserver/blob/master/haikudepotserver-api2/src/main/resources/api2/pkg.yaml#L598 - hpkgDownloadUrl="$(wget -qO- --post-data='{"name":"'"$package"'","repositorySourceCode":"haikuports_x86_64","versionType":"LATEST","naturalLanguageCode":"en"}' \ - --header='Content-Type:application/json' "$BaseUrl" | jq -r '.result.versions[].hpkgDownloadURL')" - wget -P "$__RootfsDir/generated/download" "$hpkgDownloadUrl" + hpkgDownloadUrl="$(wget -qO- --post-data='{"name":"'"$package"'","repositorySourceCode":"haikuports_'$__HaikuArch'","versionType":"LATEST","naturalLanguageCode":"en"}' \ + --header='Content-Type:application/json' "$DepotBaseUrl" | jq -r '.result.versions[].hpkgDownloadURL')" + wget -P "$__RootfsDir/tmp/download" "$hpkgDownloadUrl" + done + for package in haiku haiku_devel; do + echo "Downloading $package..." + hpkgVersion="$(wget -qO- $HpkgBaseUrl | sed -n 's/^.*version: "\([^"]*\)".*$/\1/p')" + wget -P "$__RootfsDir/tmp/download" "$HpkgBaseUrl/packages/$package-$hpkgVersion-1-$__HaikuArch.hpkg" done - # Setup the sysroot - echo "Setting up sysroot and extracting needed packages" + # Set up the sysroot + echo "Setting up sysroot and extracting required packages" mkdir -p "$__RootfsDir/boot/system" - for file in "$__RootfsDir/generated/objects/haiku/x86_64/packaging/packages/"*.hpkg; do - "$__RootfsDir/generated/objects/linux/x86_64/release/tools/package/package" extract -C "$__RootfsDir/boot/system" "$file" - done - for file in "$__RootfsDir/generated/download/"*.hpkg; do - "$__RootfsDir/generated/objects/linux/x86_64/release/tools/package/package" extract -C "$__RootfsDir/boot/system" "$file" + for file in "$__RootfsDir/tmp/download/"*.hpkg; do + echo "Extracting $file..." + LD_LIBRARY_PATH="$__RootfsDir/tmp/bin" "$__RootfsDir/tmp/bin/package" extract -C "$__RootfsDir/boot/system" "$file" done + # Download buildtools + echo "Downloading Haiku buildtools" + wget -O "$__RootfsDir/tmp/download/buildtools.zip" $($__RootfsDir/tmp/script/fetch.sh --buildtools --arch=$__HaikuArch) + unzip -o "$__RootfsDir/tmp/download/buildtools.zip" -d "$__RootfsDir" + # Cleaning up temporary files echo "Cleaning up temporary files" + popd rm -rf "$__RootfsDir/tmp" - for name in "$__RootfsDir/generated/"*; do - if [[ "$name" =~ "cross-tools-" ]]; then - : # Keep the cross-compiler - else - rm -rf "$name" - fi - done elif [[ -n "$__CodeName" ]]; then - qemu-debootstrap $__Keyring --arch "$__UbuntuArch" "$__CodeName" "$__RootfsDir" "$__UbuntuRepo" + + if [[ "$__SkipSigCheck" == "0" ]]; then + __Keyring="$__Keyring --force-check-gpg" + fi + + debootstrap "--variant=minbase" $__Keyring --arch "$__UbuntuArch" "$__CodeName" "$__RootfsDir" "$__UbuntuRepo" cp "$__CrossDir/$__BuildArch/sources.list.$__CodeName" "$__RootfsDir/etc/apt/sources.list" chroot "$__RootfsDir" apt-get update chroot "$__RootfsDir" apt-get -f -y install diff --git a/eng/common/cross/toolchain.cmake b/eng/common/cross/toolchain.cmake index ccfb9951a5..a88d643c8a 100644 --- a/eng/common/cross/toolchain.cmake +++ b/eng/common/cross/toolchain.cmake @@ -6,6 +6,7 @@ unset(FREEBSD) unset(ILLUMOS) unset(ANDROID) unset(TIZEN) +unset(HAIKU) set(TARGET_ARCH_NAME $ENV{TARGET_BUILD_ARCH}) if(EXISTS ${CROSS_ROOTFS}/bin/freebsd-version) @@ -16,6 +17,7 @@ elseif(EXISTS ${CROSS_ROOTFS}/usr/platform/i86pc) set(ILLUMOS 1) elseif(EXISTS ${CROSS_ROOTFS}/boot/system/develop/headers/config/HaikuConfig.h) set(CMAKE_SYSTEM_NAME Haiku) + set(HAIKU 1) else() set(CMAKE_SYSTEM_NAME Linux) set(LINUX 1) @@ -67,16 +69,30 @@ elseif(TARGET_ARCH_NAME STREQUAL "armv6") endif() elseif(TARGET_ARCH_NAME STREQUAL "ppc64le") set(CMAKE_SYSTEM_PROCESSOR ppc64le) - set(TOOLCHAIN "powerpc64le-linux-gnu") + if(EXISTS ${CROSS_ROOTFS}/usr/lib/gcc/powerpc64le-alpine-linux-musl) + set(TOOLCHAIN "powerpc64le-alpine-linux-musl") + else() + set(TOOLCHAIN "powerpc64le-linux-gnu") + endif() elseif(TARGET_ARCH_NAME STREQUAL "riscv64") set(CMAKE_SYSTEM_PROCESSOR riscv64) - set(TOOLCHAIN "riscv64-linux-gnu") + if(EXISTS ${CROSS_ROOTFS}/usr/lib/gcc/riscv64-alpine-linux-musl) + set(TOOLCHAIN "riscv64-alpine-linux-musl") + else() + set(TOOLCHAIN "riscv64-linux-gnu") + endif() elseif(TARGET_ARCH_NAME STREQUAL "s390x") set(CMAKE_SYSTEM_PROCESSOR s390x) - set(TOOLCHAIN "s390x-linux-gnu") + if(EXISTS ${CROSS_ROOTFS}/usr/lib/gcc/s390x-alpine-linux-musl) + set(TOOLCHAIN "s390x-alpine-linux-musl") + else() + set(TOOLCHAIN "s390x-linux-gnu") + endif() elseif(TARGET_ARCH_NAME STREQUAL "x64") set(CMAKE_SYSTEM_PROCESSOR x86_64) - if(LINUX) + if(EXISTS ${CROSS_ROOTFS}/usr/lib/gcc/x86_64-alpine-linux-musl) + set(TOOLCHAIN "x86_64-alpine-linux-musl") + elseif(LINUX) set(TOOLCHAIN "x86_64-linux-gnu") if(TIZEN) set(TIZEN_TOOLCHAIN "x86_64-tizen-linux-gnu/9.2.0") @@ -86,11 +102,15 @@ elseif(TARGET_ARCH_NAME STREQUAL "x64") elseif(ILLUMOS) set(TOOLCHAIN "x86_64-illumos") elseif(HAIKU) - set(TOOLCHAIN "x64_64-unknown-haiku") + set(TOOLCHAIN "x86_64-unknown-haiku") endif() elseif(TARGET_ARCH_NAME STREQUAL "x86") set(CMAKE_SYSTEM_PROCESSOR i686) - set(TOOLCHAIN "i686-linux-gnu") + if(EXISTS ${CROSS_ROOTFS}/usr/lib/gcc/i586-alpine-linux-musl) + set(TOOLCHAIN "i586-alpine-linux-musl") + else() + set(TOOLCHAIN "i686-linux-gnu") + endif() if(TIZEN) set(TIZEN_TOOLCHAIN "i586-tizen-linux-gnu/9.2.0") endif() @@ -196,10 +216,8 @@ elseif(HAIKU) return() endif() - set(SEARCH_PATH "${CROSS_ROOTFS}/generated/cross-tools-x86_64/bin") - find_program(EXEC_LOCATION_${exec} - PATHS ${SEARCH_PATH} + PATHS "${CROSS_ROOTFS}/cross-tools-x86_64/bin" NAMES "${TOOLSET_PREFIX}${exec}${CLR_CMAKE_COMPILER_FILE_NAME_VERSION}" "${TOOLSET_PREFIX}${exec}") @@ -264,8 +282,11 @@ elseif(TARGET_ARCH_NAME MATCHES "^(arm64|x64)$") add_toolchain_linker_flag("-Wl,--rpath-link=${CROSS_ROOTFS}/usr/lib64/gcc/${TIZEN_TOOLCHAIN}") endif() elseif(TARGET_ARCH_NAME STREQUAL "x86") + if(EXISTS ${CROSS_ROOTFS}/usr/lib/gcc/i586-alpine-linux-musl) + add_toolchain_linker_flag("--target=${TOOLCHAIN}") + add_toolchain_linker_flag("-Wl,--rpath-link=${CROSS_ROOTFS}/usr/lib/gcc/${TOOLCHAIN}") + endif() add_toolchain_linker_flag(-m32) - if(TIZEN) add_toolchain_linker_flag("-B${CROSS_ROOTFS}/usr/lib/gcc/${TIZEN_TOOLCHAIN}") add_toolchain_linker_flag("-L${CROSS_ROOTFS}/lib") @@ -275,11 +296,14 @@ elseif(TARGET_ARCH_NAME STREQUAL "x86") elseif(ILLUMOS) add_toolchain_linker_flag("-L${CROSS_ROOTFS}/lib/amd64") add_toolchain_linker_flag("-L${CROSS_ROOTFS}/usr/amd64/lib") +elseif(HAIKU) + add_toolchain_linker_flag("-lnetwork") + add_toolchain_linker_flag("-lroot") endif() # Specify compile options -if((TARGET_ARCH_NAME MATCHES "^(arm|arm64|armel|armv6|ppc64le|riscv64|s390x)$" AND NOT ANDROID AND NOT FREEBSD) OR ILLUMOS OR HAIKU) +if((TARGET_ARCH_NAME MATCHES "^(arm|arm64|armel|armv6|ppc64le|riscv64|s390x|x64|x86)$" AND NOT ANDROID AND NOT FREEBSD) OR ILLUMOS OR HAIKU) set(CMAKE_C_COMPILER_TARGET ${TOOLCHAIN}) set(CMAKE_CXX_COMPILER_TARGET ${TOOLCHAIN}) set(CMAKE_ASM_COMPILER_TARGET ${TOOLCHAIN}) @@ -298,10 +322,16 @@ if(TARGET_ARCH_NAME MATCHES "^(arm|armel)$") add_definitions (-DCLR_ARM_FPU_CAPABILITY=${CLR_ARM_FPU_CAPABILITY}) + # persist variables across multiple try_compile passes + list(APPEND CMAKE_TRY_COMPILE_PLATFORM_VARIABLES CLR_ARM_FPU_TYPE CLR_ARM_FPU_CAPABILITY) + if(TARGET_ARCH_NAME STREQUAL "armel") add_compile_options(-mfloat-abi=softfp) endif() elseif(TARGET_ARCH_NAME STREQUAL "x86") + if(EXISTS ${CROSS_ROOTFS}/usr/lib/gcc/i586-alpine-linux-musl) + add_compile_options(--target=${TOOLCHAIN}) + endif() add_compile_options(-m32) add_compile_options(-Wno-error=unused-command-line-argument) endif() diff --git a/eng/common/native/init-compiler.sh b/eng/common/native/init-compiler.sh index 7aee4213e1..517401b688 100644 --- a/eng/common/native/init-compiler.sh +++ b/eng/common/native/init-compiler.sh @@ -64,7 +64,7 @@ if [ -z "$CLR_CC" ]; then if [ -z "$majorVersion" ]; then # note: gcc (all versions) and clang versions higher than 6 do not have minor version in file name, if it is zero. if [ "$compiler" = "clang" ]; then versions="16 15 14 13 12 11 10 9 8 7 6.0 5.0 4.0 3.9 3.8 3.7 3.6 3.5" - elif [ "$compiler" = "gcc" ]; then versions="12 11 10 9 8 7 6 5 4.9"; fi + elif [ "$compiler" = "gcc" ]; then versions="13 12 11 10 9 8 7 6 5 4.9"; fi for version in $versions; do _major="${version%%.*}" diff --git a/eng/common/templates/job/job.yml b/eng/common/templates/job/job.yml index b214a31db2..44ad26abf5 100644 --- a/eng/common/templates/job/job.yml +++ b/eng/common/templates/job/job.yml @@ -25,7 +25,7 @@ parameters: enablePublishTestResults: false enablePublishUsingPipelines: false enableBuildRetry: false - disableComponentGovernance: false + disableComponentGovernance: '' componentGovernanceIgnoreDirectories: '' mergeTestResults: false testRunTitle: '' @@ -155,11 +155,16 @@ jobs: uploadRichNavArtifacts: ${{ coalesce(parameters.richCodeNavigationUploadArtifacts, false) }} continueOnError: true - - ${{ if and(eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest'), ne(parameters.disableComponentGovernance, 'true')) }}: - - task: ComponentGovernanceComponentDetection@0 - continueOnError: true - inputs: - ignoreDirectories: ${{ parameters.componentGovernanceIgnoreDirectories }} + - template: /eng/common/templates/steps/component-governance.yml + parameters: + ${{ if eq(parameters.disableComponentGovernance, '') }}: + ${{ if and(ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest'), eq(parameters.runAsPublic, 'false'), or(startsWith(variables['Build.SourceBranch'], 'refs/heads/release/'), startsWith(variables['Build.SourceBranch'], 'refs/heads/dotnet/'), startsWith(variables['Build.SourceBranch'], 'refs/heads/microsoft/'), eq(variables['Build.SourceBranch'], 'refs/heads/main'))) }}: + disableComponentGovernance: false + ${{ else }}: + disableComponentGovernance: true + ${{ else }}: + disableComponentGovernance: ${{ parameters.disableComponentGovernance }} + componentGovernanceIgnoreDirectories: ${{ parameters.componentGovernanceIgnoreDirectories }} - ${{ if eq(parameters.enableMicrobuild, 'true') }}: - ${{ if and(eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}: diff --git a/eng/common/templates/steps/component-governance.yml b/eng/common/templates/steps/component-governance.yml new file mode 100644 index 0000000000..0ecec47b0c --- /dev/null +++ b/eng/common/templates/steps/component-governance.yml @@ -0,0 +1,13 @@ +parameters: + disableComponentGovernance: false + componentGovernanceIgnoreDirectories: '' + +steps: +- ${{ if eq(parameters.disableComponentGovernance, 'true') }}: + - script: "echo ##vso[task.setvariable variable=skipComponentGovernanceDetection]true" + displayName: Set skipComponentGovernanceDetection variable +- ${{ if ne(parameters.disableComponentGovernance, 'true') }}: + - task: ComponentGovernanceComponentDetection@0 + continueOnError: true + inputs: + ignoreDirectories: ${{ parameters.componentGovernanceIgnoreDirectories }} \ No newline at end of file diff --git a/eng/common/tools.ps1 b/eng/common/tools.ps1 index 8ad03be3ec..38cf94ff88 100644 --- a/eng/common/tools.ps1 +++ b/eng/common/tools.ps1 @@ -287,6 +287,25 @@ function InstallDotNet([string] $dotnetRoot, [string] $runtimeSourceFeedKey = '', [switch] $noPath) { + $dotnetVersionLabel = "'sdk v$version'" + + if ($runtime -ne '' -and $runtime -ne 'sdk') { + $runtimePath = $dotnetRoot + $runtimePath = $runtimePath + "\shared" + if ($runtime -eq "dotnet") { $runtimePath = $runtimePath + "\Microsoft.NETCore.App" } + if ($runtime -eq "aspnetcore") { $runtimePath = $runtimePath + "\Microsoft.AspNetCore.App" } + if ($runtime -eq "windowsdesktop") { $runtimePath = $runtimePath + "\Microsoft.WindowsDesktop.App" } + $runtimePath = $runtimePath + "\" + $version + + $dotnetVersionLabel = "runtime toolset '$runtime/$architecture v$version'" + + if (Test-Path $runtimePath) { + Write-Host " Runtime toolset '$runtime/$architecture v$version' already installed." + $installSuccess = $true + Exit + } + } + $installScript = GetDotNetInstallScript $dotnetRoot $installParameters = @{ Version = $version @@ -323,18 +342,18 @@ function InstallDotNet([string] $dotnetRoot, } else { $location = "public location"; } - Write-Host "Attempting to install dotnet from $location." + Write-Host " Attempting to install $dotnetVersionLabel from $location." try { & $installScript @variation $installSuccess = $true break } catch { - Write-Host "Failed to install dotnet from $location." + Write-Host " Failed to install $dotnetVersionLabel from $location." } } if (-not $installSuccess) { - Write-PipelineTelemetryError -Category 'InitializeToolset' -Message "Failed to install dotnet from any of the specified locations." + Write-PipelineTelemetryError -Category 'InitializeToolset' -Message "Failed to install $dotnetVersionLabel from any of the specified locations." ExitWithExitCode 1 } } @@ -399,7 +418,8 @@ function InitializeVisualStudioMSBuild([bool]$install, [object]$vsRequirements = # Locate Visual Studio installation or download x-copy msbuild. $vsInfo = LocateVisualStudio $vsRequirements if ($vsInfo -ne $null) { - $vsInstallDir = $vsInfo.installationPath + # Ensure vsInstallDir has a trailing slash + $vsInstallDir = Join-Path $vsInfo.installationPath "\" $vsMajorVersion = $vsInfo.installationVersion.Split('.')[0] InitializeVisualStudioEnvironmentVariables $vsInstallDir $vsMajorVersion diff --git a/eng/common/tools.sh b/eng/common/tools.sh index cf9fb1ea2d..e8d4789433 100644 --- a/eng/common/tools.sh +++ b/eng/common/tools.sh @@ -184,6 +184,35 @@ function InstallDotNetSdk { function InstallDotNet { local root=$1 local version=$2 + local runtime=$4 + + local dotnetVersionLabel="'$runtime v$version'" + if [[ -n "${4:-}" ]] && [ "$4" != 'sdk' ]; then + runtimePath="$root" + runtimePath="$runtimePath/shared" + case "$runtime" in + dotnet) + runtimePath="$runtimePath/Microsoft.NETCore.App" + ;; + aspnetcore) + runtimePath="$runtimePath/Microsoft.AspNetCore.App" + ;; + windowsdesktop) + runtimePath="$runtimePath/Microsoft.WindowsDesktop.App" + ;; + *) + ;; + esac + runtimePath="$runtimePath/$version" + + dotnetVersionLabel="runtime toolset '$runtime/$architecture v$version'" + + if [ -d "$runtimePath" ]; then + echo " Runtime toolset '$runtime/$architecture v$version' already installed." + local installSuccess=1 + return + fi + fi GetDotNetInstallScript "$root" local install_script=$_GetDotNetInstallScript @@ -228,17 +257,17 @@ function InstallDotNet { for variationName in "${variations[@]}"; do local name="$variationName[@]" local variation=("${!name}") - echo "Attempting to install dotnet from $variationName." + echo " Attempting to install $dotnetVersionLabel from $variationName." bash "$install_script" "${variation[@]}" && installSuccess=1 if [[ "$installSuccess" -eq 1 ]]; then break fi - echo "Failed to install dotnet from $variationName." + echo " Failed to install $dotnetVersionLabel from $variationName." done if [[ "$installSuccess" -eq 0 ]]; then - Write-PipelineTelemetryError -category 'InitializeToolset' "Failed to install dotnet SDK from any of the specified locations." + Write-PipelineTelemetryError -category 'InitializeToolset' "Failed to install $dotnetVersionLabel from any of the specified locations." ExitWithExitCode 1 fi } diff --git a/eng/docker-build.sh b/eng/docker-build.sh deleted file mode 100755 index 99cfc0d047..0000000000 --- a/eng/docker-build.sh +++ /dev/null @@ -1,79 +0,0 @@ -#!/usr/bin/env bash -# Copyright (c) .NET Foundation and contributors. All rights reserved. -# Licensed under the MIT license. See LICENSE file in the project root for full license information. - -source_directory= -docker_image= -docker_container_name= - -while [ $# -ne 0 ]; do - name=$1 - case $name in - -s|--source-directory) - shift - source_directory=$1 - ;; - -i|--docker-image) - shift - docker_image=$1 - ;; - -c|--container-name) - shift - docker_container_name=$1 - ;; - *) - args="$args $1" - ;; - esac - shift -done - -echo "Initialize Docker Container" -if command -v docker > /dev/null; then - docker_bin=$(command -v docker) -else - echo "Unable to find docker" - exit 1 -fi - -$docker_bin --version - -# Get user id -user_name=$(whoami) -echo "user name: $user_name" -user_id=$(id -u $user_name) -echo "user id: $user_id" - -# Download image -$docker_bin pull $docker_image - -# Create local network to avoid port conflicts when multiple agents run on same machine -$docker_bin network create vsts_network_$docker_container_name - -# Create and start container -docker_id="$($docker_bin create -it --rm --security-opt seccomp=unconfined --ulimit core=-1 \ - --name vsts_container_$docker_container_name \ - --network=vsts_network_$docker_container_name \ - --volume $source_directory:$source_directory \ - --workdir=$source_directory $docker_image bash --verbose)" -$docker_bin start $docker_id - -# Create an user with the same uid in the container -container_user_name=vsts_$(echo $user_name | awk '{print tolower($0)}') -echo "container user name: $container_user_name" - -# Add sudo user with same uid that can run any sudo command without password -$docker_bin exec $docker_id useradd -K MAIL_DIR=/dev/null -m -u $user_id $container_user_name -$docker_bin exec $docker_id groupadd sudouser -$docker_bin exec $docker_id usermod -a -G sudouser $container_user_name -$docker_bin exec $docker_id su -c "echo '%sudouser ALL=(ALL:ALL) NOPASSWD:ALL' >> /etc/sudoers" - -echo "Execute $args" -$docker_bin exec --workdir=$source_directory --user $container_user_name $docker_id $args -lasterrorcode=$? - -echo "Cleanup Docker Container/Network" -$docker_bin container stop $docker_id -$docker_bin network rm vsts_network_$docker_container_name - -exit $lasterrorcode diff --git a/eng/build.yml b/eng/pipelines/build.yml similarity index 68% rename from eng/build.yml rename to eng/pipelines/build.yml index 6115437680..03c9700f32 100644 --- a/eng/build.yml +++ b/eng/pipelines/build.yml @@ -3,24 +3,26 @@ parameters: name: '' # Agent OS (Windows_NT, Linux, MacOS, FreeBSD) osGroup: Windows_NT + # Optional: OS suffix like -musl + osSuffix: '' # Additional variables variables: {} # Build strategy - matrix strategy: '' # Optional: Job timeout timeoutInMinutes: 180 - # Optional: Docker image to use - dockerImage: '' - # Optional: ROOTFS_DIR to use - crossrootfsDir: '' - crossbuild: false + # Optional: native build container resource name + nativeBuildContainer: '' + # Optional: container resource name + container: '' + # Optional: build only job if true + buildOnly: false # Optional: test only job if true testOnly: false - buildAndSkipTest: false - # Depends on + # Optional: architecture cross build if true + crossBuild: false + # Depends on dependsOn: '' - artifactsTargetPath: '' - requiresCapPtraceContainer: false isCodeQLRun: false jobs: @@ -62,8 +64,8 @@ jobs: name: NetCore-Public demands: ImageOverride -equals windows.vs2022.amd64.open - ${{ if and(ne(parameters.dockerImage, ''), ne(parameters.requiresCapPtraceContainer, 'true')) }}: - container: ${{ parameters.dockerImage }} + ${{ if ne(parameters.container, '') }}: + container: ${{ parameters.container }} ${{ if ne(parameters.strategy, '') }}: strategy: ${{ parameters.strategy }} @@ -76,27 +78,28 @@ jobs: variables: - ${{ insert }}: ${{ parameters.variables }} - - _DockerImageName: ${{ parameters.dockerImage }} - _PhaseName : ${{ parameters.name }} - _HelixType: build/product - _HelixBuildConfig: $(_BuildConfig) - _Pipeline_StreamDumpDir: $(Build.SourcesDirectory)/artifacts/tmp/$(_BuildConfig)/streams + - _BuildDisplayName: 'Build / Test' + - _ExtraBuildParams: '' + - _TestArgs: '-test' + - _Cross: '' + - ${{ if eq(parameters.osGroup, 'Windows_NT') }}: - - _buildScript: $(Build.SourcesDirectory)\eng\cibuild.cmd + - _buildScript: $(Build.SourcesDirectory)\build.cmd - ${{ if ne(parameters.osGroup, 'Windows_NT') }}: - - _buildScript: $(Build.SourcesDirectory)/eng/cibuild.sh - - - _TestArgs: '-test' - - _dockerEnv: '' + - _buildScript: $(Build.SourcesDirectory)/build.sh - ${{ if eq(parameters.testOnly, 'true') }}: - _TestArgs: '-test -skipnative' - - ${{ if eq(parameters.requiresCapPtraceContainer, 'true') }}: - - _dockerEnv: $(Build.SourcesDirectory)/eng/docker-build.sh - --docker-image $(_DockerImageName) - --source-directory $(Build.SourcesDirectory) - --container-name diagnostics-$(Build.BuildId) + - _BuildDisplayName: Test + + - ${{ if or(eq(parameters.buildOnly, 'true'), eq(parameters.isCodeQLRun, 'true')) }}: + - _TestArgs: '' + - ${{ if eq(parameters.isCodeQLRun, 'true') }}: - name: Codeql.Enabled value: True @@ -109,11 +112,8 @@ jobs: - name: Codeql.Language value: csharp,cpp - - ${{ if or(eq(parameters.buildAndSkipTest, 'true'), eq(parameters.isCodeQLRun, 'true')) }}: - - _TestArgs: '' - - - _InternalInstallArgs: '' # For testing msrc's and service releases. The RuntimeSourceVersion is either "default" or the service release version to test + - _InternalInstallArgs: '' - ${{ if and(ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest'), eq(parameters.isCodeQLRun, 'false')) }}: - _InternalInstallArgs: -dotnetruntimeversion '$(DotnetRuntimeVersion)' @@ -128,62 +128,88 @@ jobs: - _HelixSource: pr/dotnet/arcade/$(Build.SourceBranch) # This is only required for cross builds. - - ${{ if and(eq(parameters.crossbuild, false), eq(parameters.crossrootfsDir, '')) }}: - - _Cross: '' - - ${{ if or(eq(parameters.crossbuild, true), ne(parameters.crossrootfsDir, '')) }}: + - ${{ if eq(parameters.crossBuild, true) }}: - _Cross: -cross + # If there is a native build container, build managed in the host vm/container and native in the nativeBuildContainer + - ${{ if ne(parameters.nativeBuildContainer, '') }}: + - _ExtraBuildParams: -skipnative + - _BuildDisplayName: 'Build Managed' + + # Only add the cross build option if a combined build/test managed/native build (i.e. MacOS arm64) + - ${{ if eq(parameters.nativeBuildContainer, '') }}: + - _ExtraBuildParams: $(_Cross) + steps: - ${{ if eq(parameters.osGroup, 'Linux') }}: - ${{ if eq(parameters.testOnly, 'true') }}: - task: DownloadBuildArtifacts@0 - displayName: 'Download release builds' + displayName: 'Download Build Artifacts' inputs: downloadPath: '$(Build.ArtifactStagingDirectory)/__download__' - downloadType: specific + downloadType: specific itemPattern: | - Build_$(_BuildConfig)/bin/Linux.$(_BuildArch).$(_BuildConfig)/** + Build_$(_BuildConfig)/bin/Linux${{ parameters.osSuffix }}.$(_BuildArch).$(_BuildConfig)/** checkDownloadedFiles: true - task: CopyFiles@2 displayName: 'Binplace Product' inputs: - sourceFolder: $(Build.ArtifactStagingDirectory)/__download__/Build_$(_BuildConfig)/bin/Linux.$(_BuildArch).$(_BuildConfig) + sourceFolder: $(Build.ArtifactStagingDirectory)/__download__/Build_$(_BuildConfig)/bin/Linux${{ parameters.osSuffix }}.$(_BuildArch).$(_BuildConfig) targetFolder: '$(Build.SourcesDirectory)/artifacts/bin/Linux.$(_BuildArch).$(_BuildConfig)' - ${{ if eq(parameters.isCodeQLRun, 'true') }}: - task: CodeQL3000Init@0 displayName: CodeQL Initialize - - script: $(_dockerEnv) $(_buildScript) - -configuration $(_BuildConfig) + - script: $(_buildScript) + -ci + -configuration $(_BuildConfig) -architecture $(_BuildArch) - $(_Cross) + $(_ExtraBuildParams) $(_TestArgs) /p:OfficialBuildId=$(BUILD.BUILDNUMBER) $(_InternalInstallArgs) - displayName: Build / Test + displayName: $(_BuildDisplayName) condition: succeeded() - env: - ROOTFS_DIR: ${{ parameters.crossrootfsDir }} + + - ${{ if ne(parameters.nativeBuildContainer, '') }}: + - script: $(_buildScript) + -ci + -configuration $(_BuildConfig) + -architecture $(_BuildArch) + -skipmanaged + $(_Cross) + /p:OfficialBuildId=$(BUILD.BUILDNUMBER) + $(_InternalInstallArgs) + displayName: Build Native + target: ${{ parameters.nativeBuildContainer }} - ${{ if eq(parameters.isCodeQLRun, 'true') }}: - task: CodeQL3000Finalize@0 displayName: CodeQL Finalize - - ${{ if ne(variables['System.TeamProject'], 'public') }}: - - task: CopyFiles@2 - displayName: Gather binaries for publish to artifacts - inputs: - SourceFolder: '$(Build.SourcesDirectory)/artifacts/$(_PublishArtifacts)' - Contents: '**' - TargetFolder: $(Build.ArtifactStagingDirectory)/artifacts/${{ coalesce(parameters.artifactsTargetPath, '$(_PublishArtifacts)') }} - condition: ne(variables['_PublishArtifacts'], '') - - task: PublishBuildArtifacts@1 - displayName: Publish Build Artifacts - inputs: - pathtoPublish: '$(Build.ArtifactStagingDirectory)/artifacts' - artifactName: Build_$(_BuildConfig) - condition: ne(variables['_PublishArtifacts'], '') + - task: CopyFiles@2 + displayName: Gather binaries for publish to special artifacts path + inputs: + SourceFolder: '$(Build.SourcesDirectory)/artifacts/$(_PublishArtifacts)' + Contents: '**' + TargetFolder: $(Build.ArtifactStagingDirectory)/artifacts/$(_ArtifactsTargetPath) + condition: and(ne(variables['_PublishArtifacts'], ''), ne(variables['_ArtifactsTargetPath'], '')) + + - task: CopyFiles@2 + displayName: Gather binaries for publish to artifacts + inputs: + SourceFolder: '$(Build.SourcesDirectory)/artifacts/$(_PublishArtifacts)' + Contents: '**' + TargetFolder: $(Build.ArtifactStagingDirectory)/artifacts/$(_PublishArtifacts) + condition: and(ne(variables['_PublishArtifacts'], ''), eq(variables['_ArtifactsTargetPath'], '')) + + - task: PublishBuildArtifacts@1 + displayName: Publish Build Artifacts + inputs: + pathtoPublish: '$(Build.ArtifactStagingDirectory)/artifacts' + artifactName: Build_$(_BuildConfig) + condition: ne(variables['_PublishArtifacts'], '') - task: PublishBuildArtifacts@1 displayName: Publish Artifacts on failure @@ -230,12 +256,12 @@ jobs: continueOnError: true condition: always() - - ${{ if and(eq(parameters.buildAndSkipTest, 'false'), eq(parameters.isCodeQLRun, 'false')) }}: + - ${{ if and(eq(parameters.buildOnly, 'false'), eq(parameters.isCodeQLRun, 'false')) }}: # Publish test results to Azure Pipelines - task: PublishTestResults@2 inputs: testResultsFormat: xUnit - testResultsFiles: '**/*UnitTests*.xml' + testResultsFiles: '**/*UnitTests*.xml' searchFolder: '$(Build.SourcesDirectory)/artifacts/TestResults' failTaskOnFailedTests: true testRunTitle: 'Tests $(_PhaseName) $(_BuildArch) $(_BuildConfig)' diff --git a/eng/pipelines/pipeline-resources.yml b/eng/pipelines/pipeline-resources.yml new file mode 100644 index 0000000000..524a3793ce --- /dev/null +++ b/eng/pipelines/pipeline-resources.yml @@ -0,0 +1,61 @@ +parameters: + - name: stages + type: stageList + +resources: + containers: + - container: linux_x64 + image: mcr.microsoft.com/dotnet-buildtools/prereqs:centos-7 + + - container: linux_arm + image: mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-18.04-cross + env: + ROOTFS_DIR: /crossrootfs/arm + + - container: linux_arm64 + image: mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-18.04-cross-arm64 + env: + ROOTFS_DIR: /crossrootfs/arm64 + + - container: linux_musl_x64 + image: mcr.microsoft.com/dotnet-buildtools/prereqs:alpine-3.13-WithNode + + - container: linux_musl_arm + image: mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-18.04-cross-arm-alpine + env: + ROOTFS_DIR: /crossrootfs/arm + + - container: linux_musl_arm64 + image: mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-18.04-cross-arm64-alpine + env: + ROOTFS_DIR: /crossrootfs/arm64 + + - container: test_linux_x64 + image: mcr.microsoft.com/dotnet-buildtools/prereqs:centos-7 + + - container: test_linux_musl_x64 + image: mcr.microsoft.com/dotnet-buildtools/prereqs:alpine-3.13-WithNode + options: --cap-add=SYS_PTRACE + + - container: test_debian_11_amd64 + image: mcr.microsoft.com/dotnet-buildtools/prereqs:debian-11-amd64 + options: '--env PYTHONPATH=/usr/bin/python3.9' + + - container: test_fedora_36 + image: mcr.microsoft.com/dotnet-buildtools/prereqs:fedora-36 + options: --cap-add=SYS_PTRACE + + - container: test_opensuse_15_2 + image: mcr.microsoft.com/dotnet-buildtools/prereqs:opensuse-15.2-helix-amd64 + + - container: test_ubuntu_18_04 + image: mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-18.04 + + - container: test_ubuntu_20_04 + image: mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-20.04 + options: '--env PYTHONPATH=/usr/bin/python3.8' + + - container: test_ubuntu_22_04 + image: mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-22.04 + +stages: ${{ parameters.stages }} diff --git a/eng/prepare-release.yml b/eng/pipelines/prepare-release.yml similarity index 100% rename from eng/prepare-release.yml rename to eng/pipelines/prepare-release.yml diff --git a/global.json b/global.json index 879572b3ab..b6a0f5bea8 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "tools": { - "dotnet": "8.0.100-preview.1.23115.2", + "dotnet": "8.0.100-preview.3.23178.7", "runtimes": { "dotnet": [ "$(MicrosoftNETCoreApp60Version)", @@ -16,6 +16,6 @@ }, "msbuild-sdks": { "Microsoft.Build.NoTargets": "3.5.0", - "Microsoft.DotNet.Arcade.Sdk": "8.0.0-beta.23168.1" + "Microsoft.DotNet.Arcade.Sdk": "8.0.0-beta.23262.5" } } diff --git a/src/Microsoft.Diagnostics.ExtensionCommands/ClrMDHelper.cs b/src/Microsoft.Diagnostics.ExtensionCommands/ClrMDHelper.cs index 074026ac39..76cda04435 100644 --- a/src/Microsoft.Diagnostics.ExtensionCommands/ClrMDHelper.cs +++ b/src/Microsoft.Diagnostics.ExtensionCommands/ClrMDHelper.cs @@ -851,37 +851,51 @@ private static bool TryGetSegmentMemoryRange(ClrSegment segment, GCGeneration ge switch (generation) { case GCGeneration.Generation0: - start = segment.Generation0.Start; - end = segment.Generation0.End; - return start != end; + if (segment.Kind == GCSegmentKind.Generation0 || segment.Kind == GCSegmentKind.Ephemeral) + { + start = segment.Generation0.Start; + end = segment.Generation0.End; + } + break; case GCGeneration.Generation1: - start = segment.Generation1.Start; - end = segment.Generation1.End; - return start != end; + if (segment.Kind == GCSegmentKind.Generation1 || segment.Kind == GCSegmentKind.Ephemeral) + { + start = segment.Generation1.Start; + end = segment.Generation1.End; + } + break; case GCGeneration.Generation2: - if (segment.Kind != GCSegmentKind.Large && segment.Kind != GCSegmentKind.Large && segment.Kind != GCSegmentKind.Frozen) + if (segment.Kind == GCSegmentKind.Generation2 || segment.Kind == GCSegmentKind.Ephemeral) { start = segment.Generation2.Start; end = segment.Generation2.End; } - return start != end; + break; case GCGeneration.LargeObjectHeap: if (segment.Kind == GCSegmentKind.Large) { start = segment.Start; end = segment.End; } - return start != end; + break; case GCGeneration.PinnedObjectHeap: - if (segment.Kind == GCSegmentKind.Pinned || segment.Kind == GCSegmentKind.Frozen) + if (segment.Kind == GCSegmentKind.Pinned) { start = segment.Start; end = segment.End; } - return start != end; + break; + case GCGeneration.FrozenObjectHeap: + if (segment.Kind == GCSegmentKind.Frozen) + { + start = segment.Start; + end = segment.End; + } + break; default: return false; } + return start != end; } public IEnumerable EnumerateConcurrentQueue(ulong address) diff --git a/src/Microsoft.Diagnostics.ExtensionCommands/DumpGenCommand.cs b/src/Microsoft.Diagnostics.ExtensionCommands/DumpGenCommand.cs index ef1908ef3b..db020e7926 100644 --- a/src/Microsoft.Diagnostics.ExtensionCommands/DumpGenCommand.cs +++ b/src/Microsoft.Diagnostics.ExtensionCommands/DumpGenCommand.cs @@ -96,22 +96,21 @@ private GCGeneration ParseGenerationArgument(string generation) return GCGeneration.NotSet; } string lowerString = generation.ToLowerInvariant(); - switch (lowerString) + GCGeneration result = lowerString switch { - case "gen0": - return GCGeneration.Generation0; - case "gen1": - return GCGeneration.Generation1; - case "gen2": - return GCGeneration.Generation2; - case "loh": - return GCGeneration.LargeObjectHeap; - case "poh": - return GCGeneration.PinnedObjectHeap; - default: - WriteLine($"{generation} is not a supported generation (gen0, gen1, gen2, loh, poh)"); - return GCGeneration.NotSet; + "gen0" => GCGeneration.Generation0, + "gen1" => GCGeneration.Generation1, + "gen2" => GCGeneration.Generation2, + "loh" => GCGeneration.LargeObjectHeap, + "poh" => GCGeneration.PinnedObjectHeap, + "foh" => GCGeneration.FrozenObjectHeap, + _ => GCGeneration.NotSet, + }; + if (result == GCGeneration.NotSet) + { + WriteLine($"{generation} is not a supported generation (gen0, gen1, gen2, loh, poh, foh)"); } + return result; } @@ -133,6 +132,7 @@ Generation number can take the following values (case insensitive): - gen2 - loh - poh +- foh > dumpgen gen0 Statistics: diff --git a/src/Microsoft.Diagnostics.ExtensionCommands/DumpStackObjectsCommand.cs b/src/Microsoft.Diagnostics.ExtensionCommands/DumpStackObjectsCommand.cs index 1fb0562d63..131450fe8b 100644 --- a/src/Microsoft.Diagnostics.ExtensionCommands/DumpStackObjectsCommand.cs +++ b/src/Microsoft.Diagnostics.ExtensionCommands/DumpStackObjectsCommand.cs @@ -228,7 +228,7 @@ private ClrSegment GetSegment(ulong potentialObject, ref int segmentIndex) // and that all objects passed to it are within the given // range of segment bounds. Debug.Assert(segmentIndex >= 0 && segmentIndex <= segments.Length); - Debug.Assert(segments[0].ObjectRange.Start < potentialObject); + Debug.Assert(segments[0].ObjectRange.Start <= potentialObject); Debug.Assert(potentialObject < segments[segments.Length - 1].ObjectRange.End); for (; segmentIndex < segments.Length; segmentIndex++) diff --git a/src/Microsoft.Diagnostics.ExtensionCommands/GCGeneration.cs b/src/Microsoft.Diagnostics.ExtensionCommands/GCGeneration.cs index 5ebe713150..028e7c413c 100644 --- a/src/Microsoft.Diagnostics.ExtensionCommands/GCGeneration.cs +++ b/src/Microsoft.Diagnostics.ExtensionCommands/GCGeneration.cs @@ -10,6 +10,7 @@ public enum GCGeneration Generation1 = 2, Generation2 = 3, LargeObjectHeap = 4, - PinnedObjectHeap = 5 + PinnedObjectHeap = 5, + FrozenObjectHeap = 6 } } diff --git a/src/SOS/SOS.UnitTests/ConfigFiles/Unix/Debugger.Tests.Config.txt b/src/SOS/SOS.UnitTests/ConfigFiles/Unix/Debugger.Tests.Config.txt index bd1568c039..dbe012fada 100644 --- a/src/SOS/SOS.UnitTests/ConfigFiles/Unix/Debugger.Tests.Config.txt +++ b/src/SOS/SOS.UnitTests/ConfigFiles/Unix/Debugger.Tests.Config.txt @@ -21,6 +21,9 @@ $(RootBinDir)/TestResults/$(TargetConfiguration)/sos.unittests_$(Timestamp) $(RootBinDir)/tmp/$(TargetConfiguration)\dumps + true + true + true false @@ -140,6 +143,8 @@ - + https://github.com/dotnet/runtime - 4c0f2e7bd4cb86917e362052e0642df600984b6c + 0096ba52e8c86e4d712013f6330a9b8a6496a1e0 - + https://github.com/dotnet/runtime - 4c0f2e7bd4cb86917e362052e0642df600984b6c + 0096ba52e8c86e4d712013f6330a9b8a6496a1e0 https://github.com/dotnet/source-build-reference-packages diff --git a/eng/Versions.props b/eng/Versions.props index 36908bd64c..e7774379aa 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -18,8 +18,8 @@ 1.0.426501 - 8.0.0-preview.5.23265.1 - 8.0.0-preview.5.23265.1 + 8.0.0-preview.5.23268.1 + 8.0.0-preview.5.23268.1 8.0.0-preview.5.23265.1 8.0.0-preview.5.23265.1 From 45e7eb3057387bc0a538dc2d76ed506ef944690f Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Fri, 19 May 2023 13:46:11 +0000 Subject: [PATCH 057/111] Update dependencies from https://github.com/microsoft/clrmd build 20230518.1 (#3887) [main] Update dependencies from microsoft/clrmd --- eng/Version.Details.xml | 8 ++++---- eng/Versions.props | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 34deb024e5..adad8e31e6 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -4,13 +4,13 @@ https://github.com/dotnet/symstore 72212ba2f73877c1bf08a1c5bfbae5501e459e8a - + https://github.com/microsoft/clrmd - 881933c4b718ae832d2424c4e1c6aabfa5c7c74a + 4f66261481b629184d0d378b156ef8fab84456da - + https://github.com/microsoft/clrmd - 881933c4b718ae832d2424c4e1c6aabfa5c7c74a + 4f66261481b629184d0d378b156ef8fab84456da diff --git a/eng/Versions.props b/eng/Versions.props index e7774379aa..c5e4bd252f 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -45,7 +45,7 @@ 5.0.0 6.0.0 - 3.0.0-beta.23267.2 + 3.0.0-beta.23268.1 16.9.0-beta1.21055.5 3.0.7 6.0.0 From 4c333edb9623940813b20e6fe989379d3d6ba1a4 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Fri, 19 May 2023 13:49:51 +0000 Subject: [PATCH 058/111] Update dependencies from https://github.com/dotnet/aspnetcore build 20230518.15 (#3886) [main] Update dependencies from dotnet/aspnetcore --- eng/Version.Details.xml | 8 ++++---- eng/Versions.props | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index adad8e31e6..f4fa94cfa9 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -31,13 +31,13 @@ https://github.com/dotnet/installer 8488614afec7497b9e74b47c976af2a97506bb96 - + https://github.com/dotnet/aspnetcore - dba677f5fbf85666aac3009b16e5c05d93ec63ca + 631f523a3828530880270ff9accc925f36d67705 - + https://github.com/dotnet/aspnetcore - dba677f5fbf85666aac3009b16e5c05d93ec63ca + 631f523a3828530880270ff9accc925f36d67705 https://github.com/dotnet/runtime diff --git a/eng/Versions.props b/eng/Versions.props index c5e4bd252f..2867dbe9a4 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -21,8 +21,8 @@ 8.0.0-preview.5.23268.1 8.0.0-preview.5.23268.1 - 8.0.0-preview.5.23265.1 - 8.0.0-preview.5.23265.1 + 8.0.0-preview.5.23268.15 + 8.0.0-preview.5.23268.15 8.0.100-preview.5.23264.2 From 69565914c5ed06b148487aa93aa5a8b662669432 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Fri, 19 May 2023 17:51:09 +0000 Subject: [PATCH 059/111] Update dependencies from https://github.com/dotnet/runtime build 20230518.14 (#3888) [main] Update dependencies from dotnet/runtime --- eng/Version.Details.xml | 8 ++++---- eng/Versions.props | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index f4fa94cfa9..f517154831 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -39,13 +39,13 @@ https://github.com/dotnet/aspnetcore 631f523a3828530880270ff9accc925f36d67705 - + https://github.com/dotnet/runtime - 0096ba52e8c86e4d712013f6330a9b8a6496a1e0 + 2f49fcff6df15a200ef01eea16b3ce7930f75c5c - + https://github.com/dotnet/runtime - 0096ba52e8c86e4d712013f6330a9b8a6496a1e0 + 2f49fcff6df15a200ef01eea16b3ce7930f75c5c https://github.com/dotnet/source-build-reference-packages diff --git a/eng/Versions.props b/eng/Versions.props index 2867dbe9a4..22aa700566 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -18,8 +18,8 @@ 1.0.426501 - 8.0.0-preview.5.23268.1 - 8.0.0-preview.5.23268.1 + 8.0.0-preview.5.23268.14 + 8.0.0-preview.5.23268.14 8.0.0-preview.5.23268.15 8.0.0-preview.5.23268.15 From 1186a50bf7af14dba3bebdcba0a662cfeb14e323 Mon Sep 17 00:00:00 2001 From: Andy Ayers Date: Fri, 19 May 2023 18:25:27 -0700 Subject: [PATCH 060/111] Add PGO to DacpTieredVersionData (#3890) PGO introduces two new native code version types. The runtime already has this change, but SOS does not. --- src/SOS/Strike/util.cpp | 6 ++++++ src/shared/inc/dacprivate.h | 2 ++ 2 files changed, 8 insertions(+) diff --git a/src/SOS/Strike/util.cpp b/src/SOS/Strike/util.cpp index 8ef8d8344f..ec384ea237 100644 --- a/src/SOS/Strike/util.cpp +++ b/src/SOS/Strike/util.cpp @@ -2801,6 +2801,12 @@ void DumpTieredNativeCodeAddressInfo(struct DacpTieredVersionData * pTieredVersi case DacpTieredVersionData::OptimizationTier_ReadyToRun: descriptor = "ReadyToRun"; break; + case DacpTieredVersionData::OptimizationTier_QuickJittedInstrumented: + descriptor = "QuickJitted + Instrumented"; + break; + case DacpTieredVersionData::OptimizationTier_OptimizedTier1Instrumented: + descriptor = "OptimizedTier1 + Instrumented"; + break; } DMLOut(" CodeAddr: %s (%s)\n", DMLIP(pTieredVersionData[i].NativeCodeAddr), descriptor); ExtOut(" NativeCodeVersion: %p\n", SOS_PTR(pTieredVersionData[i].NativeCodeVersionNodePtr)); diff --git a/src/shared/inc/dacprivate.h b/src/shared/inc/dacprivate.h index abbb31405d..28295a0b17 100644 --- a/src/shared/inc/dacprivate.h +++ b/src/shared/inc/dacprivate.h @@ -610,6 +610,8 @@ struct MSLAYOUT DacpTieredVersionData OptimizationTier_OptimizedTier1, OptimizationTier_ReadyToRun, OptimizationTier_OptimizedTier1OSR, + OptimizationTier_QuickJittedInstrumented, + OptimizationTier_OptimizedTier1Instrumented }; CLRDATA_ADDRESS NativeCodeAddr; From bcdf9494982b9e0402d0f29caf71e3caffe9d5f7 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Sat, 20 May 2023 19:29:03 +0000 Subject: [PATCH 061/111] Update dependencies from https://github.com/dotnet/source-build-reference-packages build 20230519.1 (#3894) [main] Update dependencies from dotnet/source-build-reference-packages --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index f517154831..18809dc14e 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -47,9 +47,9 @@ https://github.com/dotnet/runtime 2f49fcff6df15a200ef01eea16b3ce7930f75c5c - + https://github.com/dotnet/source-build-reference-packages - fd98754b692a1a8da2aaadd28ce3952578d9d9ad + ee8aa57dda469f3fa25131bab56484ad2a216181 diff --git a/eng/Versions.props b/eng/Versions.props index 22aa700566..a191441f22 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -66,7 +66,7 @@ 7.0.0-beta.22316.2 10.0.18362 13.0.1 - 8.0.0-alpha.1.23266.4 + 8.0.0-alpha.1.23269.1 8.0.0-beta.23218.3 From d1c68b1df1c64f16d76c9ef1850be58d8ceb4ac3 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Sat, 20 May 2023 19:29:54 +0000 Subject: [PATCH 062/111] Update dependencies from https://github.com/dotnet/aspnetcore build 20230519.8 (#3891) [main] Update dependencies from dotnet/aspnetcore --- eng/Version.Details.xml | 8 ++++---- eng/Versions.props | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 18809dc14e..243c87aef0 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -31,13 +31,13 @@ https://github.com/dotnet/installer 8488614afec7497b9e74b47c976af2a97506bb96 - + https://github.com/dotnet/aspnetcore - 631f523a3828530880270ff9accc925f36d67705 + 25e93c30bb536e5554ac607f56d569fd5a228b67 - + https://github.com/dotnet/aspnetcore - 631f523a3828530880270ff9accc925f36d67705 + 25e93c30bb536e5554ac607f56d569fd5a228b67 https://github.com/dotnet/runtime diff --git a/eng/Versions.props b/eng/Versions.props index a191441f22..354d359b66 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -21,8 +21,8 @@ 8.0.0-preview.5.23268.14 8.0.0-preview.5.23268.14 - 8.0.0-preview.5.23268.15 - 8.0.0-preview.5.23268.15 + 8.0.0-preview.5.23269.8 + 8.0.0-preview.5.23269.8 8.0.100-preview.5.23264.2 From b248857026a8fc7628f866728c8913752d5c6bf6 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Sun, 21 May 2023 13:27:34 +0000 Subject: [PATCH 063/111] Update dependencies from https://github.com/dotnet/aspnetcore build 20230520.1 (#3896) [main] Update dependencies from dotnet/aspnetcore --- eng/Version.Details.xml | 8 ++++---- eng/Versions.props | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 243c87aef0..2e5c36c938 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -31,13 +31,13 @@ https://github.com/dotnet/installer 8488614afec7497b9e74b47c976af2a97506bb96 - + https://github.com/dotnet/aspnetcore - 25e93c30bb536e5554ac607f56d569fd5a228b67 + 002650f48d2ea5d8fe1e746e6ef319d95661f325 - + https://github.com/dotnet/aspnetcore - 25e93c30bb536e5554ac607f56d569fd5a228b67 + 002650f48d2ea5d8fe1e746e6ef319d95661f325 https://github.com/dotnet/runtime diff --git a/eng/Versions.props b/eng/Versions.props index 354d359b66..365801f854 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -21,8 +21,8 @@ 8.0.0-preview.5.23268.14 8.0.0-preview.5.23268.14 - 8.0.0-preview.5.23269.8 - 8.0.0-preview.5.23269.8 + 8.0.0-preview.5.23270.1 + 8.0.0-preview.5.23270.1 8.0.100-preview.5.23264.2 From e98b81eead995d43165004eaa9f2d13ecdfe1eff Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Mon, 22 May 2023 13:31:35 +0000 Subject: [PATCH 064/111] Update dependencies from https://github.com/dotnet/aspnetcore build 20230521.1 (#3899) [main] Update dependencies from dotnet/aspnetcore --- eng/Version.Details.xml | 8 ++++---- eng/Versions.props | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 2e5c36c938..a1c565b053 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -31,13 +31,13 @@ https://github.com/dotnet/installer 8488614afec7497b9e74b47c976af2a97506bb96 - + https://github.com/dotnet/aspnetcore - 002650f48d2ea5d8fe1e746e6ef319d95661f325 + c760054e1fbc8749bc0c6f2116b22532424ff60f - + https://github.com/dotnet/aspnetcore - 002650f48d2ea5d8fe1e746e6ef319d95661f325 + c760054e1fbc8749bc0c6f2116b22532424ff60f https://github.com/dotnet/runtime diff --git a/eng/Versions.props b/eng/Versions.props index 365801f854..c12308c2d3 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -21,8 +21,8 @@ 8.0.0-preview.5.23268.14 8.0.0-preview.5.23268.14 - 8.0.0-preview.5.23270.1 - 8.0.0-preview.5.23270.1 + 8.0.0-preview.5.23271.1 + 8.0.0-preview.5.23271.1 8.0.100-preview.5.23264.2 From 95221a2f90977f8fb93ab58b2f252c0bb0c84e8b Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Mon, 22 May 2023 13:37:49 +0000 Subject: [PATCH 065/111] Update dependencies from https://github.com/dotnet/arcade build 20230519.2 (#3897) [main] Update dependencies from dotnet/arcade - Coherency Updates: - Microsoft.SourceLink.GitHub: from 8.0.0-beta.23218.3 to 8.0.0-beta.23252.2 (parent: Microsoft.DotNet.Arcade.Sdk) --- eng/Version.Details.xml | 12 ++++++------ eng/Versions.props | 4 ++-- eng/common/cross/arm/sources.list.xenial | 2 +- eng/common/cross/arm64/sources.list.xenial | 2 +- global.json | 2 +- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index a1c565b053..ccdbe61192 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -14,14 +14,14 @@ - + https://github.com/dotnet/arcade - 1aff4eb33aa7cbf26ccd9fc43c17cb609a14dad4 + 792c346a52b2388152c2fad6f626b88ed8736d6f - + https://github.com/dotnet/arcade - 1aff4eb33aa7cbf26ccd9fc43c17cb609a14dad4 + 792c346a52b2388152c2fad6f626b88ed8736d6f https://github.com/dotnet/arcade @@ -52,9 +52,9 @@ ee8aa57dda469f3fa25131bab56484ad2a216181 - + https://github.com/dotnet/sourcelink - 47c52dd2ebf9edfd40abdcff999c13eb461f6ce2 + 54eb3b811c57f5e94617d31a102fc9cb664ccdd5 diff --git a/eng/Versions.props b/eng/Versions.props index c12308c2d3..92b939047e 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -61,13 +61,13 @@ 4.7.2 4.7.1 2.0.3 - 8.0.0-beta.23262.5 + 8.0.0-beta.23269.2 1.2.0-beta.406 7.0.0-beta.22316.2 10.0.18362 13.0.1 8.0.0-alpha.1.23269.1 - 8.0.0-beta.23218.3 + 8.0.0-beta.23252.2 3.11.0 diff --git a/eng/common/cross/arm/sources.list.xenial b/eng/common/cross/arm/sources.list.xenial index eacd86b7df..56fbb36a59 100644 --- a/eng/common/cross/arm/sources.list.xenial +++ b/eng/common/cross/arm/sources.list.xenial @@ -8,4 +8,4 @@ deb http://ports.ubuntu.com/ubuntu-ports/ xenial-backports main restricted deb-src http://ports.ubuntu.com/ubuntu-ports/ xenial-backports main restricted deb http://ports.ubuntu.com/ubuntu-ports/ xenial-security main restricted universe multiverse -deb-src http://ports.ubuntu.com/ubuntu-ports/ xenial-security main restricted universe multiverse \ No newline at end of file +deb-src http://ports.ubuntu.com/ubuntu-ports/ xenial-security main restricted universe multiverse diff --git a/eng/common/cross/arm64/sources.list.xenial b/eng/common/cross/arm64/sources.list.xenial index eacd86b7df..56fbb36a59 100644 --- a/eng/common/cross/arm64/sources.list.xenial +++ b/eng/common/cross/arm64/sources.list.xenial @@ -8,4 +8,4 @@ deb http://ports.ubuntu.com/ubuntu-ports/ xenial-backports main restricted deb-src http://ports.ubuntu.com/ubuntu-ports/ xenial-backports main restricted deb http://ports.ubuntu.com/ubuntu-ports/ xenial-security main restricted universe multiverse -deb-src http://ports.ubuntu.com/ubuntu-ports/ xenial-security main restricted universe multiverse \ No newline at end of file +deb-src http://ports.ubuntu.com/ubuntu-ports/ xenial-security main restricted universe multiverse diff --git a/global.json b/global.json index b6a0f5bea8..2e1efa23d9 100644 --- a/global.json +++ b/global.json @@ -16,6 +16,6 @@ }, "msbuild-sdks": { "Microsoft.Build.NoTargets": "3.5.0", - "Microsoft.DotNet.Arcade.Sdk": "8.0.0-beta.23262.5" + "Microsoft.DotNet.Arcade.Sdk": "8.0.0-beta.23269.2" } } From 61c7f5bda9875477dd04aab65e51664afa31468d Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Mon, 22 May 2023 17:14:49 +0000 Subject: [PATCH 066/111] [main] Update dependencies from dotnet/installer (#3898) [main] Update dependencies from dotnet/installer - Fix single-file version --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index ccdbe61192..a60da0d4df 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -27,9 +27,9 @@ https://github.com/dotnet/arcade ccfe6da198c5f05534863bbb1bff66e830e0c6ab - + https://github.com/dotnet/installer - 8488614afec7497b9e74b47c976af2a97506bb96 + a78abfe66f0385c5fccb357513afb258bb7e955b https://github.com/dotnet/aspnetcore diff --git a/eng/Versions.props b/eng/Versions.props index 92b939047e..b467bedbe1 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -24,7 +24,7 @@ 8.0.0-preview.5.23271.1 8.0.0-preview.5.23271.1 - 8.0.100-preview.5.23264.2 + 8.0.100-preview.5.23271.2 @@ -35,7 +35,7 @@ $(MicrosoftNETCoreApp60Version) $(MicrosoftNETCoreApp70Version) - 8.0.0-preview.5.23260.3 + 8.0.0-preview.5.23268.13 From da1422508b7304ab8b2e9bcdfb3ce72c60d37e9c Mon Sep 17 00:00:00 2001 From: Mike McLaughlin Date: Mon, 22 May 2023 10:22:18 -0700 Subject: [PATCH 067/111] Clean up IRuntime instance flushing (#3895) * Fix ClrRuntime flushing which is causing random SOS test failures in gcroot * Code review feedback * More changes * Fix failures --- .../Runtime.cs | 16 +++++----------- .../RuntimeProvider.cs | 3 +++ 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/src/Microsoft.Diagnostics.DebugServices.Implementation/Runtime.cs b/src/Microsoft.Diagnostics.DebugServices.Implementation/Runtime.cs index 40b237f884..771e0d14c2 100644 --- a/src/Microsoft.Diagnostics.DebugServices.Implementation/Runtime.cs +++ b/src/Microsoft.Diagnostics.DebugServices.Implementation/Runtime.cs @@ -20,7 +20,6 @@ namespace Microsoft.Diagnostics.DebugServices.Implementation public class Runtime : IRuntime, IDisposable { private readonly ClrInfo _clrInfo; - private readonly IDisposable _onFlushEvent; private readonly ISymbolService _symbolService; private Version _runtimeVersion; private string _dacFilePath; @@ -52,24 +51,19 @@ public Runtime(IServiceProvider services, int id, ClrInfo clrInfo) _serviceContainer.AddService(this); _serviceContainer.AddService(clrInfo); - _onFlushEvent = Target.OnFlushEvent.Register(Flush); - Trace.TraceInformation($"Created runtime #{id} {clrInfo.Flavor} {clrInfo}"); } void IDisposable.Dispose() - { - _serviceContainer.RemoveService(typeof(IRuntime)); - _serviceContainer.DisposeServices(); - _onFlushEvent.Dispose(); - } - - private void Flush() { if (_serviceContainer.TryGetCachedService(typeof(ClrRuntime), out object service)) { - ((ClrRuntime)service).FlushCachedData(); + // The DataTarget created in the RuntimeProvider is disposed here. The ClrRuntime + // instance is disposed below in DisposeServices(). + ((ClrRuntime)service).DataTarget.Dispose(); } + _serviceContainer.RemoveService(typeof(IRuntime)); + _serviceContainer.DisposeServices(); } #region IRuntime diff --git a/src/Microsoft.Diagnostics.DebugServices.Implementation/RuntimeProvider.cs b/src/Microsoft.Diagnostics.DebugServices.Implementation/RuntimeProvider.cs index a755a13d6d..3ea0ab90be 100644 --- a/src/Microsoft.Diagnostics.DebugServices.Implementation/RuntimeProvider.cs +++ b/src/Microsoft.Diagnostics.DebugServices.Implementation/RuntimeProvider.cs @@ -28,6 +28,9 @@ public RuntimeProvider(IServiceProvider services) /// The starting runtime id for this provider public IEnumerable EnumerateRuntimes(int startingRuntimeId) { + // The ClrInfo and DataTarget instances are disposed when Runtime instance is disposed. Runtime instances are + // not flushed when the Target/RuntimeService is flushed; they are all disposed and the list cleared. They are + // all re-created the next time the IRuntime or ClrRuntime instance is queried. DataTarget dataTarget = new(new CustomDataTarget(_services.GetService())) { FileLocator = null From 1780f509ad1298a0c6f7c8ef41d616af6072ee82 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Mon, 22 May 2023 12:09:41 -0700 Subject: [PATCH 068/111] Update dependencies from https://github.com/microsoft/clrmd build 20230519.1 (#3892) Microsoft.Diagnostics.Runtime , Microsoft.Diagnostics.Runtime.Utilities From Version 3.0.0-beta.23268.1 -> To Version 3.0.0-beta.23269.1 Co-authored-by: dotnet-maestro[bot] --- eng/Version.Details.xml | 8 ++++---- eng/Versions.props | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index a60da0d4df..caaf31a05a 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -4,13 +4,13 @@ https://github.com/dotnet/symstore 72212ba2f73877c1bf08a1c5bfbae5501e459e8a - + https://github.com/microsoft/clrmd - 4f66261481b629184d0d378b156ef8fab84456da + e83385be84307b5f88f1d3582dfd9e25c0797664 - + https://github.com/microsoft/clrmd - 4f66261481b629184d0d378b156ef8fab84456da + e83385be84307b5f88f1d3582dfd9e25c0797664 diff --git a/eng/Versions.props b/eng/Versions.props index b467bedbe1..7b188fe67b 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -45,7 +45,7 @@ 5.0.0 6.0.0 - 3.0.0-beta.23268.1 + 3.0.0-beta.23269.1 16.9.0-beta1.21055.5 3.0.7 6.0.0 From 85ce7b96efbc7f0fc1bcfaa2d7d331cbfd691552 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Mon, 22 May 2023 12:11:53 -0700 Subject: [PATCH 069/111] [main] Update dependencies from dotnet/runtime (#3893) * Update dependencies from https://github.com/dotnet/runtime build 20230519.11 Microsoft.NETCore.App.Runtime.win-x64 , VS.Redist.Common.NetCore.SharedFramework.x64.8.0 From Version 8.0.0-preview.5.23268.14 -> To Version 8.0.0-preview.5.23269.11 * Update dependencies from https://github.com/dotnet/runtime build 20230520.7 Microsoft.NETCore.App.Runtime.win-x64 , VS.Redist.Common.NetCore.SharedFramework.x64.8.0 From Version 8.0.0-preview.5.23268.14 -> To Version 8.0.0-preview.5.23270.7 * Update dependencies from https://github.com/dotnet/runtime build 20230522.1 Microsoft.NETCore.App.Runtime.win-x64 , VS.Redist.Common.NetCore.SharedFramework.x64.8.0 From Version 8.0.0-preview.5.23268.14 -> To Version 8.0.0-preview.5.23272.1 --------- Co-authored-by: dotnet-maestro[bot] --- eng/Version.Details.xml | 8 ++++---- eng/Versions.props | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index caaf31a05a..f170abb1d3 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -39,13 +39,13 @@ https://github.com/dotnet/aspnetcore c760054e1fbc8749bc0c6f2116b22532424ff60f - + https://github.com/dotnet/runtime - 2f49fcff6df15a200ef01eea16b3ce7930f75c5c + 9e49620aeee78c0d37dd741f88aff89850a6f5fb - + https://github.com/dotnet/runtime - 2f49fcff6df15a200ef01eea16b3ce7930f75c5c + 9e49620aeee78c0d37dd741f88aff89850a6f5fb https://github.com/dotnet/source-build-reference-packages diff --git a/eng/Versions.props b/eng/Versions.props index 7b188fe67b..15533af64c 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -18,8 +18,8 @@ 1.0.426501 - 8.0.0-preview.5.23268.14 - 8.0.0-preview.5.23268.14 + 8.0.0-preview.5.23272.1 + 8.0.0-preview.5.23272.1 8.0.0-preview.5.23271.1 8.0.0-preview.5.23271.1 From f4578cc2ae10314b7fb6aab2189858ce6e952c73 Mon Sep 17 00:00:00 2001 From: Mike McLaughlin Date: Mon, 22 May 2023 13:41:52 -0700 Subject: [PATCH 070/111] Only run sign, package and publish on internal builds --- diagnostics.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/diagnostics.yml b/diagnostics.yml index e8c56ccaa8..d60a241464 100644 --- a/diagnostics.yml +++ b/diagnostics.yml @@ -383,7 +383,7 @@ extends: # _BuildArch: x64 # Download, sign, package and publish - - ${{ if notin(variables['Build.Reason'], 'PullRequest') }}: + - ${{ if ne(variables['System.TeamProject'], 'public') }}: - template: /eng/common/templates/job/job.yml parameters: name: Sign_Package_Publish From b957aeeecb9e54f416783bbbb9e33a54145428d3 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Tue, 23 May 2023 10:29:01 -0700 Subject: [PATCH 071/111] Update dependencies from https://github.com/dotnet/source-build-reference-packages build 20230523.1 (#3904) Microsoft.SourceBuild.Intermediate.source-build-reference-packages From Version 8.0.0-alpha.1.23269.1 -> To Version 8.0.0-alpha.1.23273.1 Co-authored-by: dotnet-maestro[bot] --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index f170abb1d3..071f7f5d18 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -47,9 +47,9 @@ https://github.com/dotnet/runtime 9e49620aeee78c0d37dd741f88aff89850a6f5fb - + https://github.com/dotnet/source-build-reference-packages - ee8aa57dda469f3fa25131bab56484ad2a216181 + 43c337012443bb42d4baf97b4232dd04b443b5ef diff --git a/eng/Versions.props b/eng/Versions.props index 15533af64c..3e19fe4758 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -66,7 +66,7 @@ 7.0.0-beta.22316.2 10.0.18362 13.0.1 - 8.0.0-alpha.1.23269.1 + 8.0.0-alpha.1.23273.1 8.0.0-beta.23252.2 From fd08028090a176f8219b95813b64fc01b4df51cc Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Tue, 23 May 2023 10:29:29 -0700 Subject: [PATCH 072/111] Update dependencies from https://github.com/dotnet/runtime build 20230523.1 (#3903) Microsoft.NETCore.App.Runtime.win-x64 , VS.Redist.Common.NetCore.SharedFramework.x64.8.0 From Version 8.0.0-preview.5.23272.1 -> To Version 8.0.0-preview.5.23273.1 Co-authored-by: dotnet-maestro[bot] --- eng/Version.Details.xml | 8 ++++---- eng/Versions.props | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 071f7f5d18..a8cb1189b8 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -39,13 +39,13 @@ https://github.com/dotnet/aspnetcore c760054e1fbc8749bc0c6f2116b22532424ff60f - + https://github.com/dotnet/runtime - 9e49620aeee78c0d37dd741f88aff89850a6f5fb + 1e421670a6456d9c5b924b7ffea14cab8559a2e9 - + https://github.com/dotnet/runtime - 9e49620aeee78c0d37dd741f88aff89850a6f5fb + 1e421670a6456d9c5b924b7ffea14cab8559a2e9 https://github.com/dotnet/source-build-reference-packages diff --git a/eng/Versions.props b/eng/Versions.props index 3e19fe4758..1b11be2bff 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -18,8 +18,8 @@ 1.0.426501 - 8.0.0-preview.5.23272.1 - 8.0.0-preview.5.23272.1 + 8.0.0-preview.5.23273.1 + 8.0.0-preview.5.23273.1 8.0.0-preview.5.23271.1 8.0.0-preview.5.23271.1 From ad25ff175c96b6dbf83fe87b304121c47d45c227 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Tue, 23 May 2023 10:29:41 -0700 Subject: [PATCH 073/111] Update dependencies from https://github.com/dotnet/aspnetcore build 20230523.2 (#3902) Microsoft.AspNetCore.App.Ref , Microsoft.AspNetCore.App.Ref.Internal From Version 8.0.0-preview.5.23271.1 -> To Version 8.0.0-preview.5.23273.2 Co-authored-by: dotnet-maestro[bot] --- eng/Version.Details.xml | 8 ++++---- eng/Versions.props | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index a8cb1189b8..193a9c9206 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -31,13 +31,13 @@ https://github.com/dotnet/installer a78abfe66f0385c5fccb357513afb258bb7e955b - + https://github.com/dotnet/aspnetcore - c760054e1fbc8749bc0c6f2116b22532424ff60f + 39564d529f84f7a3bbac5b28ba11060e8ac30375 - + https://github.com/dotnet/aspnetcore - c760054e1fbc8749bc0c6f2116b22532424ff60f + 39564d529f84f7a3bbac5b28ba11060e8ac30375 https://github.com/dotnet/runtime diff --git a/eng/Versions.props b/eng/Versions.props index 1b11be2bff..1e5caf9619 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -21,8 +21,8 @@ 8.0.0-preview.5.23273.1 8.0.0-preview.5.23273.1 - 8.0.0-preview.5.23271.1 - 8.0.0-preview.5.23271.1 + 8.0.0-preview.5.23273.2 + 8.0.0-preview.5.23273.2 8.0.100-preview.5.23271.2 From b12f92439b1646725110171e6358db5bb2e94e22 Mon Sep 17 00:00:00 2001 From: Mike McLaughlin Date: Tue, 23 May 2023 20:27:36 -0700 Subject: [PATCH 074/111] Test against new Ubuntu 22.04 image (#3906) * Test against new Ubuntu 22.04 image * Add python path --- diagnostics.yml | 32 ++++++++++++++-------------- eng/pipelines/pipeline-resources.yml | 1 + 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/diagnostics.yml b/diagnostics.yml index d60a241464..599fce356f 100644 --- a/diagnostics.yml +++ b/diagnostics.yml @@ -365,22 +365,22 @@ extends: # _BuildConfig: Debug # _BuildArch: x64 - #- template: /eng/pipelines/build.yml - # parameters: - # name: Ubuntu_22_04 - # osGroup: Linux - # container: test_ubuntu_22_04 - # dependsOn: Linux_x64 - # testOnly: true - # strategy: - # matrix: - # Build_Release: - # _BuildConfig: Release - # _BuildArch: x64 - # ${{ if in(variables['Build.Reason'], 'PullRequest') }}: - # Build_Debug: - # _BuildConfig: Debug - # _BuildArch: x64 + - template: /eng/pipelines/build.yml + parameters: + name: Ubuntu_22_04 + osGroup: Linux + container: test_ubuntu_22_04 + dependsOn: Linux_x64 + testOnly: true + strategy: + matrix: + Build_Release: + _BuildConfig: Release + _BuildArch: x64 + ${{ if in(variables['Build.Reason'], 'PullRequest') }}: + Build_Debug: + _BuildConfig: Debug + _BuildArch: x64 # Download, sign, package and publish - ${{ if ne(variables['System.TeamProject'], 'public') }}: diff --git a/eng/pipelines/pipeline-resources.yml b/eng/pipelines/pipeline-resources.yml index 524a3793ce..0b3a5b51ed 100644 --- a/eng/pipelines/pipeline-resources.yml +++ b/eng/pipelines/pipeline-resources.yml @@ -57,5 +57,6 @@ resources: - container: test_ubuntu_22_04 image: mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-22.04 + options: '--env PYTHONPATH=/usr/bin/python3.10' stages: ${{ parameters.stages }} From 1e6cde31e80fa115de096fdbbb6a80bab4380a2e Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Wed, 24 May 2023 10:15:19 -0700 Subject: [PATCH 075/111] Update dependencies from https://github.com/dotnet/source-build-reference-packages build 20230523.2 (#3909) Microsoft.SourceBuild.Intermediate.source-build-reference-packages From Version 8.0.0-alpha.1.23273.1 -> To Version 8.0.0-alpha.1.23273.2 Co-authored-by: dotnet-maestro[bot] --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 193a9c9206..da4d654896 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -47,9 +47,9 @@ https://github.com/dotnet/runtime 1e421670a6456d9c5b924b7ffea14cab8559a2e9 - + https://github.com/dotnet/source-build-reference-packages - 43c337012443bb42d4baf97b4232dd04b443b5ef + ccf417a0ac5eb10eae069f9a75a836fcd46af453 diff --git a/eng/Versions.props b/eng/Versions.props index 1e5caf9619..99f5b7039e 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -66,7 +66,7 @@ 7.0.0-beta.22316.2 10.0.18362 13.0.1 - 8.0.0-alpha.1.23273.1 + 8.0.0-alpha.1.23273.2 8.0.0-beta.23252.2 From 413fc1522743d1a3a2f2ceb2b370f7842d5b13f5 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Wed, 24 May 2023 10:16:04 -0700 Subject: [PATCH 076/111] Update dependencies from https://github.com/dotnet/runtime build 20230524.1 (#3908) Microsoft.NETCore.App.Runtime.win-x64 , VS.Redist.Common.NetCore.SharedFramework.x64.8.0 From Version 8.0.0-preview.5.23273.1 -> To Version 8.0.0-preview.5.23274.1 Co-authored-by: dotnet-maestro[bot] --- eng/Version.Details.xml | 8 ++++---- eng/Versions.props | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index da4d654896..7e66f4a34a 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -39,13 +39,13 @@ https://github.com/dotnet/aspnetcore 39564d529f84f7a3bbac5b28ba11060e8ac30375 - + https://github.com/dotnet/runtime - 1e421670a6456d9c5b924b7ffea14cab8559a2e9 + 7a119156cbe958c5c34098434e84010526fac5f1 - + https://github.com/dotnet/runtime - 1e421670a6456d9c5b924b7ffea14cab8559a2e9 + 7a119156cbe958c5c34098434e84010526fac5f1 https://github.com/dotnet/source-build-reference-packages diff --git a/eng/Versions.props b/eng/Versions.props index 99f5b7039e..deb9534f9e 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -18,8 +18,8 @@ 1.0.426501 - 8.0.0-preview.5.23273.1 - 8.0.0-preview.5.23273.1 + 8.0.0-preview.5.23274.1 + 8.0.0-preview.5.23274.1 8.0.0-preview.5.23273.2 8.0.0-preview.5.23273.2 From d417029b16d62cb71c40861b4c717ac6a6ce5f97 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Wed, 24 May 2023 10:16:27 -0700 Subject: [PATCH 077/111] Update dependencies from https://github.com/dotnet/aspnetcore build 20230523.11 (#3907) Microsoft.AspNetCore.App.Ref , Microsoft.AspNetCore.App.Ref.Internal From Version 8.0.0-preview.5.23273.2 -> To Version 8.0.0-preview.6.23273.11 Co-authored-by: dotnet-maestro[bot] --- eng/Version.Details.xml | 8 ++++---- eng/Versions.props | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 7e66f4a34a..2dcd6622bf 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -31,13 +31,13 @@ https://github.com/dotnet/installer a78abfe66f0385c5fccb357513afb258bb7e955b - + https://github.com/dotnet/aspnetcore - 39564d529f84f7a3bbac5b28ba11060e8ac30375 + b300006bf317461d026c73a7775f7ae06e1a2ca8 - + https://github.com/dotnet/aspnetcore - 39564d529f84f7a3bbac5b28ba11060e8ac30375 + b300006bf317461d026c73a7775f7ae06e1a2ca8 https://github.com/dotnet/runtime diff --git a/eng/Versions.props b/eng/Versions.props index deb9534f9e..edaba35bbf 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -21,8 +21,8 @@ 8.0.0-preview.5.23274.1 8.0.0-preview.5.23274.1 - 8.0.0-preview.5.23273.2 - 8.0.0-preview.5.23273.2 + 8.0.0-preview.6.23273.11 + 8.0.0-preview.6.23273.11 8.0.100-preview.5.23271.2 From 66466081cb40f597657299f3d65f4513ac782ce2 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Thu, 25 May 2023 10:39:03 -0700 Subject: [PATCH 078/111] Update dependencies from https://github.com/dotnet/source-build-reference-packages build 20230524.2 (#3912) Microsoft.SourceBuild.Intermediate.source-build-reference-packages From Version 8.0.0-alpha.1.23273.2 -> To Version 8.0.0-alpha.1.23274.2 Co-authored-by: dotnet-maestro[bot] --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 2dcd6622bf..39db4f23b5 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -47,9 +47,9 @@ https://github.com/dotnet/runtime 7a119156cbe958c5c34098434e84010526fac5f1 - + https://github.com/dotnet/source-build-reference-packages - ccf417a0ac5eb10eae069f9a75a836fcd46af453 + db0cbe78748b71b00df05aff15cac2c8ce870cfd diff --git a/eng/Versions.props b/eng/Versions.props index edaba35bbf..a11fedbd72 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -66,7 +66,7 @@ 7.0.0-beta.22316.2 10.0.18362 13.0.1 - 8.0.0-alpha.1.23273.2 + 8.0.0-alpha.1.23274.2 8.0.0-beta.23252.2 From 210d6327ec97ac19f63461cb8300791853d49a5d Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Thu, 25 May 2023 10:40:54 -0700 Subject: [PATCH 079/111] Update dependencies from https://github.com/dotnet/aspnetcore build 20230524.6 (#3910) Microsoft.AspNetCore.App.Ref , Microsoft.AspNetCore.App.Ref.Internal From Version 8.0.0-preview.6.23273.11 -> To Version 8.0.0-preview.6.23274.6 Co-authored-by: dotnet-maestro[bot] --- eng/Version.Details.xml | 8 ++++---- eng/Versions.props | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 39db4f23b5..37b01e7c57 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -31,13 +31,13 @@ https://github.com/dotnet/installer a78abfe66f0385c5fccb357513afb258bb7e955b - + https://github.com/dotnet/aspnetcore - b300006bf317461d026c73a7775f7ae06e1a2ca8 + b441d4e816ef3bc43b72e91ba8793f252ada2c5a - + https://github.com/dotnet/aspnetcore - b300006bf317461d026c73a7775f7ae06e1a2ca8 + b441d4e816ef3bc43b72e91ba8793f252ada2c5a https://github.com/dotnet/runtime diff --git a/eng/Versions.props b/eng/Versions.props index a11fedbd72..4c28404232 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -21,8 +21,8 @@ 8.0.0-preview.5.23274.1 8.0.0-preview.5.23274.1 - 8.0.0-preview.6.23273.11 - 8.0.0-preview.6.23273.11 + 8.0.0-preview.6.23274.6 + 8.0.0-preview.6.23274.6 8.0.100-preview.5.23271.2 From cffac908a5fdbec340e595724abc10cc2814f6e4 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Thu, 25 May 2023 10:41:06 -0700 Subject: [PATCH 080/111] Update dependencies from https://github.com/dotnet/runtime build 20230524.13 (#3911) Microsoft.NETCore.App.Runtime.win-x64 , VS.Redist.Common.NetCore.SharedFramework.x64.8.0 From Version 8.0.0-preview.5.23274.1 -> To Version 8.0.0-preview.5.23274.13 Co-authored-by: dotnet-maestro[bot] --- eng/Version.Details.xml | 8 ++++---- eng/Versions.props | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 37b01e7c57..443be65e90 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -39,13 +39,13 @@ https://github.com/dotnet/aspnetcore b441d4e816ef3bc43b72e91ba8793f252ada2c5a - + https://github.com/dotnet/runtime - 7a119156cbe958c5c34098434e84010526fac5f1 + 7cf329b773fa5ed544a9377587018713751c73e3 - + https://github.com/dotnet/runtime - 7a119156cbe958c5c34098434e84010526fac5f1 + 7cf329b773fa5ed544a9377587018713751c73e3 https://github.com/dotnet/source-build-reference-packages diff --git a/eng/Versions.props b/eng/Versions.props index 4c28404232..5242952401 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -18,8 +18,8 @@ 1.0.426501 - 8.0.0-preview.5.23274.1 - 8.0.0-preview.5.23274.1 + 8.0.0-preview.5.23274.13 + 8.0.0-preview.5.23274.13 8.0.0-preview.6.23274.6 8.0.0-preview.6.23274.6 From aa26d3005b74a35d6ade61bb9cfebe5d87dc9132 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Fri, 26 May 2023 09:42:08 -0700 Subject: [PATCH 081/111] Update dependencies from https://github.com/dotnet/symstore build 20230525.1 (#3915) Microsoft.SymbolStore From Version 1.0.426501 -> To Version 1.0.427501 Co-authored-by: dotnet-maestro[bot] --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 443be65e90..6a872a4f3a 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -1,8 +1,8 @@ - + https://github.com/dotnet/symstore - 72212ba2f73877c1bf08a1c5bfbae5501e459e8a + 9b742f12faf1f14b2554be9fd86739efa4ec3874 https://github.com/microsoft/clrmd diff --git a/eng/Versions.props b/eng/Versions.props index 5242952401..ab9de458e9 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -16,7 +16,7 @@ - 1.0.426501 + 1.0.427501 8.0.0-preview.5.23274.13 8.0.0-preview.5.23274.13 From 3da2dc636dfb215965202e65a053588d01bf7c0b Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Fri, 26 May 2023 09:42:40 -0700 Subject: [PATCH 082/111] Update dependencies from https://github.com/dotnet/runtime build 20230526.1 (#3916) Microsoft.NETCore.App.Runtime.win-x64 , VS.Redist.Common.NetCore.SharedFramework.x64.8.0 From Version 8.0.0-preview.5.23274.13 -> To Version 8.0.0-preview.5.23276.1 Co-authored-by: dotnet-maestro[bot] --- eng/Version.Details.xml | 8 ++++---- eng/Versions.props | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 6a872a4f3a..6a0f08eb8a 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -39,13 +39,13 @@ https://github.com/dotnet/aspnetcore b441d4e816ef3bc43b72e91ba8793f252ada2c5a - + https://github.com/dotnet/runtime - 7cf329b773fa5ed544a9377587018713751c73e3 + 2678b3452e2bac6592baa2a528915ca0de3e6e43 - + https://github.com/dotnet/runtime - 7cf329b773fa5ed544a9377587018713751c73e3 + 2678b3452e2bac6592baa2a528915ca0de3e6e43 https://github.com/dotnet/source-build-reference-packages diff --git a/eng/Versions.props b/eng/Versions.props index ab9de458e9..db2ef40aa1 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -18,8 +18,8 @@ 1.0.427501 - 8.0.0-preview.5.23274.13 - 8.0.0-preview.5.23274.13 + 8.0.0-preview.5.23276.1 + 8.0.0-preview.5.23276.1 8.0.0-preview.6.23274.6 8.0.0-preview.6.23274.6 From 269219a0d0928052b6d84724d5d9e94d38b31ef8 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Fri, 26 May 2023 09:42:53 -0700 Subject: [PATCH 083/111] Update dependencies from https://github.com/dotnet/aspnetcore build 20230525.7 (#3914) Microsoft.AspNetCore.App.Ref , Microsoft.AspNetCore.App.Ref.Internal From Version 8.0.0-preview.6.23274.6 -> To Version 8.0.0-preview.6.23275.7 Co-authored-by: dotnet-maestro[bot] --- eng/Version.Details.xml | 8 ++++---- eng/Versions.props | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 6a0f08eb8a..fb9f1db582 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -31,13 +31,13 @@ https://github.com/dotnet/installer a78abfe66f0385c5fccb357513afb258bb7e955b - + https://github.com/dotnet/aspnetcore - b441d4e816ef3bc43b72e91ba8793f252ada2c5a + f53a14c08ca062025ae03c4dd45be82b2c1f1528 - + https://github.com/dotnet/aspnetcore - b441d4e816ef3bc43b72e91ba8793f252ada2c5a + f53a14c08ca062025ae03c4dd45be82b2c1f1528 https://github.com/dotnet/runtime diff --git a/eng/Versions.props b/eng/Versions.props index db2ef40aa1..e68c388498 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -21,8 +21,8 @@ 8.0.0-preview.5.23276.1 8.0.0-preview.5.23276.1 - 8.0.0-preview.6.23274.6 - 8.0.0-preview.6.23274.6 + 8.0.0-preview.6.23275.7 + 8.0.0-preview.6.23275.7 8.0.100-preview.5.23271.2 From 151a21a9b5aaa75b5257eb5c59257a37312df56a Mon Sep 17 00:00:00 2001 From: Mike McLaughlin Date: Fri, 26 May 2023 18:34:00 -0700 Subject: [PATCH 084/111] Fix gcroot test failures (#3919) The SOS DataReader impl given to clrmd didn't copy the thread context correctly. A future PR will improve the IThread.GetThreadContext() interface method to reduce these kind of bugs. --- .../DataReader.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Microsoft.Diagnostics.DebugServices.Implementation/DataReader.cs b/src/Microsoft.Diagnostics.DebugServices.Implementation/DataReader.cs index 89716bf326..ba1ecc6d21 100644 --- a/src/Microsoft.Diagnostics.DebugServices.Implementation/DataReader.cs +++ b/src/Microsoft.Diagnostics.DebugServices.Implementation/DataReader.cs @@ -55,10 +55,10 @@ bool IDataReader.GetThreadContext(uint threadId, uint contextFlags, Span c try { byte[] registerContext = ThreadService.GetThreadFromId(threadId).GetThreadContext(); - context = new Span(registerContext); + registerContext.AsSpan().Slice(0, context.Length).CopyTo(context); return true; } - catch (DiagnosticsException ex) + catch (Exception ex) when (ex is DiagnosticsException or ArgumentException) { Trace.TraceError($"GetThreadContext: {threadId} exception {ex.Message}"); } From e7d596fdf91c00e7b6926b835890a2ea04aeaa40 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Sat, 27 May 2023 13:28:13 +0000 Subject: [PATCH 085/111] Update dependencies from https://github.com/dotnet/aspnetcore build 20230526.6 (#3920) [main] Update dependencies from dotnet/aspnetcore --- eng/Version.Details.xml | 8 ++++---- eng/Versions.props | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index fb9f1db582..85ffe67a5a 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -31,13 +31,13 @@ https://github.com/dotnet/installer a78abfe66f0385c5fccb357513afb258bb7e955b - + https://github.com/dotnet/aspnetcore - f53a14c08ca062025ae03c4dd45be82b2c1f1528 + 2a709351416d0ad85011805787dbdeaecb251b8f - + https://github.com/dotnet/aspnetcore - f53a14c08ca062025ae03c4dd45be82b2c1f1528 + 2a709351416d0ad85011805787dbdeaecb251b8f https://github.com/dotnet/runtime diff --git a/eng/Versions.props b/eng/Versions.props index e68c388498..0b0606d89a 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -21,8 +21,8 @@ 8.0.0-preview.5.23276.1 8.0.0-preview.5.23276.1 - 8.0.0-preview.6.23275.7 - 8.0.0-preview.6.23275.7 + 8.0.0-preview.6.23276.6 + 8.0.0-preview.6.23276.6 8.0.100-preview.5.23271.2 From af37640a0a5983cd34ad9dafd780d5383bacae0f Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Sat, 27 May 2023 13:40:59 +0000 Subject: [PATCH 086/111] Update dependencies from https://github.com/dotnet/runtime build 20230526.2 (#3921) [main] Update dependencies from dotnet/runtime --- eng/Version.Details.xml | 8 ++++---- eng/Versions.props | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 85ffe67a5a..1490194ebd 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -39,13 +39,13 @@ https://github.com/dotnet/aspnetcore 2a709351416d0ad85011805787dbdeaecb251b8f - + https://github.com/dotnet/runtime - 2678b3452e2bac6592baa2a528915ca0de3e6e43 + 7b2dc26555db2ef75c4ef822613a63b8c1d25e85 - + https://github.com/dotnet/runtime - 2678b3452e2bac6592baa2a528915ca0de3e6e43 + 7b2dc26555db2ef75c4ef822613a63b8c1d25e85 https://github.com/dotnet/source-build-reference-packages diff --git a/eng/Versions.props b/eng/Versions.props index 0b0606d89a..afa32d8cf8 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -18,8 +18,8 @@ 1.0.427501 - 8.0.0-preview.5.23276.1 - 8.0.0-preview.5.23276.1 + 8.0.0-preview.5.23276.2 + 8.0.0-preview.5.23276.2 8.0.0-preview.6.23276.6 8.0.0-preview.6.23276.6 From 5007f171a7e0c86ceca7a34d5ff39d10a1fa05db Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Sun, 28 May 2023 13:22:11 +0000 Subject: [PATCH 087/111] Update dependencies from https://github.com/dotnet/aspnetcore build 20230527.1 (#3922) [main] Update dependencies from dotnet/aspnetcore --- eng/Version.Details.xml | 8 ++++---- eng/Versions.props | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 1490194ebd..c37b2b690a 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -31,13 +31,13 @@ https://github.com/dotnet/installer a78abfe66f0385c5fccb357513afb258bb7e955b - + https://github.com/dotnet/aspnetcore - 2a709351416d0ad85011805787dbdeaecb251b8f + d0e94423f0ef587b8fe262667c8168e14e4f5ac7 - + https://github.com/dotnet/aspnetcore - 2a709351416d0ad85011805787dbdeaecb251b8f + d0e94423f0ef587b8fe262667c8168e14e4f5ac7 https://github.com/dotnet/runtime diff --git a/eng/Versions.props b/eng/Versions.props index afa32d8cf8..0de0100829 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -21,8 +21,8 @@ 8.0.0-preview.5.23276.2 8.0.0-preview.5.23276.2 - 8.0.0-preview.6.23276.6 - 8.0.0-preview.6.23276.6 + 8.0.0-preview.6.23277.1 + 8.0.0-preview.6.23277.1 8.0.100-preview.5.23271.2 From f1aded7c3bb646c185a6205b12396080c91192b2 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Mon, 29 May 2023 13:27:54 +0000 Subject: [PATCH 088/111] Update dependencies from https://github.com/dotnet/arcade build 20230529.1 (#3923) [main] Update dependencies from dotnet/arcade --- eng/Version.Details.xml | 8 ++++---- eng/Versions.props | 2 +- eng/common/sdk-task.ps1 | 2 +- eng/common/templates/job/job.yml | 12 ++++++++---- eng/common/templates/steps/source-build.yml | 6 ++++++ eng/common/tools.ps1 | 4 ++-- global.json | 4 ++-- 7 files changed, 24 insertions(+), 14 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index c37b2b690a..ab45324b77 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -14,14 +14,14 @@ - + https://github.com/dotnet/arcade - 792c346a52b2388152c2fad6f626b88ed8736d6f + 174c08a43b26fc26ba98975065f1125f910f5c37 - + https://github.com/dotnet/arcade - 792c346a52b2388152c2fad6f626b88ed8736d6f + 174c08a43b26fc26ba98975065f1125f910f5c37 https://github.com/dotnet/arcade diff --git a/eng/Versions.props b/eng/Versions.props index 0de0100829..75a8965d20 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -61,7 +61,7 @@ 4.7.2 4.7.1 2.0.3 - 8.0.0-beta.23269.2 + 8.0.0-beta.23279.1 1.2.0-beta.406 7.0.0-beta.22316.2 10.0.18362 diff --git a/eng/common/sdk-task.ps1 b/eng/common/sdk-task.ps1 index e10a596879..6c4ac6fec1 100644 --- a/eng/common/sdk-task.ps1 +++ b/eng/common/sdk-task.ps1 @@ -64,7 +64,7 @@ try { $GlobalJson.tools | Add-Member -Name "vs" -Value (ConvertFrom-Json "{ `"version`": `"16.5`" }") -MemberType NoteProperty } if( -not ($GlobalJson.tools.PSObject.Properties.Name -match "xcopy-msbuild" )) { - $GlobalJson.tools | Add-Member -Name "xcopy-msbuild" -Value "17.4.1" -MemberType NoteProperty + $GlobalJson.tools | Add-Member -Name "xcopy-msbuild" -Value "17.6.0-2" -MemberType NoteProperty } if ($GlobalJson.tools."xcopy-msbuild".Trim() -ine "none") { $xcopyMSBuildToolsFolder = InitializeXCopyMSBuild $GlobalJson.tools."xcopy-msbuild" -install $true diff --git a/eng/common/templates/job/job.yml b/eng/common/templates/job/job.yml index 44ad26abf5..e20ee3a983 100644 --- a/eng/common/templates/job/job.yml +++ b/eng/common/templates/job/job.yml @@ -75,6 +75,10 @@ jobs: - ${{ if eq(parameters.enableRichCodeNavigation, 'true') }}: - name: EnableRichCodeNavigation value: 'true' + # Retry signature validation up to three times, waiting 2 seconds between attempts. + # See https://learn.microsoft.com/en-us/nuget/reference/errors-and-warnings/nu3028#retry-untrusted-root-failures + - name: NUGET_EXPERIMENTAL_CHAIN_BUILD_RETRY_POLICY + value: 3,2000 - ${{ each variable in parameters.variables }}: # handle name-value variable syntax # example: @@ -83,7 +87,7 @@ jobs: - ${{ if ne(variable.name, '') }}: - name: ${{ variable.name }} value: ${{ variable.value }} - + # handle variable groups - ${{ if ne(variable.group, '') }}: - group: ${{ variable.group }} @@ -169,7 +173,7 @@ jobs: - ${{ if eq(parameters.enableMicrobuild, 'true') }}: - ${{ if and(eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}: - task: MicroBuildCleanup@1 - displayName: Execute Microbuild cleanup tasks + displayName: Execute Microbuild cleanup tasks condition: and(always(), in(variables['_SignType'], 'real', 'test'), eq(variables['Agent.Os'], 'Windows_NT')) continueOnError: ${{ parameters.continueOnError }} env: @@ -219,7 +223,7 @@ jobs: displayName: Publish XUnit Test Results inputs: testResultsFormat: 'xUnit' - testResultsFiles: '*.xml' + testResultsFiles: '*.xml' searchFolder: '$(Build.SourcesDirectory)/artifacts/TestResults/$(_BuildConfig)' testRunTitle: ${{ coalesce(parameters.testRunTitle, parameters.name, '$(System.JobName)') }}-xunit mergeTestResults: ${{ parameters.mergeTestResults }} @@ -230,7 +234,7 @@ jobs: displayName: Publish TRX Test Results inputs: testResultsFormat: 'VSTest' - testResultsFiles: '*.trx' + testResultsFiles: '*.trx' searchFolder: '$(Build.SourcesDirectory)/artifacts/TestResults/$(_BuildConfig)' testRunTitle: ${{ coalesce(parameters.testRunTitle, parameters.name, '$(System.JobName)') }}-trx mergeTestResults: ${{ parameters.mergeTestResults }} diff --git a/eng/common/templates/steps/source-build.yml b/eng/common/templates/steps/source-build.yml index a97a185a36..1100521834 100644 --- a/eng/common/templates/steps/source-build.yml +++ b/eng/common/templates/steps/source-build.yml @@ -68,6 +68,11 @@ steps: runtimeOsArgs='/p:RuntimeOS=${{ parameters.platform.runtimeOS }}' fi + baseOsArgs= + if [ '${{ parameters.platform.baseOS }}' != '' ]; then + baseOsArgs='/p:BaseOS=${{ parameters.platform.baseOS }}' + fi + publishArgs= if [ '${{ parameters.platform.skipPublishValidation }}' != 'true' ]; then publishArgs='--publish' @@ -86,6 +91,7 @@ steps: $internalRestoreArgs \ $targetRidArgs \ $runtimeOsArgs \ + $baseOsArgs \ /p:SourceBuildNonPortable=${{ parameters.platform.nonPortable }} \ /p:ArcadeBuildFromSource=true \ /p:AssetManifestFileName=$assetManifestFileName diff --git a/eng/common/tools.ps1 b/eng/common/tools.ps1 index 38cf94ff88..ffe0b4e2df 100644 --- a/eng/common/tools.ps1 +++ b/eng/common/tools.ps1 @@ -384,8 +384,8 @@ function InitializeVisualStudioMSBuild([bool]$install, [object]$vsRequirements = # If the version of msbuild is going to be xcopied, # use this version. Version matches a package here: - # https://dev.azure.com/dnceng/public/_packaging?_a=package&feed=dotnet-eng&package=RoslynTools.MSBuild&protocolType=NuGet&version=17.4.1&view=overview - $defaultXCopyMSBuildVersion = '17.4.1' + # https://dev.azure.com/dnceng/public/_artifacts/feed/dotnet-eng/NuGet/RoslynTools.MSBuild/versions/17.6.0-2 + $defaultXCopyMSBuildVersion = '17.6.0-2' if (!$vsRequirements) { if (Get-Member -InputObject $GlobalJson.tools -Name 'vs') { diff --git a/global.json b/global.json index 2e1efa23d9..ab4da14584 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "tools": { - "dotnet": "8.0.100-preview.3.23178.7", + "dotnet": "8.0.100-preview.4.23260.5", "runtimes": { "dotnet": [ "$(MicrosoftNETCoreApp60Version)", @@ -16,6 +16,6 @@ }, "msbuild-sdks": { "Microsoft.Build.NoTargets": "3.5.0", - "Microsoft.DotNet.Arcade.Sdk": "8.0.0-beta.23269.2" + "Microsoft.DotNet.Arcade.Sdk": "8.0.0-beta.23279.1" } } From 29cb64fc827063b364d1185d8540c12150d01a9e Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Mon, 29 May 2023 13:30:01 +0000 Subject: [PATCH 089/111] Update dependencies from https://github.com/dotnet/runtime build 20230529.2 (#3925) [main] Update dependencies from dotnet/runtime --- eng/Version.Details.xml | 8 ++++---- eng/Versions.props | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index ab45324b77..fb0ee23533 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -39,13 +39,13 @@ https://github.com/dotnet/aspnetcore d0e94423f0ef587b8fe262667c8168e14e4f5ac7 - + https://github.com/dotnet/runtime - 7b2dc26555db2ef75c4ef822613a63b8c1d25e85 + 93da0c966f9bc537dd77fbe2cbeb0bec4ff6a48b - + https://github.com/dotnet/runtime - 7b2dc26555db2ef75c4ef822613a63b8c1d25e85 + 93da0c966f9bc537dd77fbe2cbeb0bec4ff6a48b https://github.com/dotnet/source-build-reference-packages diff --git a/eng/Versions.props b/eng/Versions.props index 75a8965d20..8eec507a1c 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -18,8 +18,8 @@ 1.0.427501 - 8.0.0-preview.5.23276.2 - 8.0.0-preview.5.23276.2 + 8.0.0-preview.5.23279.2 + 8.0.0-preview.5.23279.2 8.0.0-preview.6.23277.1 8.0.0-preview.6.23277.1 From 0bee8b300f57498439a54b219e9cc768037a2868 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Mon, 29 May 2023 18:31:13 +0000 Subject: [PATCH 090/111] [main] Update dependencies from dotnet/installer (#3924) [main] Update dependencies from dotnet/installer - Update single-file runtime version --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index fb0ee23533..16cd52a341 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -27,9 +27,9 @@ https://github.com/dotnet/arcade ccfe6da198c5f05534863bbb1bff66e830e0c6ab - + https://github.com/dotnet/installer - a78abfe66f0385c5fccb357513afb258bb7e955b + 6150605bd0a63b57ef3d8a8cc7355131ceeceb5a https://github.com/dotnet/aspnetcore diff --git a/eng/Versions.props b/eng/Versions.props index 8eec507a1c..3760e3c77a 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -24,7 +24,7 @@ 8.0.0-preview.6.23277.1 8.0.0-preview.6.23277.1 - 8.0.100-preview.5.23271.2 + 8.0.100-preview.6.23276.3 @@ -35,7 +35,7 @@ $(MicrosoftNETCoreApp60Version) $(MicrosoftNETCoreApp70Version) - 8.0.0-preview.5.23268.13 + 8.0.0-preview.5.23272.14 From 40da1ffd4bb8dd22ca0ea3de40ab2046892c17ad Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Tue, 30 May 2023 13:40:40 +0000 Subject: [PATCH 091/111] Update dependencies from https://github.com/dotnet/runtime build 20230529.6 (#3928) [main] Update dependencies from dotnet/runtime --- eng/Version.Details.xml | 8 ++++---- eng/Versions.props | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 16cd52a341..e612567c64 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -39,13 +39,13 @@ https://github.com/dotnet/aspnetcore d0e94423f0ef587b8fe262667c8168e14e4f5ac7 - + https://github.com/dotnet/runtime - 93da0c966f9bc537dd77fbe2cbeb0bec4ff6a48b + 73cb995cff35b053d5b0d3daf319ac33769657d0 - + https://github.com/dotnet/runtime - 93da0c966f9bc537dd77fbe2cbeb0bec4ff6a48b + 73cb995cff35b053d5b0d3daf319ac33769657d0 https://github.com/dotnet/source-build-reference-packages diff --git a/eng/Versions.props b/eng/Versions.props index 3760e3c77a..8fba9e7f4f 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -18,8 +18,8 @@ 1.0.427501 - 8.0.0-preview.5.23279.2 - 8.0.0-preview.5.23279.2 + 8.0.0-preview.6.23279.6 + 8.0.0-preview.6.23279.6 8.0.0-preview.6.23277.1 8.0.0-preview.6.23277.1 From 880cb9b1da240db2ea1ccdcebefcb13e0465a1ac Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Tue, 30 May 2023 13:43:19 +0000 Subject: [PATCH 092/111] Update dependencies from https://github.com/dotnet/aspnetcore build 20230529.8 (#3927) [main] Update dependencies from dotnet/aspnetcore --- eng/Version.Details.xml | 8 ++++---- eng/Versions.props | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index e612567c64..e476fb065e 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -31,13 +31,13 @@ https://github.com/dotnet/installer 6150605bd0a63b57ef3d8a8cc7355131ceeceb5a - + https://github.com/dotnet/aspnetcore - d0e94423f0ef587b8fe262667c8168e14e4f5ac7 + 483c972eb89ca9dbab84a3e223147d5ab0258a11 - + https://github.com/dotnet/aspnetcore - d0e94423f0ef587b8fe262667c8168e14e4f5ac7 + 483c972eb89ca9dbab84a3e223147d5ab0258a11 https://github.com/dotnet/runtime diff --git a/eng/Versions.props b/eng/Versions.props index 8fba9e7f4f..6161cb5538 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -21,8 +21,8 @@ 8.0.0-preview.6.23279.6 8.0.0-preview.6.23279.6 - 8.0.0-preview.6.23277.1 - 8.0.0-preview.6.23277.1 + 8.0.0-preview.6.23279.8 + 8.0.0-preview.6.23279.8 8.0.100-preview.6.23276.3 From 9debdce30aa59446372c1e3a1b115b87c54e6e34 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Tue, 30 May 2023 14:03:35 +0000 Subject: [PATCH 093/111] Update dependencies from https://github.com/dotnet/source-build-reference-packages build 20230529.2 (#3929) [main] Update dependencies from dotnet/source-build-reference-packages --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index e476fb065e..c0ed23d6c7 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -47,9 +47,9 @@ https://github.com/dotnet/runtime 73cb995cff35b053d5b0d3daf319ac33769657d0 - + https://github.com/dotnet/source-build-reference-packages - db0cbe78748b71b00df05aff15cac2c8ce870cfd + 1c8ee93e7a8cc4d32e3ac1306c2d7956c3f9f1c1 diff --git a/eng/Versions.props b/eng/Versions.props index 6161cb5538..aa21dc5972 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -66,7 +66,7 @@ 7.0.0-beta.22316.2 10.0.18362 13.0.1 - 8.0.0-alpha.1.23274.2 + 8.0.0-alpha.1.23279.2 8.0.0-beta.23252.2 From 7ca35242a05228c26fb6417e32cf4d1aba89b6b2 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Wed, 31 May 2023 13:49:03 +0000 Subject: [PATCH 094/111] Update dependencies from https://github.com/dotnet/aspnetcore build 20230531.2 (#3930) [main] Update dependencies from dotnet/aspnetcore --- eng/Version.Details.xml | 8 ++++---- eng/Versions.props | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index c0ed23d6c7..51d4314b6b 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -31,13 +31,13 @@ https://github.com/dotnet/installer 6150605bd0a63b57ef3d8a8cc7355131ceeceb5a - + https://github.com/dotnet/aspnetcore - 483c972eb89ca9dbab84a3e223147d5ab0258a11 + 690d78279e940d267669f825aa6627b0d731f64c - + https://github.com/dotnet/aspnetcore - 483c972eb89ca9dbab84a3e223147d5ab0258a11 + 690d78279e940d267669f825aa6627b0d731f64c https://github.com/dotnet/runtime diff --git a/eng/Versions.props b/eng/Versions.props index aa21dc5972..fac7c39ad1 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -21,8 +21,8 @@ 8.0.0-preview.6.23279.6 8.0.0-preview.6.23279.6 - 8.0.0-preview.6.23279.8 - 8.0.0-preview.6.23279.8 + 8.0.0-preview.6.23281.2 + 8.0.0-preview.6.23281.2 8.0.100-preview.6.23276.3 From 0094555182f3668a99a24b71a5b238b8067528db Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Wed, 31 May 2023 17:44:50 +0000 Subject: [PATCH 095/111] Update dependencies from https://github.com/dotnet/runtime build 20230530.5 (#3931) [main] Update dependencies from dotnet/runtime --- eng/Version.Details.xml | 8 ++++---- eng/Versions.props | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 51d4314b6b..dc9efe30db 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -39,13 +39,13 @@ https://github.com/dotnet/aspnetcore 690d78279e940d267669f825aa6627b0d731f64c - + https://github.com/dotnet/runtime - 73cb995cff35b053d5b0d3daf319ac33769657d0 + bf7fb2ecbf69deb6a73bb8bbca1e56e7beec8d8a - + https://github.com/dotnet/runtime - 73cb995cff35b053d5b0d3daf319ac33769657d0 + bf7fb2ecbf69deb6a73bb8bbca1e56e7beec8d8a https://github.com/dotnet/source-build-reference-packages diff --git a/eng/Versions.props b/eng/Versions.props index fac7c39ad1..164c6ac195 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -18,8 +18,8 @@ 1.0.427501 - 8.0.0-preview.6.23279.6 - 8.0.0-preview.6.23279.6 + 8.0.0-preview.6.23280.5 + 8.0.0-preview.6.23280.5 8.0.0-preview.6.23281.2 8.0.0-preview.6.23281.2 From fa130d3e1bf0021cb74b81f788a80099821b77fd Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Thu, 1 Jun 2023 13:51:14 +0000 Subject: [PATCH 096/111] Update dependencies from https://github.com/dotnet/runtime build 20230601.1 (#3933) [main] Update dependencies from dotnet/runtime --- eng/Version.Details.xml | 8 ++++---- eng/Versions.props | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index dc9efe30db..a788f06b63 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -39,13 +39,13 @@ https://github.com/dotnet/aspnetcore 690d78279e940d267669f825aa6627b0d731f64c - + https://github.com/dotnet/runtime - bf7fb2ecbf69deb6a73bb8bbca1e56e7beec8d8a + 3eb4407e441b539c81c6ea8cc797f97536abd01f - + https://github.com/dotnet/runtime - bf7fb2ecbf69deb6a73bb8bbca1e56e7beec8d8a + 3eb4407e441b539c81c6ea8cc797f97536abd01f https://github.com/dotnet/source-build-reference-packages diff --git a/eng/Versions.props b/eng/Versions.props index 164c6ac195..e850715f0e 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -18,8 +18,8 @@ 1.0.427501 - 8.0.0-preview.6.23280.5 - 8.0.0-preview.6.23280.5 + 8.0.0-preview.6.23301.1 + 8.0.0-preview.6.23301.1 8.0.0-preview.6.23281.2 8.0.0-preview.6.23281.2 From 2c54a03c41969fb0c8cb2797fa3e89a08b2282e8 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Thu, 1 Jun 2023 13:53:53 +0000 Subject: [PATCH 097/111] Update dependencies from https://github.com/dotnet/aspnetcore build 20230531.5 (#3932) [main] Update dependencies from dotnet/aspnetcore --- eng/Version.Details.xml | 8 ++++---- eng/Versions.props | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index a788f06b63..a26a48eef5 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -31,13 +31,13 @@ https://github.com/dotnet/installer 6150605bd0a63b57ef3d8a8cc7355131ceeceb5a - + https://github.com/dotnet/aspnetcore - 690d78279e940d267669f825aa6627b0d731f64c + be14dda052a54373e542a9978f172d1900f15486 - + https://github.com/dotnet/aspnetcore - 690d78279e940d267669f825aa6627b0d731f64c + be14dda052a54373e542a9978f172d1900f15486 https://github.com/dotnet/runtime diff --git a/eng/Versions.props b/eng/Versions.props index e850715f0e..931d3b60b8 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -21,8 +21,8 @@ 8.0.0-preview.6.23301.1 8.0.0-preview.6.23301.1 - 8.0.0-preview.6.23281.2 - 8.0.0-preview.6.23281.2 + 8.0.0-preview.6.23281.5 + 8.0.0-preview.6.23281.5 8.0.100-preview.6.23276.3 From 1c60002a474b6aaddea27d8056d51a75fb7b6473 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Thu, 1 Jun 2023 17:38:09 +0000 Subject: [PATCH 098/111] Update dependencies from https://github.com/dotnet/source-build-reference-packages build 20230531.1 (#3936) [main] Update dependencies from dotnet/source-build-reference-packages --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index a26a48eef5..d87be49722 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -47,9 +47,9 @@ https://github.com/dotnet/runtime 3eb4407e441b539c81c6ea8cc797f97536abd01f - + https://github.com/dotnet/source-build-reference-packages - 1c8ee93e7a8cc4d32e3ac1306c2d7956c3f9f1c1 + 5bc298ffcdf49cea125e418972930d4cd524452d diff --git a/eng/Versions.props b/eng/Versions.props index 931d3b60b8..e2d9358cdc 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -66,7 +66,7 @@ 7.0.0-beta.22316.2 10.0.18362 13.0.1 - 8.0.0-alpha.1.23279.2 + 8.0.0-alpha.1.23281.1 8.0.0-beta.23252.2 From f0098ac32d7d1c9f5e42ebd52fec39fb95e58099 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Fri, 2 Jun 2023 13:38:17 +0000 Subject: [PATCH 099/111] Update dependencies from https://github.com/dotnet/aspnetcore build 20230601.3 (#3937) [main] Update dependencies from dotnet/aspnetcore --- eng/Version.Details.xml | 8 ++++---- eng/Versions.props | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index d87be49722..4c9f03d43c 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -31,13 +31,13 @@ https://github.com/dotnet/installer 6150605bd0a63b57ef3d8a8cc7355131ceeceb5a - + https://github.com/dotnet/aspnetcore - be14dda052a54373e542a9978f172d1900f15486 + d919168952ac4da33be8532c6980547a783a7389 - + https://github.com/dotnet/aspnetcore - be14dda052a54373e542a9978f172d1900f15486 + d919168952ac4da33be8532c6980547a783a7389 https://github.com/dotnet/runtime diff --git a/eng/Versions.props b/eng/Versions.props index e2d9358cdc..1308abaea6 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -21,8 +21,8 @@ 8.0.0-preview.6.23301.1 8.0.0-preview.6.23301.1 - 8.0.0-preview.6.23281.5 - 8.0.0-preview.6.23281.5 + 8.0.0-preview.6.23301.3 + 8.0.0-preview.6.23301.3 8.0.100-preview.6.23276.3 From bfd6b42925cd4e1d123f711487336b187f7d77e5 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Fri, 2 Jun 2023 09:24:59 -0700 Subject: [PATCH 100/111] Update dependencies from https://github.com/dotnet/source-build-reference-packages build 20230601.1 (#3939) Microsoft.SourceBuild.Intermediate.source-build-reference-packages From Version 8.0.0-alpha.1.23281.1 -> To Version 8.0.0-alpha.1.23301.1 Co-authored-by: dotnet-maestro[bot] --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 4c9f03d43c..a7f348ffb7 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -47,9 +47,9 @@ https://github.com/dotnet/runtime 3eb4407e441b539c81c6ea8cc797f97536abd01f - + https://github.com/dotnet/source-build-reference-packages - 5bc298ffcdf49cea125e418972930d4cd524452d + e19d5e6d3d294d9d9360aa0c5a40dc7658439b63 diff --git a/eng/Versions.props b/eng/Versions.props index 1308abaea6..2a441bc05e 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -66,7 +66,7 @@ 7.0.0-beta.22316.2 10.0.18362 13.0.1 - 8.0.0-alpha.1.23281.1 + 8.0.0-alpha.1.23301.1 8.0.0-beta.23252.2 From 95b1a16b02f5820b3af5b54e4e49aafb2863f593 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Fri, 2 Jun 2023 09:25:55 -0700 Subject: [PATCH 101/111] Update dependencies from https://github.com/dotnet/runtime build 20230602.1 (#3938) Microsoft.NETCore.App.Runtime.win-x64 , VS.Redist.Common.NetCore.SharedFramework.x64.8.0 From Version 8.0.0-preview.6.23301.1 -> To Version 8.0.0-preview.6.23302.1 Co-authored-by: dotnet-maestro[bot] --- eng/Version.Details.xml | 8 ++++---- eng/Versions.props | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index a7f348ffb7..3ed632e7ea 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -39,13 +39,13 @@ https://github.com/dotnet/aspnetcore d919168952ac4da33be8532c6980547a783a7389 - + https://github.com/dotnet/runtime - 3eb4407e441b539c81c6ea8cc797f97536abd01f + 7febca6802545d8c96e386187d536bc100d40337 - + https://github.com/dotnet/runtime - 3eb4407e441b539c81c6ea8cc797f97536abd01f + 7febca6802545d8c96e386187d536bc100d40337 https://github.com/dotnet/source-build-reference-packages diff --git a/eng/Versions.props b/eng/Versions.props index 2a441bc05e..892b507970 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -18,8 +18,8 @@ 1.0.427501 - 8.0.0-preview.6.23301.1 - 8.0.0-preview.6.23301.1 + 8.0.0-preview.6.23302.1 + 8.0.0-preview.6.23302.1 8.0.0-preview.6.23301.3 8.0.0-preview.6.23301.3 From 5b4dc1b51fb3858658b54679d0b2b71f030c1f97 Mon Sep 17 00:00:00 2001 From: Mike McLaughlin Date: Fri, 2 Jun 2023 14:25:57 -0700 Subject: [PATCH 102/111] Fix Watson crash on null module names (#3940) --- src/SOS/SOS.Extensions/ModuleServiceFromDebuggerServices.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SOS/SOS.Extensions/ModuleServiceFromDebuggerServices.cs b/src/SOS/SOS.Extensions/ModuleServiceFromDebuggerServices.cs index 39110a923a..ed88c37705 100644 --- a/src/SOS/SOS.Extensions/ModuleServiceFromDebuggerServices.cs +++ b/src/SOS/SOS.Extensions/ModuleServiceFromDebuggerServices.cs @@ -86,7 +86,7 @@ public ModuleFromDebuggerServices( { _moduleService = moduleService; ModuleIndex = moduleIndex; - FileName = imageName; + FileName = imageName ?? string.Empty; ImageBase = imageBase; ImageSize = imageSize; IndexFileSize = indexTimeStamp == InvalidTimeStamp ? null : indexFileSize; From bc60fe0126e2c0d56f37013ff1631cabba20cb80 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Sat, 3 Jun 2023 13:24:49 +0000 Subject: [PATCH 103/111] Update dependencies from https://github.com/microsoft/clrmd build 20230602.1 (#3942) [main] Update dependencies from microsoft/clrmd --- eng/Version.Details.xml | 8 ++++---- eng/Versions.props | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 3ed632e7ea..62b00161fd 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -4,13 +4,13 @@ https://github.com/dotnet/symstore 9b742f12faf1f14b2554be9fd86739efa4ec3874 - + https://github.com/microsoft/clrmd - e83385be84307b5f88f1d3582dfd9e25c0797664 + 272986369826a777686ba616a00acd48febc2546 - + https://github.com/microsoft/clrmd - e83385be84307b5f88f1d3582dfd9e25c0797664 + 272986369826a777686ba616a00acd48febc2546 diff --git a/eng/Versions.props b/eng/Versions.props index 892b507970..1d2eae873c 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -45,7 +45,7 @@ 5.0.0 6.0.0 - 3.0.0-beta.23269.1 + 3.0.0-beta.23302.1 16.9.0-beta1.21055.5 3.0.7 6.0.0 From 671f7c5c2bfa4b52aef40e0489c7cd0b8ee5dc7c Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Sat, 3 Jun 2023 13:31:07 +0000 Subject: [PATCH 104/111] Update dependencies from https://github.com/dotnet/symstore build 20230602.1 (#3943) [main] Update dependencies from dotnet/symstore --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 62b00161fd..44c65fa798 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -1,8 +1,8 @@ - + https://github.com/dotnet/symstore - 9b742f12faf1f14b2554be9fd86739efa4ec3874 + 00f6edae1666690960cd207fd2b7a51232af9605 https://github.com/microsoft/clrmd diff --git a/eng/Versions.props b/eng/Versions.props index 1d2eae873c..c55e98d71e 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -16,7 +16,7 @@ - 1.0.427501 + 1.0.430201 8.0.0-preview.6.23302.1 8.0.0-preview.6.23302.1 From 088eee4f3f33c0ddc256a10413d2d22f24b7d0d9 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Sat, 3 Jun 2023 13:36:28 +0000 Subject: [PATCH 105/111] Update dependencies from https://github.com/dotnet/runtime build 20230602.11 (#3944) [main] Update dependencies from dotnet/runtime --- eng/Version.Details.xml | 8 ++++---- eng/Versions.props | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 44c65fa798..08a5e684be 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -39,13 +39,13 @@ https://github.com/dotnet/aspnetcore d919168952ac4da33be8532c6980547a783a7389 - + https://github.com/dotnet/runtime - 7febca6802545d8c96e386187d536bc100d40337 + 2f18320e731cc3b06bc43cdb4d82dffc4f8f81fc - + https://github.com/dotnet/runtime - 7febca6802545d8c96e386187d536bc100d40337 + 2f18320e731cc3b06bc43cdb4d82dffc4f8f81fc https://github.com/dotnet/source-build-reference-packages diff --git a/eng/Versions.props b/eng/Versions.props index c55e98d71e..946d659bf3 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -18,8 +18,8 @@ 1.0.430201 - 8.0.0-preview.6.23302.1 - 8.0.0-preview.6.23302.1 + 8.0.0-preview.6.23302.11 + 8.0.0-preview.6.23302.11 8.0.0-preview.6.23301.3 8.0.0-preview.6.23301.3 From 585332de2509202e8b132b77be77917d33f365c0 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Sat, 3 Jun 2023 13:38:37 +0000 Subject: [PATCH 106/111] Update dependencies from https://github.com/dotnet/aspnetcore build 20230602.1 (#3941) [main] Update dependencies from dotnet/aspnetcore --- eng/Version.Details.xml | 8 ++++---- eng/Versions.props | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 08a5e684be..faffbdc78d 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -31,13 +31,13 @@ https://github.com/dotnet/installer 6150605bd0a63b57ef3d8a8cc7355131ceeceb5a - + https://github.com/dotnet/aspnetcore - d919168952ac4da33be8532c6980547a783a7389 + c2488eead6ead7208f543d0a57104b5d167b93f9 - + https://github.com/dotnet/aspnetcore - d919168952ac4da33be8532c6980547a783a7389 + c2488eead6ead7208f543d0a57104b5d167b93f9 https://github.com/dotnet/runtime diff --git a/eng/Versions.props b/eng/Versions.props index 946d659bf3..8feb5d4049 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -21,8 +21,8 @@ 8.0.0-preview.6.23302.11 8.0.0-preview.6.23302.11 - 8.0.0-preview.6.23301.3 - 8.0.0-preview.6.23301.3 + 8.0.0-preview.6.23302.1 + 8.0.0-preview.6.23302.1 8.0.100-preview.6.23276.3 From 1aae26791822a907e7c5557965e99a027ae9fb23 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Sat, 3 Jun 2023 14:05:43 +0000 Subject: [PATCH 107/111] Update dependencies from https://github.com/dotnet/source-build-reference-packages build 20230602.3 (#3945) [main] Update dependencies from dotnet/source-build-reference-packages --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index faffbdc78d..a2f4d514e0 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -47,9 +47,9 @@ https://github.com/dotnet/runtime 2f18320e731cc3b06bc43cdb4d82dffc4f8f81fc - + https://github.com/dotnet/source-build-reference-packages - e19d5e6d3d294d9d9360aa0c5a40dc7658439b63 + 4a3b4b6b37bdafe501477bf2e564380e1962ce61 diff --git a/eng/Versions.props b/eng/Versions.props index 8feb5d4049..7b9a331bd8 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -66,7 +66,7 @@ 7.0.0-beta.22316.2 10.0.18362 13.0.1 - 8.0.0-alpha.1.23301.1 + 8.0.0-alpha.1.23302.3 8.0.0-beta.23252.2 From ecdbe3ec25596d33c478f85c728f0081c8d7de45 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Sun, 4 Jun 2023 13:37:26 +0000 Subject: [PATCH 108/111] Update dependencies from https://github.com/dotnet/runtime build 20230603.4 (#3946) [main] Update dependencies from dotnet/runtime --- eng/Version.Details.xml | 8 ++++---- eng/Versions.props | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index a2f4d514e0..dcdd6efb3a 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -39,13 +39,13 @@ https://github.com/dotnet/aspnetcore c2488eead6ead7208f543d0a57104b5d167b93f9 - + https://github.com/dotnet/runtime - 2f18320e731cc3b06bc43cdb4d82dffc4f8f81fc + da1da02bbd2cb54490b7fc22f43ec32f5f302615 - + https://github.com/dotnet/runtime - 2f18320e731cc3b06bc43cdb4d82dffc4f8f81fc + da1da02bbd2cb54490b7fc22f43ec32f5f302615 https://github.com/dotnet/source-build-reference-packages diff --git a/eng/Versions.props b/eng/Versions.props index 7b9a331bd8..a3b8a5627c 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -18,8 +18,8 @@ 1.0.430201 - 8.0.0-preview.6.23302.11 - 8.0.0-preview.6.23302.11 + 8.0.0-preview.6.23303.4 + 8.0.0-preview.6.23303.4 8.0.0-preview.6.23302.1 8.0.0-preview.6.23302.1 From 78ec7d3af701ec51e91816f1277231045e1b8085 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Mon, 5 Jun 2023 13:42:46 +0000 Subject: [PATCH 109/111] Update dependencies from https://github.com/dotnet/arcade build 20230602.3 (#3947) [main] Update dependencies from dotnet/arcade --- eng/Version.Details.xml | 8 ++++---- eng/Versions.props | 2 +- global.json | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index dcdd6efb3a..f67056bed6 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -14,14 +14,14 @@ - + https://github.com/dotnet/arcade - 174c08a43b26fc26ba98975065f1125f910f5c37 + 234e0726c7384ee84bf08550f2d16a1ff2d5c543 - + https://github.com/dotnet/arcade - 174c08a43b26fc26ba98975065f1125f910f5c37 + 234e0726c7384ee84bf08550f2d16a1ff2d5c543 https://github.com/dotnet/arcade diff --git a/eng/Versions.props b/eng/Versions.props index a3b8a5627c..1b2664210d 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -61,7 +61,7 @@ 4.7.2 4.7.1 2.0.3 - 8.0.0-beta.23279.1 + 8.0.0-beta.23302.3 1.2.0-beta.406 7.0.0-beta.22316.2 10.0.18362 diff --git a/global.json b/global.json index ab4da14584..d3ebd457b7 100644 --- a/global.json +++ b/global.json @@ -16,6 +16,6 @@ }, "msbuild-sdks": { "Microsoft.Build.NoTargets": "3.5.0", - "Microsoft.DotNet.Arcade.Sdk": "8.0.0-beta.23279.1" + "Microsoft.DotNet.Arcade.Sdk": "8.0.0-beta.23302.3" } } From 057c93df7b866fc811d17c8947facd896b48c883 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Mon, 5 Jun 2023 14:07:34 +0000 Subject: [PATCH 110/111] Update dependencies from https://github.com/dotnet/runtime build 20230604.2 (#3949) [main] Update dependencies from dotnet/runtime --- eng/Version.Details.xml | 8 ++++---- eng/Versions.props | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index f67056bed6..a7ed6b5556 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -39,13 +39,13 @@ https://github.com/dotnet/aspnetcore c2488eead6ead7208f543d0a57104b5d167b93f9 - + https://github.com/dotnet/runtime - da1da02bbd2cb54490b7fc22f43ec32f5f302615 + 2bf8f1aa83e192a307d5846424880cd61bec1a4f - + https://github.com/dotnet/runtime - da1da02bbd2cb54490b7fc22f43ec32f5f302615 + 2bf8f1aa83e192a307d5846424880cd61bec1a4f https://github.com/dotnet/source-build-reference-packages diff --git a/eng/Versions.props b/eng/Versions.props index 1b2664210d..5ef918d437 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -18,8 +18,8 @@ 1.0.430201 - 8.0.0-preview.6.23303.4 - 8.0.0-preview.6.23303.4 + 8.0.0-preview.6.23304.2 + 8.0.0-preview.6.23304.2 8.0.0-preview.6.23302.1 8.0.0-preview.6.23302.1 From 1c189ab62d02b7cd82197fea1e3a0ae5a0618328 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Mon, 5 Jun 2023 18:10:42 +0000 Subject: [PATCH 111/111] [main] Update dependencies from dotnet/installer (#3948) [main] Update dependencies from dotnet/installer - Update single-file version --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index a7ed6b5556..6c4edc2c12 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -27,9 +27,9 @@ https://github.com/dotnet/arcade ccfe6da198c5f05534863bbb1bff66e830e0c6ab - + https://github.com/dotnet/installer - 6150605bd0a63b57ef3d8a8cc7355131ceeceb5a + 18dc2cf11a2daaaa1633afd0c4225e188ce6c239 https://github.com/dotnet/aspnetcore diff --git a/eng/Versions.props b/eng/Versions.props index 5ef918d437..027abc2e6f 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -24,7 +24,7 @@ 8.0.0-preview.6.23302.1 8.0.0-preview.6.23302.1 - 8.0.100-preview.6.23276.3 + 8.0.100-preview.6.23305.2 @@ -35,7 +35,7 @@ $(MicrosoftNETCoreApp60Version) $(MicrosoftNETCoreApp70Version) - 8.0.0-preview.5.23272.14 + 8.0.0-preview.6.23302.2