Skip to content

Commit

Permalink
Merge pull request #20 from Unity-Technologies/line-numbers
Browse files Browse the repository at this point in the history
Line number and multiple domain support
  • Loading branch information
UnityAlex committed Feb 28, 2023
2 parents abb5a72 + 1a3e340 commit da539d2
Show file tree
Hide file tree
Showing 14 changed files with 152,871 additions and 104 deletions.
13 changes: 13 additions & 0 deletions .idea/.idea.UnityMixedCallstack/.idea/.gitignore

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

50 changes: 50 additions & 0 deletions CallstackTestProj/CallstackTestProj.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net472</TargetFramework>

<IsPackable>false</IsPackable>
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
<PlatformTarget>x64</PlatformTarget>
<Platforms>AnyCPU;x64</Platforms>
<VSSdkPath Condition="'$(VisualStudioVersion.Contains(`17`))'">$(ProgramFiles)\Microsoft Visual Studio\2022\Professional\VSSDK\</VSSdkPath>
<VSSdkPath Condition="'$(VisualStudioVersion.Contains(`16`))'">$(MSBuildProgramFiles32)\Microsoft Visual Studio\2019\Professional\VSSDK\</VSSdkPath>
<ConcordSDKDir>$(VSSdkPath)VisualStudioIntegration\</ConcordSDKDir>
</PropertyGroup>

<ItemGroup>
<None Remove="pmip_32260_3.txt" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="Microsoft.TestPlatform" Version="17.5.0" />
<PackageReference Include="MSTest.TestAdapter" Version="3.0.2" />
<PackageReference Include="NUnit" Version="3.13.3" />
<PackageReference Include="NUnit3TestAdapter" Version="4.4.0" />
</ItemGroup>

<Import Project="$(ConcordSDKDir)Tools\bin\Microsoft.VSSDK.Debugger.VSDConfigTool.targets" />

<ItemGroup>
<ProjectReference Include="..\UnityMixedCallStack.csproj" />
</ItemGroup>

<ItemGroup>
<None Update="TestData\line-numbers\pmip_23672_1_0.txt">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="TestData\line-numbers\pmip_23672_4_1.txt">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="TestData\pmip_31964_3.txt">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="TestData\pmip_32260_3.txt">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="TestData\pmip_44920_4.txt">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>

</Project>
208 changes: 208 additions & 0 deletions CallstackTestProj/TestData/line-numbers/pmip_23672_1_0.txt

Large diffs are not rendered by default.

95,270 changes: 95,270 additions & 0 deletions CallstackTestProj/TestData/line-numbers/pmip_23672_4_1.txt

Large diffs are not rendered by default.

15,699 changes: 15,699 additions & 0 deletions CallstackTestProj/TestData/pmip_31964_3.txt

Large diffs are not rendered by default.

20,617 changes: 20,617 additions & 0 deletions CallstackTestProj/TestData/pmip_32260_3.txt

Large diffs are not rendered by default.

98 changes: 98 additions & 0 deletions CallstackTestProj/UnitTest1.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
using NUnit.Framework;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using UnityMixedCallStack;

