Skip to content
Merged
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
10 changes: 6 additions & 4 deletions Engine/StackResolver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ public bool IsInputSingleLine(string text, string patternsToTreatAsMultiline) {
/// Runs through each of the frames in a call stack and looks up symbols for each
private string ResolveSymbols(Dictionary<string, DiaUtil> _diautils, string[] callStackLines, string symPath, bool searchPDBsRecursively, bool cachePDB, bool includeSourceInfo, bool relookupSource, bool includeOffsets, bool showInlineFrames, List<string> modulesToIgnore, CancellationTokenSource cts) {
var finalCallstack = new StringBuilder();
int frameNum = int.MinValue;
int runningFrameNum = int.MinValue;
foreach (var iterFrame in callStackLines) {
if (cts.IsCancellationRequested) { StatusMessage = OperationCanceled; PercentComplete = 0; return OperationCanceled; }
// hard-coded find-replace for XML markup - useful when importing from XML histograms
Expand Down Expand Up @@ -127,9 +127,10 @@ private string ResolveSymbols(Dictionary<string, DiaUtil> _diautils, string[] ca
var matchedModuleName = match.Groups["module"].Value;
// maybe we have a "not well-known" module, attempt to (best effort) find PDB for it.
if (!_diautils.ContainsKey(matchedModuleName)) DiaUtil.LocateandLoadPDBs(_diautils, symPath, searchPDBsRecursively, new List<string>() { matchedModuleName }, cachePDB, modulesToIgnore);
frameNum = string.IsNullOrWhiteSpace(match.Groups["framenum"].Value) ? int.MinValue : frameNum == int.MinValue ? Convert.ToInt32(match.Groups["framenum"].Value, 16) : frameNum;
int frameNumFromInput = string.IsNullOrWhiteSpace(match.Groups["framenum"].Value) ? int.MinValue : Convert.ToInt32(match.Groups["framenum"].Value, 16);
if (frameNumFromInput != int.MinValue && runningFrameNum == int.MinValue) runningFrameNum = frameNumFromInput;
if (_diautils.ContainsKey(matchedModuleName)) {
string processedFrame = ProcessFrameModuleOffset(_diautils, ref frameNum, matchedModuleName, match.Groups["offset"].Value, includeSourceInfo, includeOffsets, showInlineFrames);
string processedFrame = ProcessFrameModuleOffset(_diautils, frameNumFromInput, ref runningFrameNum, matchedModuleName, match.Groups["offset"].Value, includeSourceInfo, includeOffsets, showInlineFrames);
if (!string.IsNullOrEmpty(processedFrame)) finalCallstack.AppendLine(processedFrame); // typically this is because we could not find the offset in any known function range
else finalCallstack.AppendLine(currentFrame);
}
Expand Down Expand Up @@ -162,7 +163,7 @@ private bool TryObtainModuleOffset(ulong virtAddress, out string moduleName, out

/// This is the most important function in this whole utility! It uses DIA to lookup the symbol based on RVA offset
/// It also looks up line number information if available and then formats all of this information for returning to caller
private string ProcessFrameModuleOffset(Dictionary<string, DiaUtil> _diautils, ref int frameNum, string moduleName, string offset, bool includeSourceInfo, bool includeOffset, bool showInlineFrames) {
private string ProcessFrameModuleOffset(Dictionary<string, DiaUtil> _diautils, int frameNumFromInput, ref int frameNum, string moduleName, string offset, bool includeSourceInfo, bool includeOffset, bool showInlineFrames) {
bool useUndecorateLogic = false;

// the offsets in the XE output are in hex, so we convert to base-10 accordingly
Expand Down Expand Up @@ -233,6 +234,7 @@ private string ProcessFrameModuleOffset(Dictionary<string, DiaUtil> _diautils, r
}

if (frameNum != int.MinValue) {
if (frameNumFromInput == 0) frameNum = frameNumFromInput;
var withFrameNums = new StringBuilder();
var resultLines = result.Split('\n');
foreach (var line in resultLines) {
Expand Down
16 changes: 16 additions & 0 deletions Tests/Tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -494,6 +494,22 @@ private string PrepareLargeXEventInput() {
Assert.AreEqual(expected.Trim(), ret.Trim());
}

/// End-to-end test with stacks being resolved based on symbols from symsrv, and to check that frame numbers are preserved
[TestMethod][TestCategory("Unit")] public async Task E2ESymSrvXMLFramesWithInlineFramesAndRenumbering() {
using var csr = new StackResolver();
using var cts = new CancellationTokenSource();
var pdbPath = @"srv*https://msdl.microsoft.com/download/symbols";
var input = "<frame id=\"00\" pdb=\"ntdll.pdb\" age=\"1\" guid=\"C374E059-5793-9B92-6525-386A66A2D3F5\" module=\"ntdll.dll\" rva=\"0x9F7E4\" />" +
"<frame id=\"01\" pdb=\"Wdf01000.pdb\" age=\"1\" guid=\"C9EC2937-69A8-15AB-22B5-909C290FB963\" module=\"Wdf01000.sys\" rva=\"0x17f27\" />\r\n" +
"<frame id=\"02\" pdb=\"kernelbase.pdb\" age=\"1\" guid=\"E77E26E7-D1C4-72BB-2C05-DD17624A9E58\" module=\"KERNELBASE.dll\" rva=\"0x38973\" />\r\n\r\n" +
"<frame id=\"00\" pdb=\"ntdll.pdb\" age=\"1\" guid=\"C374E059-5793-9B92-6525-386A66A2D3F5\" module=\"ntdll.dll\" rva=\"0x9F7E4\" />" +
"<frame id=\"01\" pdb=\"kernelbase.pdb\" age=\"1\" guid=\"E77E26E7-D1C4-72BB-2C05-DD17624A9E58\" module=\"KERNELBASE.dll\" rva=\"0x38973\" />";

var ret = await csr.ResolveCallstacksAsync(await csr.GetListofCallStacksAsync(input, false, cts), pdbPath, false, null, false, true, false, true, true, false, null, cts);
var expected = "00 ntdll!NtWaitForSingleObject+20\r\n01 (Inline Function) Wdf01000!Mx::MxLeaveCriticalRegion+12 (minkernel\\wdf\\framework\\shared\\inc\\primitives\\km\\MxGeneralKm.h:198)\r\n02 (Inline Function) Wdf01000!FxWaitLockInternal::ReleaseLock+62 (minkernel\\wdf\\framework\\shared\\inc\\private\\common\\FxWaitLock.hpp:305)\r\n03 (Inline Function) Wdf01000!FxEnumerationInfo::ReleaseParentPowerStateLock+62 (minkernel\\wdf\\framework\\shared\\inc\\private\\common\\FxPkgPnp.hpp:510)\r\n04 Wdf01000!FxPkgPnp::PowerPolicyCanChildPowerUp+143 (minkernel\\wdf\\framework\\shared\\inc\\private\\common\\FxPkgPnp.hpp:4127)\r\n05 KERNELBASE!WaitForSingleObjectEx+147\r\n00 ntdll!NtWaitForSingleObject+20\r\n01 KERNELBASE!WaitForSingleObjectEx+147";
Assert.AreEqual(expected.Trim(), ret.Trim());
}

/// End-to-end test with stacks being resolved based on symbols from symsrv, with XML-encoded input (as is usually seen in clients like SSMS).
[TestMethod][TestCategory("Unit")] public async Task E2ESymSrvXMLFramesEncoded() {
using var csr = new StackResolver();
Expand Down