Skip to content

Commit 569033c

Browse files
authored
PMIP fix issue with mono_dont_free_domains (Unity-Technologies#3)
* read use latest file * Address Feedback * Print errors correctly. Check env variable on attach, disable if not set.
1 parent eaa90ce commit 569033c

File tree

3 files changed

+111
-48
lines changed

3 files changed

+111
-48
lines changed

PmipCallStackFilter.cs

Lines changed: 107 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,41 @@
11
using System;
22
using System.Collections.Generic;
3+
using System.Diagnostics;
34
using System.Globalization;
45
using System.IO;
6+
using Microsoft.VisualStudio;
7+
using Microsoft.VisualStudio.Debugger;
58
using Microsoft.VisualStudio.Debugger.CallStack;
69
using Microsoft.VisualStudio.Debugger.ComponentInterfaces;
10+
using Microsoft.VisualStudio.Shell;
11+
using Microsoft.VisualStudio.Shell.Interop;
712

813
namespace PmipMyCallStack
914
{
10-
public class PmipCallStackFilter : IDkmCallStackFilter
15+
public class PmipCallStackFilter : IDkmCallStackFilter, IDkmLoadCompleteNotification
1116
{
12-
private static Range[] _rangesSortedByIp;
13-
private static long _previousFileLength;
17+
private static List<Range> _rangesSortedByIp = new List<Range>();
1418
private static FuzzyRangeComparer _comparer = new FuzzyRangeComparer();
19+
private static bool _enabled = true;
20+
private static IVsOutputWindowPane _debugPane;
21+
private static string _currentFile;
22+
private static FileStream _fileStream;
23+
private static StreamReader _fileStreamReader;
24+
25+
public void OnLoadComplete(DkmProcess process, DkmWorkList workList, DkmEventDescriptor eventDescriptor)
26+
{
27+
IVsOutputWindow outWindow = Package.GetGlobalService(typeof(SVsOutputWindow)) as IVsOutputWindow;
28+
Guid debugPaneGuid = VSConstants.GUID_OutWindowDebugPane;
29+
outWindow.GetPane(ref debugPaneGuid, out _debugPane);
30+
31+
var env = Environment.GetEnvironmentVariable("UNITY_MIXED_CALLSTACK");
32+
if (env == null || env == "0") // plugin not enabled
33+
{
34+
_debugPane.OutputString("Warning: To use the UnityMixedCallstack plugin please set the environment variable UNITY_MIXED_CALLSTACK=1 and relaunch Unity and Visual Studio\n");
35+
_debugPane.Activate();
36+
_enabled = false;
37+
}
38+
}
1539

1640
public DkmStackWalkFrame[] FilterNextFrame(DkmStackContext stackContext, DkmStackWalkFrame input)
1741
{
@@ -27,14 +51,15 @@ public DkmStackWalkFrame[] FilterNextFrame(DkmStackContext stackContext, DkmStac
2751
if (!stackContext.Thread.IsMainThread) // error case
2852
return new[] { input };
2953

54+
if (!_enabled) // environment variable not set
55+
return new[] { input };
3056

3157
return new[] { PmipStackFrame(stackContext, input) };
3258
}
3359

34-
public static DkmStackWalkFrame PmipStackFrame(DkmStackContext stackContext, DkmStackWalkFrame frame)
60+
private static DkmStackWalkFrame PmipStackFrame(DkmStackContext stackContext, DkmStackWalkFrame frame)
3561
{
36-
var fileName = Path.Combine(Path.GetTempPath(), "pmip." + frame.Process.LivePart.Id);
37-
RefreshStackData(fileName);
62+
RefreshStackData(frame.Process.LivePart.Id);
3863
string name = null;
3964
if (TryGetDescriptionForIp(frame.InstructionAddress.CPUInstructionPart.InstructionPointer, out name))
4065
return DkmStackWalkFrame.Create(
@@ -50,70 +75,105 @@ public static DkmStackWalkFrame PmipStackFrame(DkmStackContext stackContext, Dkm
5075
return frame;
5176
}
5277

53-
public static void RefreshStackData(string fileName)
78+
private static int GetFileNameSequenceNum(string path)
5479
{
55-
try
80+
var name = Path.GetFileNameWithoutExtension(path);
81+
const char delemiter = '_';
82+
var tokens = name.Split(delemiter);
83+
84+
if (tokens.Length != 3)
85+
return -1;
86+
87+
return int.Parse(tokens[2]);
88+
}
89+
90+
private static void DisposeStreams()
91+
{
92+
_fileStreamReader?.Dispose();
93+
_fileStream?.Dispose();
94+
_rangesSortedByIp.Clear();
95+
}
96+
97+
private static void RefreshStackData(int pid)
98+
{
99+
DirectoryInfo taskDirectory = new DirectoryInfo(Path.GetTempPath());
100+
FileInfo[] taskFiles = taskDirectory.GetFiles("pmip_" + pid + "_*.txt");
101+
102+
if (taskFiles.Length < 1)
103+
return;
104+
105+
Array.Sort(taskFiles, (a, b) => GetFileNameSequenceNum(a.Name).CompareTo(GetFileNameSequenceNum(b.Name)));
106+
var fileName = taskFiles[taskFiles.Length - 1].FullName;
107+
108+
if (_currentFile != fileName)
56109
{
57-
if (!File.Exists(fileName))
58-
return;
110+
DisposeStreams();
111+
try
112+
{
113+
_fileStream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite | FileShare.Delete);
114+
_fileStreamReader = new StreamReader(_fileStream);
115+
_currentFile = fileName;
116+
var versionStr = _fileStreamReader.ReadLine();
117+
const char delimiter = ':';
118+
var tokens = versionStr.Split(delimiter);
59119

60-
var fileInfo = new FileInfo(fileName);
61-
if (fileInfo.Length == _previousFileLength)
62-
return;
120+
if (tokens.Length != 2)
121+
throw new Exception("Failed reading input file " + fileName + ": Incorrect format");
122+
123+
var version = double.Parse(tokens[1]);
63124

64-
var list = new List<Range>(10000);
65-
using (var inStream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
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");
127+
}
128+
catch (Exception ex)
66129
{
67-
using (var file = new StreamReader(inStream))
68-
{
69-
string line;
70-
while ((line = file.ReadLine()) != null)
71-
{
72-
const char delemiter = ';';
73-
var tokens = line.Split(delemiter);
74-
75-
//should never happen, but lets be safe and not get array out of bounds if it does
76-
if (tokens.Length != 3)
77-
continue;
78-
79-
var startip = tokens[0];
80-
var endip = tokens[1];
81-
var description = tokens[2];
82-
83-
var startiplong = ulong.Parse(startip, NumberStyles.HexNumber);
84-
var endipint = ulong.Parse(endip, NumberStyles.HexNumber);
85-
86-
list.Add(new Range() { Name = description, Start = startiplong, End = endipint });
87-
}
88-
}
130+
_currentFile = null;
131+
_debugPane.OutputString("Unable to read dumped pmip file: " + ex.Message + "\n");
132+
DisposeStreams();
133+
return;
89134
}
135+
}
136+
137+
try
138+
{
139+
string line;
140+
while ((line = _fileStreamReader.ReadLine()) != null)
141+
{
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];
90152

91-
list.Sort((r1, r2) => r1.Start.CompareTo(r2.Start));
92-
_rangesSortedByIp = list.ToArray();
93-
_previousFileLength = fileInfo.Length;
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 });
156+
}
94157
}
95158
catch (Exception ex)
96159
{
97-
Console.WriteLine("Unable to read dumped pmip file: " + ex.Message);
160+
_debugPane.OutputString("Unable to read dumped pmip file: " + ex.Message + "\n");
98161
}
99162

163+
_rangesSortedByIp.Sort((r1, r2) => r1.Start.CompareTo(r2.Start));
100164
}
101165

102-
public static bool TryGetDescriptionForIp(ulong ip, out string name)
166+
private static bool TryGetDescriptionForIp(ulong ip, out string name)
103167
{
104168
name = string.Empty;
105169

106-
if (_rangesSortedByIp == null)
107-
return false;
108-
109170
var rangeToFindIp = new Range() { Start = ip };
110-
var index = Array.BinarySearch(_rangesSortedByIp, rangeToFindIp, _comparer);
171+
var index = _rangesSortedByIp.BinarySearch(rangeToFindIp, _comparer);
111172

112173
if (index < 0)
113174
return false;
114175

115176
name = _rangesSortedByIp[index].Name;
116-
117177
return true;
118178
}
119179
}

PmipMyCallStack.csproj

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<?xml version="1.0" encoding="utf-8"?>
1+
<?xml version="1.0" encoding="utf-8"?>
22
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
33
<PropertyGroup>
44
<MinimumVisualStudioVersion>14.0</MinimumVisualStudioVersion>
@@ -50,6 +50,8 @@
5050
<StartArguments>/rootsuffix Exp</StartArguments>
5151
</PropertyGroup>
5252
<ItemGroup>
53+
<Reference Include="Microsoft.VisualStudio.Shell.14.0, Version=14.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL" />
54+
<Reference Include="Microsoft.VisualStudio.Shell.Interop, Version=7.1.40304.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
5355
<Reference Include="System" />
5456
<Reference Include="System.Core" />
5557
<Reference Include="Microsoft.VisualStudio.Debugger.Engine">

PmipMyCallStack.vsdconfigxml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
<InterfaceGroup>
1212
<NoFilter/>
1313
<Interface Name="IDkmCallStackFilter"/>
14+
<Interface Name="IDkmLoadCompleteNotification"/>
1415
</InterfaceGroup>
1516
</Implements>
1617
</Class>

0 commit comments

Comments
 (0)