namespace CallstackTestProj
{
[TestFixture]
public class Tests
{
private Tuple<string, string>[] m_legacyData =
{
Tuple.Create("000001C44A1C81D7", "[UnityEditor.CoreModule.dll] (wrapper managed-to-native) UnityEditor.EditorGUIUtility:RenderPlayModeViewCamerasInternal_Injected (UnityEngine.RenderTexture,int,UnityEngine.Vector2&,bool,bool)"),
Tuple.Create("000001C44A1C8083", "[UnityEditor.CoreModule.dll] UnityEditor.EditorGUIUtility:RenderPlayModeViewCamerasInternal (UnityEngine.RenderTexture,int,UnityEngine.Vector2,bool,bool)"),
Tuple.Create("000001C44A1C52EB", "[UnityEditor.CoreModule.dll] UnityEditor.PlayModeView:RenderView (UnityEngine.Vector2,bool)"),
Tuple.Create("000001C449F19A23", "[UnityEditor.CoreModule.dll] UnityEditor.GameView:OnGUI ()"),
Tuple.Create("000001C449F12BF8", "[UnityEditor.CoreModule.dll] UnityEditor.HostView:InvokeOnGUI (UnityEngine.Rect)"),
Tuple.Create("000001C449F12793", "[UnityEditor.CoreModule.dll] UnityEditor.DockArea:DrawView (UnityEngine.Rect)"),
Tuple.Create("000001C449EF1353", "[UnityEditor.CoreModule.dll] UnityEditor.DockArea:OldOnGUI ()"),
Tuple.Create("000001C449EBCCE9", "[UnityEngine.UIElementsModule.dll] UnityEngine.UIElements.IMGUIContainer:DoOnGUI (UnityEngine.Event,UnityEngine.Matrix4x4,UnityEngine.Rect,bool,UnityEngine.Rect,System.Action,bool)"),
Tuple.Create("000001C449EBAC13", "[UnityEngine.UIElementsModule.dll] UnityEngine.UIElements.IMGUIContainer:HandleIMGUIEvent (UnityEngine.Event,UnityEngine.Matrix4x4,UnityEngine.Rect,System.Action,bool)")
};

[Test]
public void LegacyDataTest()
{
Assert.IsTrue(PmipReader.ReadPmipFile(Path.Combine(TestContext.CurrentContext.TestDirectory, "TestData", "pmip_32260_3.txt")));
PmipReader.Sort();

foreach (Tuple<string, string> t in m_legacyData)
{
if (PmipReader.TryGetDescriptionForIp(ulong.Parse(t.Item1, NumberStyles.HexNumber), out string retVal))
{
Assert.AreEqual(t.Item2, retVal);
}
else
Assert.Fail();
}
PmipReader.DisposeStreams();
}

private Tuple<string, string>[] m_legacyModeData =
{
Tuple.Create("000001C4F5DC03FF", "[Assembly-CSharp.dll] SpinMe:FooBar ()"),
Tuple.Create("000001C4F5DC02D3", "[Assembly-CSharp.dll] SpinMe:Foo ()"),
Tuple.Create("000001C4F5DBF6F3", "[Assembly-CSharp.dll] SpinMe:Update ()"),
Tuple.Create("000001C3FF868578", "[mscorlib.dll] (wrapper runtime-invoke) object:runtime_invoke_void__this__ (object,intptr,intptr,intptr)")
};

[Test]
public void LegacyModeDataTest()
{
Assert.IsTrue(PmipReader.ReadPmipFile(Path.Combine(TestContext.CurrentContext.TestDirectory, "TestData", "pmip_31964_3.txt")));
PmipReader.Sort();

foreach (Tuple<string, string> t in m_legacyModeData)
{
if (PmipReader.TryGetDescriptionForIp(ulong.Parse(t.Item1, NumberStyles.HexNumber), out string retVal))
{
Assert.AreEqual(t.Item2, retVal);
}
else
Assert.Fail();
};
PmipReader.DisposeStreams();
}

private Tuple<string, string>[] m_lineNumbersData =
{
Tuple.Create("00000244C7A990BF", "[Assembly-CSharp.dll] SpinMe:FooBar ()"),
Tuple.Create("00000244C7A98F93", "[Assembly-CSharp.dll] SpinMe:Foo () : 32"),
Tuple.Create("00000244C7A98153", "[Assembly-CSharp.dll] SpinMe:Update () : 26"),
Tuple.Create("00000244EC9DF6B8", "[mscorlib.dll] (wrapper runtime-invoke) object:runtime_invoke_void__this__ (object,intptr,intptr,intptr)")
};

[Test]
public void LineNumbersDataTest()
{
Assert.IsTrue(PmipReader.ReadPmipFile(Path.Combine(TestContext.CurrentContext.TestDirectory, "TestData", "line-numbers", "pmip_23672_1_0.txt")));
Assert.IsTrue(PmipReader.ReadPmipFile(Path.Combine(TestContext.CurrentContext.TestDirectory, "TestData", "line-numbers", "pmip_23672_4_1.txt")));
PmipReader.Sort();

foreach (Tuple<string, string> t in m_lineNumbersData)
{
if (PmipReader.TryGetDescriptionForIp(ulong.Parse(t.Item1, NumberStyles.HexNumber), out string retVal))
{
Assert.AreEqual(t.Item2, retVal);
}
else
Assert.Fail($"Couldn't find address: {t.Item1}");
};

PmipReader.DisposeStreams();
}
}
}
6 changes: 6 additions & 0 deletions FuzzyRangeComparer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@ struct Range
public ulong Start;
public ulong End;
public string Name;
public string File;

