Skip to content

Commit 4dc17ae

Browse files
committed
Capture logs on failure to locate source line, falling back to legacy logic
1 parent 060d15b commit 4dc17ae

File tree

2 files changed

+95
-1
lines changed

2 files changed

+95
-1
lines changed

src/Management/src/Endpoint/Actuators/ThreadDump/EventPipeThreadDumper.cs

Lines changed: 89 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -300,7 +300,7 @@ private IEnumerable<StackTraceElement> GetStackTrace(int threadId, StackSourceSa
300300

301301
while (!frameName.StartsWith(ThreadIdTemplate, StringComparison.Ordinal))
302302
{
303-
SourceLocation? sourceLocation = stackSource.GetSourceLine(frameIndex, symbolReader);
303+
SourceLocation? sourceLocation = stackSource.GetSourceLine(frameIndex, symbolReader) ?? LegacyGetSourceLine(stackSource, frameIndex, symbolReader);
304304
StackTraceElement stackElement = GetStackTraceElement(frameName, sourceLocation);
305305

306306
yield return stackElement;
@@ -311,6 +311,94 @@ private IEnumerable<StackTraceElement> GetStackTrace(int threadId, StackSourceSa
311311
}
312312
}
313313

314+
// Much of this code is from PerfView/TraceLog.cs
315+
private SourceLocation? LegacyGetSourceLine(TraceEventStackSource stackSource, StackSourceFrameIndex frameIndex, SymbolReader reader)
316+
{
317+
TraceLog log = stackSource.TraceLog;
318+
uint codeAddress = (uint)frameIndex - (uint)StackSourceFrameIndex.Start;
319+
320+
if (codeAddress >= log.CodeAddresses.Count)
321+
{
322+
return null;
323+
}
324+
325+
var codeAddressIndex = (CodeAddressIndex)codeAddress;
326+
TraceModuleFile moduleFile = log.CodeAddresses.ModuleFile(codeAddressIndex);
327+
328+
if (moduleFile == null)
329+
{
330+
string hexAddress = log.CodeAddresses.Address(codeAddressIndex).ToString("X", CultureInfo.InvariantCulture);
331+
_logger.LogTrace("LegacyGetSourceLine: Could not find moduleFile {HexAddress}.", hexAddress);
332+
return null;
333+
}
334+
335+
MethodIndex methodIndex = log.CodeAddresses.MethodIndex(codeAddressIndex);
336+
337+
if (methodIndex == MethodIndex.Invalid)
338+
{
339+
string hexAddress = log.CodeAddresses.Address(codeAddressIndex).ToString("X", CultureInfo.InvariantCulture);
340+
_logger.LogTrace("LegacyGetSourceLine: Could not find method for {HexAddress}.", hexAddress);
341+
return null;
342+
}
343+
344+
int methodToken = log.CodeAddresses.Methods.MethodToken(methodIndex);
345+
346+
if (methodToken == 0)
347+
{
348+
string hexAddress = log.CodeAddresses.Address(codeAddressIndex).ToString("X", CultureInfo.InvariantCulture);
349+
_logger.LogTrace("LegacyGetSourceLine: Could not find method for {HexAddress}.", hexAddress);
350+
return null;
351+
}
352+
353+
int ilOffset = log.CodeAddresses.ILOffset(codeAddressIndex);
354+
355+
if (ilOffset < 0)
356+
{
357+
ilOffset = 0;
358+
}
359+
360+
string? pdbFileName = null;
361+
362+
if (moduleFile.PdbSignature != Guid.Empty)
363+
{
364+
pdbFileName = reader.FindSymbolFilePath(moduleFile.PdbName, moduleFile.PdbSignature, moduleFile.PdbAge, moduleFile.FilePath,
365+
moduleFile.ProductVersion, true);
366+
}
367+
368+
if (pdbFileName == null)
369+
{
370+
string simpleName = Path.GetFileNameWithoutExtension(moduleFile.FilePath);
371+
372+
if (simpleName.EndsWith(".il", StringComparison.Ordinal))
373+
{
374+
simpleName = Path.GetFileNameWithoutExtension(simpleName);
375+
}
376+
377+
pdbFileName = reader.FindSymbolFilePath($"{simpleName}.pdb", Guid.Empty, 0);
378+
}
379+
380+
if (pdbFileName != null)
381+
{
382+
ManagedSymbolModule symbolReaderModule = reader.OpenSymbolFile(pdbFileName);
383+
384+
if (symbolReaderModule != null)
385+
{
386+
if (moduleFile.PdbSignature != Guid.Empty && symbolReaderModule.PdbGuid != moduleFile.PdbSignature)
387+
{
388+
_logger.LogTrace("ERROR: The PDB opened does not match the PDB desired. PDB GUID = {PdbGuid}, DESIRED GUID = {DesiredGuid}",
389+
symbolReaderModule.PdbGuid, moduleFile.PdbSignature);
390+
391+
return null;
392+
}
393+
394+
symbolReaderModule.ExePath = moduleFile.FilePath;
395+
return symbolReaderModule.SourceLocationForManagedCode((uint)methodToken, ilOffset);
396+
}
397+
}
398+
399+
return null;
400+
}
401+
314402
private static StackTraceElement GetStackTraceElement(string frameName, SourceLocation? sourceLocation)
315403
{
316404
if (string.IsNullOrEmpty(frameName))

src/Management/test/Endpoint.Test/Actuators/ThreadDump/EventPipeThreadDumperTest.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,12 @@ public async Task Can_resolve_source_location_from_pdb()
3535
StackTraceElement? backgroundThreadFrame = threads.SelectMany(thread => thread.StackTrace)
3636
.FirstOrDefault(frame => frame.MethodName == "BackgroundThreadCallback(class System.Object)");
3737

38+
if (backgroundThreadFrame == null)
39+
{
40+
string logs = loggerProvider.GetAsText();
41+
throw new InvalidOperationException($"Failed to find expected stack frame. Captured log:{System.Environment.NewLine}{logs}");
42+
}
43+
3844
backgroundThreadFrame.Should().NotBeNull();
3945
backgroundThreadFrame.IsNativeMethod.Should().BeFalse();
4046
backgroundThreadFrame.ModuleName.Should().Be(GetType().Assembly.GetName().Name);

0 commit comments

Comments
 (0)