Skip to content

Commit 0c0942f

Browse files
committed
Initial commit
0 parents  commit 0c0942f

10 files changed

+336
-0
lines changed

.gitattributes

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
* text=auto
2+
3+
.md text
4+
.cs text
5+
6+
.sln text=crlf
7+
.*proj text=crlf
8+
.settings text=crlf

.gitignore

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
bin
2+
obj
3+
*.suo
4+
*.user
5+
*.pidb
6+
*.userprefs
7+
*.xml
8+
*.nupkg
9+
.vs
10+
**/test-results/*
11+
*Resharper*
12+
Mono.Cecil.sln.ide*

PmipCallStackFilter.cs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
using Microsoft.VisualStudio.Debugger.CallStack;
2+
using Microsoft.VisualStudio.Debugger.ComponentInterfaces;
3+
4+
namespace PmipMyCallStack
5+
{
6+
public class PmipCallStackFilter : IDkmCallStackFilter
7+
{
8+
public DkmStackWalkFrame[] FilterNextFrame(DkmStackContext stackContext, DkmStackWalkFrame input)
9+
{
10+
if (input == null) // after last frame
11+
return null;
12+
13+
if (input.InstructionAddress == null) // error case
14+
return new[] { input };
15+
16+
if (input.InstructionAddress.ModuleInstance != null) // code in existing module
17+
return new[] { input };
18+
19+
var runner = new PmipRunner(stackContext, input);
20+
return new[] { runner.PmipStackFrame() };
21+
}
22+
}
23+
}

PmipFunctionDataItem.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
using Microsoft.VisualStudio.Debugger;
2+
3+
namespace PmipMyCallStack
4+
{
5+
class PmipFunctionDataItem : DkmDataItem
6+
{
7+
public string PmipFunction { get; set; }
8+
}
9+
}

PmipMyCallStack.csproj

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3+
<PropertyGroup>
4+
<MinimumVisualStudioVersion>14.0</MinimumVisualStudioVersion>
5+
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">11.0</VisualStudioVersion>
6+
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
7+
</PropertyGroup>
8+
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
9+
<PropertyGroup>
10+
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
11+
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
12+
<SchemaVersion>2.0</SchemaVersion>
13+
<ProjectGuid>{9A899D87-5BFA-4886-B701-68C515F1371C}</ProjectGuid>
14+
<OutputType>Library</OutputType>
15+
<AppDesignerFolder>Properties</AppDesignerFolder>
16+
<RootNamespace>PmipMyCallStack</RootNamespace>
17+
<AssemblyName>PmipMyCallStack</AssemblyName>
18+
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
19+
<FileAlignment>512</FileAlignment>
20+
<GeneratePkgDefFile>false</GeneratePkgDefFile>
21+
<!--Root directory to Concord SDK install; includes the trailing backslash '\'.-->
22+
<ConcordSDKDir>$(VSSDK140Install)VisualStudioIntegration\</ConcordSDKDir>
23+
</PropertyGroup>
24+
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
25+
<DebugSymbols>true</DebugSymbols>
26+
<DebugType>full</DebugType>
27+
<Optimize>false</Optimize>
28+
<OutputPath>bin\Debug\</OutputPath>
29+
<DefineConstants>DEBUG;TRACE</DefineConstants>
30+
<ErrorReport>prompt</ErrorReport>
31+
<WarningLevel>4</WarningLevel>
32+
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
33+
<Prefer32Bit>false</Prefer32Bit>
34+
</PropertyGroup>
35+
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
36+
<DebugType>pdbonly</DebugType>
37+
<Optimize>true</Optimize>
38+
<OutputPath>bin\Release\</OutputPath>
39+
<DefineConstants>TRACE</DefineConstants>
40+
<ErrorReport>prompt</ErrorReport>
41+
<WarningLevel>4</WarningLevel>
42+
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
43+
<Prefer32Bit>false</Prefer32Bit>
44+
</PropertyGroup>
45+
<PropertyGroup>
46+
<StartAction>Program</StartAction>
47+
<StartProgram>$(DevEnvDir)devenv.exe</StartProgram>
48+
<StartWorkingDirectory>$(DevEnvDir)</StartWorkingDirectory>
49+
<StartArguments>/rootsuffix Exp</StartArguments>
50+
</PropertyGroup>
51+
<ItemGroup>
52+
<Reference Include="System" />
53+
<Reference Include="System.Core" />
54+
<Reference Include="System.Xml" />
55+
<Reference Include="Microsoft.VisualStudio.Debugger.Engine">
56+
<HintPath>$(ConcordSDKDir)Reference Assemblies\Microsoft.VisualStudio.Debugger.Engine.dll</HintPath>
57+
<Private>False</Private>
58+
</Reference>
59+
</ItemGroup>
60+
<ItemGroup>
61+
<Compile Include="PmipCallStackFilter.cs" />
62+
<Compile Include="PmipFunctionDataItem.cs" />
63+
<Compile Include="PmipRunner.cs" />
64+
<Compile Include="Properties\AssemblyInfo.cs" />
65+
</ItemGroup>
66+
<ItemGroup>
67+
<VsdConfigXmlFiles Include="PmipMyCallStack.vsdconfigxml"/>
68+
</ItemGroup>
69+
<ItemGroup>
70+
<None Include="source.extension.vsixmanifest">
71+
<SubType>Designer</SubType>
72+
</None>
73+
</ItemGroup>
74+
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
75+
<Import Project="$(ConcordSDKDir)Tools\bin\Microsoft.VSDebugger.targets" />
76+
<Import Project="$(VSToolsPath)\VSSDK\Microsoft.VsSDK.targets" Condition="'$(VSToolsPath)' != ''" />
77+
<PropertyGroup>
78+
<VsdConfigOutput>$(OutputPath)\PmipMyCallStack.vsdconfig</VsdConfigOutput>
79+
</PropertyGroup>
80+
<Target Name="IncludeVsdConfig" BeforeTargets="AssignTargetPaths;GetVSIXSourceItems" Condition="$(VSTarget) != '10.0'">
81+
<ItemGroup>
82+
<Content Include="$(VsdConfigOutput)">
83+
<IncludeInVSIX>true</IncludeInVSIX>
84+
<VSIXSubPath>.</VSIXSubPath>
85+
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
86+
<Link>$([System.IO.Path]::GetFileName($(VsdConfigOutput)))</Link>
87+
</Content>
88+
</ItemGroup>
89+
<Message Text="VsdConfigOutput: $(VsdConfigOutput)" Importance="high" />
90+
</Target>
91+
</Project>

PmipMyCallStack.sln

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
2+
Microsoft Visual Studio Solution File, Format Version 12.00
3+
# Visual Studio 14
4+
VisualStudioVersion = 14.0.23107.0
5+
MinimumVisualStudioVersion = 10.0.40219.1
6+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PmipMyCallStack", "PmipMyCallStack.csproj", "{9A899D87-5BFA-4886-B701-68C515F1371C}"
7+
EndProject
8+
Global
9+
GlobalSection(SolutionConfigurationPlatforms) = preSolution
10+
Debug|Any CPU = Debug|Any CPU
11+
Release|Any CPU = Release|Any CPU
12+
EndGlobalSection
13+
GlobalSection(ProjectConfigurationPlatforms) = postSolution
14+
{9A899D87-5BFA-4886-B701-68C515F1371C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
15+
{9A899D87-5BFA-4886-B701-68C515F1371C}.Debug|Any CPU.Build.0 = Debug|Any CPU
16+
{9A899D87-5BFA-4886-B701-68C515F1371C}.Release|Any CPU.ActiveCfg = Release|Any CPU
17+
{9A899D87-5BFA-4886-B701-68C515F1371C}.Release|Any CPU.Build.0 = Release|Any CPU
18+
EndGlobalSection
19+
GlobalSection(SolutionProperties) = preSolution
20+
HideSolutionNode = FALSE
21+
EndGlobalSection
22+
EndGlobal

PmipMyCallStack.vsdconfigxml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<Configuration xmlns="http://schemas.microsoft.com/vstudio/vsdconfig/2008">
3+
<ManagedComponent
4+
ComponentId="408CB9BB-93B1-44A7-AA4E-88956AB421DB"
5+
ComponentLevel="9995000"
6+
AssemblyName="PmipMyCallStack">
7+
8+
<Class Name="PmipMyCallStack.PmipCallStackFilter">
9+
10+
<Implements>
11+
<InterfaceGroup>
12+
<NoFilter/>
13+
<Interface Name="IDkmCallStackFilter"/>
14+
</InterfaceGroup>
15+
</Implements>
16+
</Class>
17+
18+
</ManagedComponent>
19+
</Configuration>

PmipRunner.cs

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
using System;
2+
using Microsoft.VisualStudio.Debugger;
3+
using Microsoft.VisualStudio.Debugger.CallStack;
4+
using Microsoft.VisualStudio.Debugger.Evaluation;
5+
6+
namespace PmipMyCallStack
7+
{
8+
class PmipRunner
9+
{
10+
private static readonly DkmLanguage CppLanguage = DkmLanguage.Create("C++", new DkmCompilerId(DkmVendorId.Microsoft, DkmLanguageId.Cpp));
11+
private static readonly string[] Modules = { "mono", "monosgen-2.0" };
12+
13+
private readonly DkmStackContext _stackContext;
14+
private readonly DkmStackWalkFrame _frame;
15+
private readonly DkmInspectionContext _inspectionContext;
16+
17+
public PmipRunner(DkmStackContext stackContext, DkmStackWalkFrame frame)
18+
{
19+
_stackContext = stackContext;
20+
_frame = frame;
21+
_inspectionContext = CreateInspectionContext(stackContext, frame);
22+
}
23+
24+
public DkmStackWalkFrame PmipStackFrame()
25+
{
26+
PmipFunctionDataItem pmipFunction;
27+
if (!TryGetPmipFunction(out pmipFunction))
28+
return _frame;
29+
30+
var ip = $"0x{_frame.InstructionAddress.CPUInstructionPart.InstructionPointer:X}";
31+
var call = $"((char*(*)(void*)){pmipFunction.PmipFunction})((void*){ip})";
32+
33+
var result = "";
34+
var isNull = true;
35+
36+
var eval = EvaluateExpression(call, r =>
37+
{
38+
isNull = r.Address.InstructionAddress.CPUInstructionPart.InstructionPointer == 0;
39+
result = r.Value;
40+
});
41+
42+
if (!eval || isNull)
43+
return _frame;
44+
45+
return DkmStackWalkFrame.Create(
46+
_stackContext.Thread,
47+
_frame.InstructionAddress,
48+
_frame.FrameBase,
49+
_frame.FrameSize,
50+
_frame.Flags,
51+
result,
52+
_frame.Registers,
53+
_frame.Annotations);
54+
}
55+
56+
private bool TryGetPmipFunction(out PmipFunctionDataItem pmipFunction)
57+
{
58+
pmipFunction = _stackContext.GetDataItem<PmipFunctionDataItem>();
59+
if (pmipFunction != null)
60+
return true;
61+
62+
foreach (var module in Modules)
63+
{
64+
var definition = $"{{,,{module}}}mono_pmip";
65+
66+
PmipFunctionDataItem item = null;
67+
if (!EvaluateExpression(definition, r => item = new PmipFunctionDataItem {PmipFunction = definition}))
68+
continue;
69+
70+
pmipFunction = item;
71+
_stackContext.SetDataItem(DkmDataCreationDisposition.CreateAlways, item);
72+
return true;
73+
}
74+
75+
return false;
76+
}
77+
78+
private static DkmLanguageExpression CppExpression(string expression)
79+
{
80+
return DkmLanguageExpression.Create(CppLanguage, DkmEvaluationFlags.None, expression, null);
81+
}
82+
83+
private static DkmInspectionContext CreateInspectionContext(DkmStackContext stackContext, DkmStackWalkFrame frame)
84+
{
85+
return DkmInspectionContext.Create(
86+
stackContext.InspectionSession,
87+
frame.RuntimeInstance,
88+
frame.Thread,
89+
1000,
90+
DkmEvaluationFlags.None,
91+
DkmFuncEvalFlags.None,
92+
10,
93+
CppLanguage,
94+
null);
95+
}
96+
97+
private bool EvaluateExpression(string expression, Action<DkmSuccessEvaluationResult> onSuccess)
98+
{
99+
var workList = DkmWorkList.Create(null);
100+
var success = false;
101+
102+
_inspectionContext.EvaluateExpression(workList, CppExpression(expression), _frame, res =>
103+
{
104+
var resObj = res.ResultObject;
105+
var result = resObj as DkmSuccessEvaluationResult;
106+
if (result != null)
107+
{
108+
success = true;
109+
onSuccess(result);
110+
}
111+
112+
resObj.Close();
113+
});
114+
115+
workList.Execute();
116+
return success;
117+
}
118+
}
119+
}

Properties/AssemblyInfo.cs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
using System.Reflection;
2+
using System.Runtime.InteropServices;
3+
4+
[assembly: AssemblyTitle("PmipMyCallStack")]
5+
[assembly: AssemblyDescription("")]
6+
[assembly: AssemblyConfiguration("")]
7+
[assembly: AssemblyCompany("")]
8+
[assembly: AssemblyProduct("PmipMyCallStack")]
9+
[assembly: AssemblyCopyright("Copyright (C) 2015 Jb Evain")]
10+
[assembly: AssemblyTrademark("")]
11+
[assembly: AssemblyCulture("")]
12+
13+
[assembly: ComVisible(false)]
14+
15+
[assembly: AssemblyVersion("1.0.0.0")]
16+
[assembly: AssemblyFileVersion("1.0.0.0")]

source.extension.vsixmanifest

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<PackageManifest Version="2.0.0" xmlns="http://schemas.microsoft.com/developer/vsx-schema/2011" xmlns:d="http://schemas.microsoft.com/developer/vsx-schema-design/2011">
3+
<Metadata>
4+
<Identity Id="PmipMyCallStack.jbevain.15921810-5bc8-451e-acc0-e45161908103" Version="1.0" Language="en-US" Publisher="Jb Evain" />
5+
<DisplayName>Pmip My Call Stack</DisplayName>
6+
<Description xml:space="preserve">Visual Studio native debugger extension to help debug native applications using Mono.</Description>
7+
</Metadata>
8+
<Installation>
9+
<InstallationTarget Id="Microsoft.VisualStudio.Community" Version="[14.0]" />
10+
</Installation>
11+
<Dependencies>
12+
<Dependency Id="Microsoft.Framework.NDP" DisplayName="Microsoft .NET Framework" d:Source="Manual" Version="4.5" />
13+
</Dependencies>
14+
<Assets>
15+
<Asset Type="DebuggerEngineExtension" Path="PmipMyCallStack.vsdconfig"/>
16+
</Assets>
17+
</PackageManifest>

0 commit comments

Comments
 (0)