Skip to content

Commit 81ee19d

Browse files
committed
Adding line number support
Adding support for having pmip file per domain. Also keeping support for loading "legacy" pmip files.
1 parent abb5a72 commit 81ee19d

File tree

2 files changed

+136
-44
lines changed

2 files changed

+136
-44
lines changed

FuzzyRangeComparer.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ struct Range
77
public ulong Start;
88
public ulong End;
99
public string Name;
10+
public string File;
1011
}
1112
class FuzzyRangeComparer : IComparer<Range>
1213
{

UnityMixedCallstackFilter.cs

Lines changed: 135 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,20 @@ namespace UnityMixedCallstack
1414
public class UnityMixedCallstackFilter : IDkmCallStackFilter, IDkmLoadCompleteNotification, IDkmModuleInstanceLoadNotification
1515
{
1616
private static List<Range> _rangesSortedByIp = new List<Range>();
17+
private static List<Range> _legacyRanges = new List<Range>();
1718
private static FuzzyRangeComparer _comparer = new FuzzyRangeComparer();
1819
private static bool _enabled;
1920
private static IVsOutputWindowPane _debugPane;
20-
private static string _currentFile;
21+
private static Dictionary<int, PmipFile> _currentFiles = new Dictionary<int, PmipFile>();
2122
private static FileStream _fileStream;
2223
private static StreamReader _fileStreamReader;
2324

25+
struct PmipFile
26+
{
27+
public int count;
28+
public string path;
29+
}
30+
2431
public void OnLoadComplete(DkmProcess process, DkmWorkList workList, DkmEventDescriptor eventDescriptor)
2532
{
2633
DisposeStreams();
@@ -30,6 +37,8 @@ public void OnLoadComplete(DkmProcess process, DkmWorkList workList, DkmEventDes
3037
IVsOutputWindow outWindow = Package.GetGlobalService(typeof(SVsOutputWindow)) as IVsOutputWindow;
3138
Guid debugPaneGuid = VSConstants.GUID_OutWindowDebugPane;
3239
outWindow?.GetPane(ref debugPaneGuid, out _debugPane);
40+
if (_debugPane != null)
41+
_debugPane.OutputString("MIXEDCALLSTACK WORKS NOW?!\n");
3342
}
3443
}
3544

@@ -47,12 +56,21 @@ public DkmStackWalkFrame[] FilterNextFrame(DkmStackContext stackContext, DkmStac
4756
if (!_enabled) // environment variable not set
4857
return new[] { input };
4958

50-
return new[] { UnityMixedStackFrame(stackContext, input) };
59+
try
60+
{
61+
DkmStackWalkFrame[] retVal = new[] { UnityMixedStackFrame(stackContext, input) };
62+
return retVal;
63+
} catch (Exception ex)
64+
{
65+
_debugPane?.OutputString("UNITYMIXEDCALLSTACK :: ip : " + input.Process.LivePart.Id + " threw exception: " + ex.Message + "\n" + ex.StackTrace);
66+
}
67+
return new[] { input };
5168
}
5269

5370
private static DkmStackWalkFrame UnityMixedStackFrame(DkmStackContext stackContext, DkmStackWalkFrame frame)
5471
{
5572
RefreshStackData(frame.Process.LivePart.Id);
73+
_debugPane?.OutputString("UNITYMIXEDCALLSTACK :: done refreshing data\n");
5674
string name = null;
5775
if (TryGetDescriptionForIp(frame.InstructionAddress.CPUInstructionPart.InstructionPointer, out name))
5876
return DkmStackWalkFrame.Create(
@@ -88,96 +106,169 @@ private static void DisposeStreams()
88106
_fileStream?.Dispose();
89107
_fileStream = null;
90108

91-
_currentFile = null;
92-
93109
_rangesSortedByIp.Clear();
94110
}
95111

112+
private static bool CheckForUpdatedFiles(FileInfo[] taskFiles)
113+
{
114+
bool retVal = false;
115+
try
116+
{
117+
foreach (FileInfo taskFile in taskFiles)
118+
{
119+
string fName = Path.GetFileNameWithoutExtension(taskFile.Name);
120+
string[] tokens = fName.Split('_');
121+
PmipFile pmipFile = new PmipFile()
122+
{
123+
count = int.Parse(tokens[2]),
124+
path = taskFile.FullName
125+
};
126+
127+
_debugPane?.OutputString("MIXEDCALLSTACK :: parsing fName: " + fName + " Tokens length: "+ tokens.Length +"\n");
128+
129+
// 3 is legacy and treat everything as root domain
130+
if (tokens.Length == 3 &&
131+
(!_currentFiles.TryGetValue(0, out PmipFile curFile) ||
132+
curFile.count < pmipFile.count))
133+
{
134+
_currentFiles[0] = pmipFile;
135+
retVal = true;
136+
}
137+
else if (tokens.Length == 4)
138+
{
139+
int domainID = int.Parse(tokens[3]);
140+
if (!_currentFiles.TryGetValue(domainID, out PmipFile cFile) || cFile.count < pmipFile.count)
141+
{
142+
_debugPane?.OutputString("MIXEDCALLSTACK :: adding pmip file to list: " + pmipFile.path + "\n");
143+
_currentFiles[domainID] = pmipFile;
144+
retVal = true;
145+
}
146+
}
147+
}
148+
} catch (Exception e)
149+
{
150+
_debugPane?.OutputString("MIXEDCALLSTACK :: BAD THINGS HAPPEND: " + e.Message + "\n");
151+
_enabled = false;
152+
}
153+
return retVal;
154+
}
155+
96156
private static void RefreshStackData(int pid)
97157
{
98158
DirectoryInfo taskDirectory = new DirectoryInfo(Path.GetTempPath());
99159
FileInfo[] taskFiles = taskDirectory.GetFiles("pmip_" + pid + "_*.txt");
100160

161+
_debugPane?.OutputString("MIXEDCALLSTACK :: taskfiles length: " + taskFiles.Length + "\n");
162+
101163
if (taskFiles.Length < 1)
102164
return;
103165

104-
Array.Sort(taskFiles, (a, b) => GetFileNameSequenceNum(a.Name).CompareTo(GetFileNameSequenceNum(b.Name)));
105-
var fileName = taskFiles[taskFiles.Length - 1].FullName;
166+
if (!CheckForUpdatedFiles(taskFiles))
167+
return;
106168

107-
if (_currentFile != fileName)
169+
foreach (PmipFile pmipFile in _currentFiles.Values)
108170
{
171+
172+
_debugPane?.OutputString("MIXEDCALLSTACK :: Reading pmip file: " + pmipFile.path + "\n");
109173
DisposeStreams();
110174
try
111175
{
112-
_fileStream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite | FileShare.Delete);
176+
_fileStream = new FileStream(pmipFile.path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite | FileShare.Delete);
113177
_fileStreamReader = new StreamReader(_fileStream);
114-
_currentFile = fileName;
115178
var versionStr = _fileStreamReader.ReadLine();
116179
const char delimiter = ':';
117180
var tokens = versionStr.Split(delimiter);
118181

119182
if (tokens.Length != 2)
120-
throw new Exception("Failed reading input file " + fileName + ": Incorrect format");
183+
throw new Exception("Failed reading input file " + pmipFile.path + ": Incorrect format");
121184

122185
if (!double.TryParse(tokens[1], NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture, out var version))
123-
throw new Exception("Failed reading input file " + fileName + ": Incorrect version format");
186+
throw new Exception("Failed reading input file " + pmipFile.path + ": Incorrect version format");
124187

125-
if(version > 1.0)
126-
throw new Exception("Failed reading input file " + fileName + ": A newer version of UnityMixedCallstacks plugin is required to read this file");
188+
if (version > 2.0)
189+
throw new Exception("Failed reading input file " + pmipFile.path + ": A newer version of UnityMixedCallstacks plugin is required to read this file");
127190
}
128191
catch (Exception ex)
129192
{
130-
_debugPane?.OutputString("Unable to read dumped pmip file: " + ex.Message + "\n");
193+
_debugPane?.OutputString("MIXEDCALLSTACK :: Unable to read dumped pmip file: " + ex.Message + "\n");
131194
DisposeStreams();
132195
_enabled = false;
133196
return;
134197
}
135-
}
136198

137-
try
138-
{
139-
string line;
140-
while ((line = _fileStreamReader.ReadLine()) != null)
199+
try
141200
{
142-
const char delemiter = ';';
143-
var tokens = line.Split(delemiter);
144-
145-
//should never happen, but lets be safe and not get array out of bounds if it does
146-
if (tokens.Length != 3)
147-
continue;
148-
149-
var startip = tokens[0];
150-
var endip = tokens[1];
151-
var description = tokens[2];
152-
153-
var startiplong = ulong.Parse(startip, NumberStyles.HexNumber);
154-
var endipint = ulong.Parse(endip, NumberStyles.HexNumber);
155-
_rangesSortedByIp.Add(new Range() { Name = description, Start = startiplong, End = endipint });
201+
string line;
202+
while ((line = _fileStreamReader.ReadLine()) != null)
203+
{
204+
const char delemiter = ';';
205+
var tokens = line.Split(delemiter);
206+
207+
//should never happen, but lets be safe and not get array out of bounds if it does
208+
if (tokens.Length == 3 || tokens.Length == 4)
209+
{
210+
string startip = tokens[0];
211+
string endip = tokens[1];
212+
string description = tokens[2];
213+
string file = "";
214+
if (tokens.Length == 4)
215+
file = tokens[3];
216+
217+
if (startip.StartsWith("---"))
218+
{
219+
startip = startip.Remove(0, 3);
220+
}
221+
222+
var startiplong = ulong.Parse(startip, NumberStyles.HexNumber);
223+
var endipint = ulong.Parse(endip, NumberStyles.HexNumber);
224+
if (tokens[0].StartsWith("---"))
225+
{
226+
// legacy stored in new pmip file
227+
_legacyRanges.Add(new Range() { Name = description, File = file, Start = startiplong, End = endipint });
228+
}
229+
else
230+
_rangesSortedByIp.Add(new Range() { Name = description, File = file, Start = startiplong, End = endipint });
231+
}
232+
}
233+
_debugPane?.OutputString("MIXEDCALLSTACK :: map now has " + _rangesSortedByIp.Count + " entries! legacy map has: "+ _legacyRanges.Count +"\n");
234+
}
235+
catch (Exception ex)
236+
{
237+
_debugPane?.OutputString("MIXEDCALLSTACK :: Unable to read dumped pmip file: " + ex.Message + "\n");
238+
DisposeStreams();
239+
_enabled = false;
240+
return;
156241
}
157-
}
158-
catch (Exception ex)
159-
{
160-
_debugPane?.OutputString("Unable to read dumped pmip file: " + ex.Message + "\n");
161-
DisposeStreams();
162-
_enabled = false;
163-
return;
164242
}
165243

244+
_legacyRanges.Sort((r1, r2) => r1.Start.CompareTo(r2.Start));
166245
_rangesSortedByIp.Sort((r1, r2) => r1.Start.CompareTo(r2.Start));
167246
}
168247

169248
private static bool TryGetDescriptionForIp(ulong ip, out string name)
170249
{
171250
name = string.Empty;
172251

252+
_debugPane?.OutputString("MIXEDCALLSTACK :: Looking for ip: " + String.Format("{0:X}", ip) + "\n");
173253
var rangeToFindIp = new Range() { Start = ip };
174254
var index = _rangesSortedByIp.BinarySearch(rangeToFindIp, _comparer);
255+
256+
if (index >= 0)
257+
{
258+
_debugPane?.OutputString("MIXEDCALLSTACK :: SUCCESS!!\n");
259+
name = _rangesSortedByIp[index].Name;
260+
return true;
261+
}
175262

176-
if (index < 0)
177-
return false;
263+
index = _legacyRanges.BinarySearch(rangeToFindIp, _comparer);
264+
if (index >= 0)
265+
{
266+
_debugPane?.OutputString("MIXEDCALLSTACK :: LEGACY SUCCESS!! "+ String.Format("{0:X}", _legacyRanges[index].Start) +" -- "+ String.Format("{0:X}", _legacyRanges[index].End) + "\n");
267+
name = _legacyRanges[index].Name;
268+
return true;
269+
}
178270

179-
name = _rangesSortedByIp[index].Name;
180-
return true;
271+
return false;
181272
}
182273

183274
public void OnModuleInstanceLoad(DkmModuleInstance moduleInstance, DkmWorkList workList, DkmEventDescriptorS eventDescriptor)

0 commit comments

Comments
 (0)