diff --git a/.github/workflows/component-common.yml b/.github/workflows/component-common.yml
index 80f6ea8e7b..4909d6736a 100644
--- a/.github/workflows/component-common.yml
+++ b/.github/workflows/component-common.yml
@@ -8,6 +8,7 @@ on:
- stylecop.json
- '*.props'
- '*.ruleset'
+ - nuget.config
- .config/dotnet-tools.json
- .github/workflows/component-shared-workflow.yml
- .github/workflows/component-common.yml
diff --git a/.github/workflows/component-configuration.yml b/.github/workflows/component-configuration.yml
index f0cae5d49c..3f6cc30272 100644
--- a/.github/workflows/component-configuration.yml
+++ b/.github/workflows/component-configuration.yml
@@ -8,6 +8,7 @@ on:
- stylecop.json
- '*.props'
- '*.ruleset'
+ - nuget.config
- .config/dotnet-tools.json
- .github/workflows/component-shared-workflow.yml
- .github/workflows/component-configuration.yml
diff --git a/.github/workflows/component-connectors.yml b/.github/workflows/component-connectors.yml
index 375c7677f9..43f173b6f4 100644
--- a/.github/workflows/component-connectors.yml
+++ b/.github/workflows/component-connectors.yml
@@ -8,6 +8,7 @@ on:
- stylecop.json
- '*.props'
- '*.ruleset'
+ - nuget.config
- .config/dotnet-tools.json
- .github/workflows/component-shared-workflow.yml
- .github/workflows/component-connectors.yml
diff --git a/.github/workflows/component-discovery.yml b/.github/workflows/component-discovery.yml
index 12bf4088a7..7e991eb1db 100644
--- a/.github/workflows/component-discovery.yml
+++ b/.github/workflows/component-discovery.yml
@@ -8,6 +8,7 @@ on:
- stylecop.json
- '*.props'
- '*.ruleset'
+ - nuget.config
- .config/dotnet-tools.json
- .github/workflows/component-shared-workflow.yml
- .github/workflows/component-discovery.yml
diff --git a/.github/workflows/component-logging.yml b/.github/workflows/component-logging.yml
index 1a453d26a8..1ad817653a 100644
--- a/.github/workflows/component-logging.yml
+++ b/.github/workflows/component-logging.yml
@@ -8,6 +8,7 @@ on:
- stylecop.json
- '*.props'
- '*.ruleset'
+ - nuget.config
- .config/dotnet-tools.json
- .github/workflows/component-shared-workflow.yml
- .github/workflows/component-logging.yml
diff --git a/.github/workflows/component-management.yml b/.github/workflows/component-management.yml
index e3a01e34f8..da124fbeea 100644
--- a/.github/workflows/component-management.yml
+++ b/.github/workflows/component-management.yml
@@ -8,6 +8,7 @@ on:
- stylecop.json
- '*.props'
- '*.ruleset'
+ - nuget.config
- .config/dotnet-tools.json
- .github/workflows/component-shared-workflow.yml
- .github/workflows/component-management.yml
diff --git a/.github/workflows/component-security.yml b/.github/workflows/component-security.yml
index cfe3a805f5..25658195ec 100644
--- a/.github/workflows/component-security.yml
+++ b/.github/workflows/component-security.yml
@@ -8,6 +8,7 @@ on:
- stylecop.json
- '*.props'
- '*.ruleset'
+ - nuget.config
- .config/dotnet-tools.json
- .github/workflows/component-shared-workflow.yml
- .github/workflows/component-security.yml
diff --git a/nuget.config b/nuget.config
index f5253c498c..d363dbb2bd 100644
--- a/nuget.config
+++ b/nuget.config
@@ -1,8 +1,17 @@
-
+
-
+
+
-
+
+
+
+
+
+
+
+
+
diff --git a/src/Management/src/Endpoint/Actuators/ThreadDump/EventPipeThreadDumper.cs b/src/Management/src/Endpoint/Actuators/ThreadDump/EventPipeThreadDumper.cs
index 4270877b40..8fd30e2691 100644
--- a/src/Management/src/Endpoint/Actuators/ThreadDump/EventPipeThreadDumper.cs
+++ b/src/Management/src/Endpoint/Actuators/ThreadDump/EventPipeThreadDumper.cs
@@ -155,7 +155,7 @@ private async Task> GetThreadsFromEventPipeSessionAsync(EventPi
List results = ReadStackSource(stackSource, symbolReader).ToList();
- _logger.LogTrace("Finished thread walk.");
+ _logger.LogTrace("Finished thread walk, found {Count} results.", results.Count);
return results;
}
finally
@@ -237,6 +237,8 @@ private IEnumerable ReadStackSource(MutableTraceEventStackSource sta
stackSource.ForEach(sample =>
{
+ _logger.LogTrace("Analyzing sample: {Sample}", sample);
+
StackSourceCallStackIndex stackIndex = sample.StackIndex;
while (!stackSource.GetFrameName(stackSource.GetFrameIndex(stackIndex), false).StartsWith(ThreadIdTemplate, StringComparison.Ordinal))
@@ -257,6 +259,14 @@ private IEnumerable ReadStackSource(MutableTraceEventStackSource sta
}
});
+ // Workaround for Sonar bug, which incorrectly flags the code as unreachable.
+#pragma warning disable S2589 // Boolean expressions should not be gratuitous
+ if (samplesForThread.Count == 0)
+ {
+ _logger.LogWarning("No managed samples found.");
+ }
+#pragma warning restore S2589 // Boolean expressions should not be gratuitous
+
// For every thread recorded in our trace, use the first stack.
foreach ((int threadId, List samples) in samplesForThread)
{
@@ -300,7 +310,7 @@ private IEnumerable GetStackTrace(int threadId, StackSourceSa
while (!frameName.StartsWith(ThreadIdTemplate, StringComparison.Ordinal))
{
- SourceLocation? sourceLocation = stackSource.GetSourceLine(frameIndex, symbolReader);
+ SourceLocation? sourceLocation = stackSource.GetSourceLine(frameIndex, symbolReader) ?? LegacyGetSourceLine(stackSource, frameIndex, symbolReader);
StackTraceElement stackElement = GetStackTraceElement(frameName, sourceLocation);
yield return stackElement;
@@ -311,6 +321,94 @@ private IEnumerable GetStackTrace(int threadId, StackSourceSa
}
}
+ // Much of this code is from PerfView/TraceLog.cs
+ private SourceLocation? LegacyGetSourceLine(TraceEventStackSource stackSource, StackSourceFrameIndex frameIndex, SymbolReader reader)
+ {
+ TraceLog log = stackSource.TraceLog;
+ uint codeAddress = (uint)frameIndex - (uint)StackSourceFrameIndex.Start;
+
+ if (codeAddress >= log.CodeAddresses.Count)
+ {
+ return null;
+ }
+
+ var codeAddressIndex = (CodeAddressIndex)codeAddress;
+ TraceModuleFile moduleFile = log.CodeAddresses.ModuleFile(codeAddressIndex);
+
+ if (moduleFile == null)
+ {
+ string hexAddress = log.CodeAddresses.Address(codeAddressIndex).ToString("X", CultureInfo.InvariantCulture);
+ _logger.LogTrace("LegacyGetSourceLine: Could not find moduleFile {HexAddress}.", hexAddress);
+ return null;
+ }
+
+ MethodIndex methodIndex = log.CodeAddresses.MethodIndex(codeAddressIndex);
+
+ if (methodIndex == MethodIndex.Invalid)
+ {
+ string hexAddress = log.CodeAddresses.Address(codeAddressIndex).ToString("X", CultureInfo.InvariantCulture);
+ _logger.LogTrace("LegacyGetSourceLine: Could not find method for {HexAddress}.", hexAddress);
+ return null;
+ }
+
+ int methodToken = log.CodeAddresses.Methods.MethodToken(methodIndex);
+
+ if (methodToken == 0)
+ {
+ string hexAddress = log.CodeAddresses.Address(codeAddressIndex).ToString("X", CultureInfo.InvariantCulture);
+ _logger.LogTrace("LegacyGetSourceLine: Could not find method for {HexAddress}.", hexAddress);
+ return null;
+ }
+
+ int ilOffset = log.CodeAddresses.ILOffset(codeAddressIndex);
+
+ if (ilOffset < 0)
+ {
+ ilOffset = 0;
+ }
+
+ string? pdbFileName = null;
+
+ if (moduleFile.PdbSignature != Guid.Empty)
+ {
+ pdbFileName = reader.FindSymbolFilePath(moduleFile.PdbName, moduleFile.PdbSignature, moduleFile.PdbAge, moduleFile.FilePath,
+ moduleFile.ProductVersion, true);
+ }
+
+ if (pdbFileName == null)
+ {
+ string simpleName = Path.GetFileNameWithoutExtension(moduleFile.FilePath);
+
+ if (simpleName.EndsWith(".il", StringComparison.Ordinal))
+ {
+ simpleName = Path.GetFileNameWithoutExtension(simpleName);
+ }
+
+ pdbFileName = reader.FindSymbolFilePath($"{simpleName}.pdb", Guid.Empty, 0);
+ }
+
+ if (pdbFileName != null)
+ {
+ ManagedSymbolModule symbolReaderModule = reader.OpenSymbolFile(pdbFileName);
+
+ if (symbolReaderModule != null)
+ {
+ if (moduleFile.PdbSignature != Guid.Empty && symbolReaderModule.PdbGuid != moduleFile.PdbSignature)
+ {
+ _logger.LogTrace("ERROR: The PDB opened does not match the PDB desired. PDB GUID = {PdbGuid}, DESIRED GUID = {DesiredGuid}",
+ symbolReaderModule.PdbGuid, moduleFile.PdbSignature);
+
+ return null;
+ }
+
+ symbolReaderModule.ExePath = moduleFile.FilePath;
+ return symbolReaderModule.SourceLocationForManagedCode((uint)methodToken, ilOffset);
+ }
+ }
+
+ return null;
+ }
+
private static StackTraceElement GetStackTraceElement(string frameName, SourceLocation? sourceLocation)
{
if (string.IsNullOrEmpty(frameName))
diff --git a/src/Management/test/Endpoint.Test/Actuators/ThreadDump/EventPipeThreadDumperTest.cs b/src/Management/test/Endpoint.Test/Actuators/ThreadDump/EventPipeThreadDumperTest.cs
index 01346608b3..9ddf7acb2d 100644
--- a/src/Management/test/Endpoint.Test/Actuators/ThreadDump/EventPipeThreadDumperTest.cs
+++ b/src/Management/test/Endpoint.Test/Actuators/ThreadDump/EventPipeThreadDumperTest.cs
@@ -35,6 +35,12 @@ public async Task Can_resolve_source_location_from_pdb()
StackTraceElement? backgroundThreadFrame = threads.SelectMany(thread => thread.StackTrace)
.FirstOrDefault(frame => frame.MethodName == "BackgroundThreadCallback(class System.Object)");
+ if (backgroundThreadFrame == null)
+ {
+ string logs = loggerProvider.GetAsText();
+ throw new InvalidOperationException($"Failed to find expected stack frame. Captured log:{System.Environment.NewLine}{logs}");
+ }
+
backgroundThreadFrame.Should().NotBeNull();
backgroundThreadFrame.IsNativeMethod.Should().BeFalse();
backgroundThreadFrame.ModuleName.Should().Be(GetType().Assembly.GetName().Name);