public override string ToString()
{
return $"{File}::{Name} -- IP Range: {Start:X16} -> {End:X16}";
}
}
class FuzzyRangeComparer : IComparer<Range>
{
Expand Down
168 changes: 168 additions & 0 deletions PmipReader.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using UnityMixedCallstack;

namespace UnityMixedCallStack
{
public class PmipReader
{
private static List<Range> _rangesSortedByIp = new List<Range>();
private static List<Range> _legacyRanges = new List<Range>();
private static FuzzyRangeComparer _comparer = new FuzzyRangeComparer();

private struct PmipStreams
{
public FileStream fileStream;
public StreamReader fileStreamReader;

public void Dispose()
{
fileStreamReader.Dispose();
fileStreamReader = null;
fileStream.Dispose();
fileStream = null;
}
}

private static Dictionary<string, PmipStreams> _currentFiles = new Dictionary<string, PmipStreams>();

public static void Sort()
{
_legacyRanges.Sort((r1, r2) => r1.Start.CompareTo(r2.Start));
_rangesSortedByIp.Sort((r1, r2) => r1.Start.CompareTo(r2.Start));
}

public static void DisposeStreams()
{
foreach (PmipStreams streams in _currentFiles.Values)
streams.Dispose();
_currentFiles.Clear();

_rangesSortedByIp.Clear();
_legacyRanges.Clear();
}
public static bool ReadPmipFile(string filePath)
{
var _debugPane = UnityMixedCallstackFilter._debugPane;
#if DEBUG
_debugPane?.OutputString("MIXEDCALLSTACK :: Reading pmip file: " + filePath + "\n");
#endif
//DisposeStreams();

if (!_currentFiles.TryGetValue(filePath, out PmipStreams pmipStreams))
{
pmipStreams = new PmipStreams();
try
{
pmipStreams.fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite | FileShare.Delete);
pmipStreams.fileStreamReader = new StreamReader(pmipStreams.fileStream);
var versionStr = pmipStreams.fileStreamReader.ReadLine();
const char delimiter = ':';
var tokens = versionStr.Split(delimiter);

if (tokens.Length != 2)
throw new Exception("Failed reading input file " + filePath + ": Incorrect format");

if (!double.TryParse(tokens[1], NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture, out var version))
throw new Exception("Failed reading input file " + filePath + ": Incorrect version format");

if (version > 2.0)
throw new Exception("Failed reading input file " + filePath + ": A newer version of UnityMixedCallstacks plugin is required to read this file");
}
catch (Exception ex)
{
_debugPane?.OutputString("MIXEDCALLSTACK :: Unable to read dumped pmip file: " + ex.Message + "\n");
DisposeStreams();
return false;
}
_currentFiles.Add(filePath, pmipStreams);
}

try
{
string line;
int count = 0;
int legacyCount = 0;
while ((line = pmipStreams.fileStreamReader.ReadLine()) != null)
{
const char delemiter = ';';
var tokens = line.Split(delemiter);

//should never happen, but lets be safe and not get array out of bounds if it does
if (tokens.Length == 3 || tokens.Length == 4)
{
string startip = tokens[0];
string endip = tokens[1];
string description = tokens[2];
string file = "";
if (tokens.Length == 4)
file = tokens[3];

if (startip.StartsWith("---"))
{
startip = startip.Remove(0, 3);
}

var startiplong = ulong.Parse(startip, NumberStyles.HexNumber);
var endipint = ulong.Parse(endip, NumberStyles.HexNumber);
if (tokens[0].StartsWith("---"))
{
// legacy stored in new pmip file
_legacyRanges.Add(new Range() { Name = description, File = file, Start = startiplong, End = endipint });
legacyCount++;
}
else
{
Range range = new Range() { Name = description, File = file, Start = startiplong, End = endipint };
#if DEBUG
_debugPane?.OutputString($"MIXEDCALLSTACK :: adding range: {range}\n");
#endif
_rangesSortedByIp.Add(range);
count++;
}
}
}
#if DEBUG
if (count > 0 || legacyCount > 0)
_debugPane?.OutputString($"MIXEDCALLSTACK :: added {count} to map for a total of {_rangesSortedByIp.Count} entries! Added {legacyCount} to legacy map for a total of {_legacyRanges.Count} \n");
#endif
}
catch (Exception ex)
{
_debugPane?.OutputString("MIXEDCALLSTACK :: Unable to read dumped pmip file: " + ex.Message + "\n");
DisposeStreams();
return false;
}
return true;
}

public static bool TryGetDescriptionForIp(ulong ip, out string name)
{
name = string.Empty;

//_debugPane?.OutputString("MIXEDCALLSTACK :: Looking for ip: " + String.Format("{0:X}", ip) + "\n");
var rangeToFindIp = new Range() { Start = ip };
var index = _rangesSortedByIp.BinarySearch(rangeToFindIp, _comparer);

if (index >= 0)
{
//_debugPane?.OutputString("MIXEDCALLSTACK :: SUCCESS!!\n");
name = _rangesSortedByIp[index].Name;
return true;
}

index = _legacyRanges.BinarySearch(rangeToFindIp, _comparer);
if (index >= 0)
{
//_debugPane?.OutputString("MIXEDCALLSTACK :: LEGACY SUCCESS!! "+ String.Format("{0:X}", _legacyRanges[index].Start) +" -- "+ String.Format("{0:X}", _legacyRanges[index].End) + "\n");
name = _legacyRanges[index].Name;
return true;
}

return false;
}

}
}

0 comments on commit da539d2

Please sign in to comment.