Skip to content

Commit b6821ef

Browse files
Check for and report corrupt PDBs (#103)
* Check for and report corrupt PDBs * Also refactor some string literals into constants * Bump latest release to 2022.11.05
1 parent a02de4e commit b6821ef

File tree

7 files changed

+41
-18
lines changed

7 files changed

+41
-18
lines changed

Engine/DiaUtil.cs

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -48,12 +48,10 @@ private void ReleaseDiaObjects() {
4848
}
4949

5050
/// This function builds up the PDB map, by searching for matched PDBs (based on name) and constructing the DIA session for each
51-
internal static bool LocateandLoadPDBs(Dictionary<string, DiaUtil> _diautils, string userSuppliedSymPath, string symSrvSymPath, bool recurse, Dictionary<string, string> moduleNamesMap, bool cachePDB, List<string> modulesToIgnore) {
51+
internal static bool LocateandLoadPDBs(string currentModule, string pdbFileName, Dictionary<string, DiaUtil> _diautils, string userSuppliedSymPath, string symSrvSymPath, bool recurse, bool cachePDB, List<string> modulesToIgnore, out string errorDetails) {
5252
var completeSymPath = $"{symSrvSymPath};{userSuppliedSymPath}";
53-
List<string> moduleNames;
54-
lock (moduleNamesMap) moduleNames = moduleNamesMap.Keys.ToList();
5553
// loop through each module, trying to find matched PDB files
56-
foreach (string currentModule in moduleNames.Where(m => !modulesToIgnore.Contains(m) && !_diautils.ContainsKey(m))) {
54+
if (!modulesToIgnore.Contains(currentModule) && !_diautils.ContainsKey(currentModule)) {
5755
// we only need to search for the PDB if it does not already exist in our map
5856
var cachedPDBFile = Path.Combine(Path.GetTempPath(), "SymCache", currentModule + ".pdb");
5957
lock (_syncRoot) { // the lock is needed to ensure that we do not make multiple copies of PDBs when cachePDB is true
@@ -75,8 +73,6 @@ internal static bool LocateandLoadPDBs(Dictionary<string, DiaUtil> _diautils, st
7573
}
7674

7775
// if needed, make a last attempt looking for the original module name - but only amongst user-supplied symbol path folder(s)
78-
string pdbFileName;
79-
lock (moduleNamesMap) pdbFileName = moduleNamesMap[currentModule] + ".pdb";
8076
if (!foundFiles.Any()) foreach (var currPath in userSuppliedSymPath.Split(';').Where(p => Directory.Exists(p) && !p.EndsWith(currentModule))) {
8177
foundFiles = Directory.EnumerateFiles(currPath, pdbFileName, recurse ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly);
8278
}
@@ -92,10 +88,12 @@ internal static bool LocateandLoadPDBs(Dictionary<string, DiaUtil> _diautils, st
9288
try {
9389
_diautils.Add(currentModule, new DiaUtil(cachedPDBFile));
9490
} catch (COMException) {
91+
errorDetails = cachedPDBFile;
9592
return false;
9693
}
9794
} else if (!modulesToIgnore.Contains(currentModule)) modulesToIgnore.Add(currentModule);
9895
}
96+
errorDetails = string.Empty;
9997
return true;
10098
}
10199

@@ -127,7 +125,7 @@ internal static string GetSourceInfo(IDiaEnumLineNumbers enumLineNums, bool pdbH
127125
// only if we found line number information should we append to output
128126
if (enumLineNums.count > 0) {
129127
for (uint tmpOrdinal = 0; tmpOrdinal < enumLineNums.count; tmpOrdinal++) {
130-
if (tmpOrdinal > 0) sbOutput.Append(" -- WARNING: multiple matches -- ");
128+
if (tmpOrdinal > 0) sbOutput.Append($" {StackResolver.WARNING_PREFIX} multiple matches -- ");
131129
sbOutput.Append(string.Format(CultureInfo.CurrentCulture,
132130
"({0}:{1})", enumLineNums.Item(tmpOrdinal).sourceFile.fileName,
133131
enumLineNums.Item(tmpOrdinal).lineNumber));
@@ -136,7 +134,7 @@ internal static string GetSourceInfo(IDiaEnumLineNumbers enumLineNums, bool pdbH
136134
Marshal.FinalReleaseComObject(enumLineNums.Item(tmpOrdinal));
137135
}
138136
}
139-
else if (pdbHasSourceInfo) sbOutput.Append("-- WARNING: unable to find source info --");
137+
else if (pdbHasSourceInfo) sbOutput.Append($"{StackResolver.WARNING_PREFIX} unable to find source info --");
140138
Marshal.FinalReleaseComObject(enumLineNums);
141139
return sbOutput.ToString();
142140
}
@@ -163,9 +161,9 @@ internal static string ProcessInlineFrames(string moduleName, bool useUndecorate
163161
}
164162
Marshal.FinalReleaseComObject(enumInlinees);
165163
} catch (COMException) {
166-
sbInline.AppendLine(" -- WARNING: Unable to process inline frames; maybe symbols are mismatched?");
164+
sbInline.AppendLine($" {StackResolver.WARNING_PREFIX} Unable to process inline frames; maybe symbols are mismatched?");
167165
} catch (System.ArgumentException) {
168-
sbInline.AppendLine(" -- WARNING: Unable to process inline frames; maybe symbols are mismatched?");
166+
sbInline.AppendLine($" {StackResolver.WARNING_PREFIX} Unable to process inline frames; maybe symbols are mismatched?");
169167
}
170168

171169
return sbInline.ToString();

Engine/StackResolver.cs

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ public class StackResolver : IDisposable {
55
public const string OperationCanceled = "Operation cancelled.";
66
public const int OperationWaitIntervalMilliseconds = 300;
77
public const int Operation100Percent = 100;
8+
public const string WARNING_PREFIX = "-- WARNING:";
89

910
/// This is used to store module name and start / end virtual address ranges
1011
/// Only populated if the user provides a tab-separated string corresponding to the output of the following SQL query:
@@ -87,7 +88,9 @@ private string ResolveSymbols(Dictionary<string, DiaUtil> _diautils, Dictionary<
8788
var matchAlreadySymbolized = rgxAlreadySymbolizedFrame.Match(currentFrame);
8889
if (matchAlreadySymbolized.Success) {
8990
var matchedModuleName = matchAlreadySymbolized.Groups["module"].Value;
90-
if (!_diautils.ContainsKey(matchedModuleName)) DiaUtil.LocateandLoadPDBs(_diautils, userSuppliedSymPath, symSrvSymPath, searchPDBsRecursively, new Dictionary<string, string>() { { matchedModuleName, matchedModuleName } }, cachePDB, modulesToIgnore);
91+
if (!_diautils.ContainsKey(matchedModuleName) && !DiaUtil.LocateandLoadPDBs(matchedModuleName, $"{matchedModuleName}.pdb", _diautils, userSuppliedSymPath, symSrvSymPath, searchPDBsRecursively, cachePDB, modulesToIgnore, out string errorDetails)) {
92+
currentFrame += $" {WARNING_PREFIX} could not load symbol file {errorDetails}. The file may possibly be corrupt.";
93+
}
9194
if (_diautils.TryGetValue(matchedModuleName, out var existingEntry) && _diautils[matchedModuleName].HasSourceInfo) {
9295
var myDIAsession = existingEntry._IDiaSession;
9396
myDIAsession.findChildrenEx(myDIAsession.globalScope, SymTagEnum.SymTagNull, matchAlreadySymbolized.Groups["symbolizedfunc"].Value, 0, out IDiaEnumSymbols matchedSyms);
@@ -107,7 +110,7 @@ private string ResolveSymbols(Dictionary<string, DiaUtil> _diautils, Dictionary<
107110
if (enumAllLineNums.Item(tmpOrdinalInner).addressOffset <= currAddress
108111
&& currAddress < enumAllLineNums.Item(tmpOrdinalInner).addressOffset + enumAllLineNums.Item(tmpOrdinalInner).length) {
109112
currentFrame = $"{matchedModuleName}+{currAddress - enumAllLineNums.Item(tmpOrdinalInner).addressOffset + enumAllLineNums.Item(tmpOrdinalInner).relativeVirtualAddress:X}"
110-
+ (foundMatch ? " -- WARNING: ambiguous symbol; relookup might be incorrect -- " : String.Empty);
113+
+ (foundMatch ? $" {WARNING_PREFIX}: ambiguous symbol; relookup might be incorrect -- " : String.Empty);
111114
foundMatch = true;
112115
}
113116
Marshal.FinalReleaseComObject(enumAllLineNums.Item(tmpOrdinalInner));
@@ -125,8 +128,14 @@ private string ResolveSymbols(Dictionary<string, DiaUtil> _diautils, Dictionary<
125128
var match = rgxModuleName.Match(currentFrame);
126129
if (match.Success) {
127130
var matchedModuleName = match.Groups["module"].Value;
128-
lock (moduleNamesMap) if (!moduleNamesMap.ContainsKey(matchedModuleName)) moduleNamesMap.Add(matchedModuleName, matchedModuleName);
129-
if (!_diautils.ContainsKey(matchedModuleName)) DiaUtil.LocateandLoadPDBs(_diautils, userSuppliedSymPath, symSrvSymPath, searchPDBsRecursively, moduleNamesMap, cachePDB, modulesToIgnore);
131+
string pdbFileName;
132+
lock (moduleNamesMap) {
133+
if (!moduleNamesMap.ContainsKey(matchedModuleName)) moduleNamesMap.Add(matchedModuleName, matchedModuleName);
134+
pdbFileName = $"{moduleNamesMap[matchedModuleName]}.pdb";
135+
}
136+
if (!_diautils.ContainsKey(matchedModuleName) && !DiaUtil.LocateandLoadPDBs(matchedModuleName, pdbFileName, _diautils, userSuppliedSymPath, symSrvSymPath, searchPDBsRecursively, cachePDB, modulesToIgnore, out string errorDetails)) {
137+
currentFrame += $" {WARNING_PREFIX} could not load symbol file {errorDetails}. The file may possibly be corrupt.";
138+
}
130139
int frameNumFromInput = string.IsNullOrWhiteSpace(match.Groups["framenum"].Value) ? int.MinValue : Convert.ToInt32(match.Groups["framenum"].Value, 16);
131140
if (frameNumFromInput != int.MinValue && runningFrameNum == int.MinValue) runningFrameNum = frameNumFromInput;
132141
if (_diautils.ContainsKey(matchedModuleName)) {
@@ -216,7 +225,7 @@ private string ProcessFrameModuleOffset(Dictionary<string, DiaUtil> _diautils, D
216225
Marshal.FinalReleaseComObject(enumLineNums);
217226
}
218227
var originalModuleName = moduleNamesMap.TryGetValue(moduleName, out string existingModule) ? existingModule : moduleName;
219-
if (showInlineFrames && pdbHasSourceInfo && !sourceInfo.Contains("-- WARNING:")) {
228+
if (showInlineFrames && pdbHasSourceInfo && !sourceInfo.Contains(WARNING_PREFIX)) {
220229
inlineFrameAndSourceInfo = DiaUtil.ProcessInlineFrames(originalModuleName, useUndecorateLogic, includeOffset, includeSourceInfo, rva, mysym, pdbHasSourceInfo);
221230
}
222231

Engine/XELHelper.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ await xeStream.ReadEventStream(evt => {
6767
parent.PercentComplete = (int)((double)parent.globalCounter / callstackRaw.Count * 100.0);
6868
}
6969

70-
if (hasOverflow) xmlEquivalent.AppendLine("<!-- WARNING: output was truncated due to size limits -->");
70+
if (hasOverflow) xmlEquivalent.AppendLine($"<!{StackResolver.WARNING_PREFIX} output was truncated due to size limits -->");
7171
xmlEquivalent.AppendLine("</Events>");
7272
finalEventCount = callstackRaw.Count;
7373
}

GUI/MainForm.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ private void ResolveCallstacks_Click(object sender, EventArgs e) {
9797
finalOutput.Text = resolverTask.Result;
9898
}
9999

100-
if (finalOutput.Text.Contains("WARNING:")) {
100+
if (finalOutput.Text.Contains(StackResolver.WARNING_PREFIX)) {
101101
MessageBox.Show(this,
102102
"One or more potential issues exist in the output. This is sometimes due to mismatched symbols, so please double-check symbol paths and re-run if needed.",
103103
"Potential issues with the output", MessageBoxButtons.OK, MessageBoxIcon.Warning);

Tests/TestCases/downloadsyms.ps1

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,14 @@ if (-not (test-path $localpath)) {
5757
dir "./TestOrdinal"
5858
}
5959

60+
### CorruptPDB
61+
mkdir -Force "./CorruptPDB" -ErrorAction Ignore
62+
$localpath = "./CorruptPDB/sqldk.pdb"
63+
if (-not (test-path $localpath)) {
64+
(Get-Content "./TestOrdinal/sqldk.pdb" -encoding byte -TotalCount 1000) | Set-Content $localpath -encoding byte
65+
dir $localpath
66+
}
67+
6068
### ImportXEL
6169
mkdir -Force "./ImportXEL" -ErrorAction Ignore
6270
$localpath = "./ImportXEL/XESpins_0_131627061603030000.xel"

Tests/Tests.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,14 @@ public class Tests {
7575
Assert.AreEqual(expectedSymbol + Environment.NewLine + expectedSymbol, ret.Trim());
7676
}
7777

78+
/// A corrupt PDB should be reported as a warning
79+
[TestMethod][TestCategory("Unit")] public async Task CorruptPDBWarning() {
80+
using var csr = new StackResolver();
81+
using var cts = new CancellationTokenSource();
82+
var ret = await csr.ResolveCallstacksAsync(await csr.GetListofCallStacksAsync("sqldk+40609", false, cts), @"..\..\..\Tests\TestCases\CorruptPDB", false, null, false, false, false, true, false, false, null, cts);
83+
Assert.IsTrue(ret.StartsWith($"sqldk+40609 {StackResolver.WARNING_PREFIX}"));
84+
}
85+
7886
/// Test the resolution of a "regular" symbol with virtual address as input.
7987
[TestMethod][TestCategory("Unit")] public async Task RegularSymbolVirtualAddress() {
8088
using var csr = new StackResolver();

latestrelease.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
2022-10-29 00:00
1+
2022-11-05 00:00

0 commit comments

Comments
 (0)