Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/component-common.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/component-configuration.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/component-connectors.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/component-discovery.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/component-logging.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/component-management.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/component-security.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
15 changes: 12 additions & 3 deletions nuget.config
Original file line number Diff line number Diff line change
@@ -1,8 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<!-- Required for .NET Aspire Configuration Schema Generator, which needs System.CommandLine. -->
<clear />
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" />
<add key="dotnet-libraries" value="https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-libraries/nuget/v3/index.json" />
<add key="NuGet" value="https://api.nuget.org/v3/index.json" />
</packageSources>
<packageSourceMapping>
<packageSource key="nuget.org">
<package pattern="*" />
</packageSource>
<packageSource key="dotnet-libraries">
<!-- Required for .NET Aspire Configuration Schema Generator, which needs System.CommandLine. -->
<package pattern="System.CommandLine" />
</packageSource>
</packageSourceMapping>
</configuration>
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ private async Task<List<ThreadInfo>> GetThreadsFromEventPipeSessionAsync(EventPi

List<ThreadInfo> results = ReadStackSource(stackSource, symbolReader).ToList();

_logger.LogTrace("Finished thread walk.");
_logger.LogTrace("Finished thread walk, found {Count} results.", results.Count);
return results;
}
finally
Expand Down Expand Up @@ -237,6 +237,8 @@ private IEnumerable<ThreadInfo> 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))
Expand All @@ -257,6 +259,14 @@ private IEnumerable<ThreadInfo> 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<StackSourceSample> samples) in samplesForThread)
{
Expand Down Expand Up @@ -300,7 +310,7 @@ private IEnumerable<StackTraceElement> 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;
Expand All @@ -311,6 +321,94 @@ private IEnumerable<StackTraceElement> 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))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down