Skip to content

Commit 4ca653c

Browse files
author
Michael DeRoy
committed
[Not working] Read a file to get callstack info
1 parent 85e3634 commit 4ca653c

5 files changed

+254
-142
lines changed

PmipCallStackFilter.cs

Lines changed: 37 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,54 @@
1-
using Microsoft.VisualStudio.Debugger.CallStack;
1+
using System;
2+
using System.Collections.Generic;
3+
using Microsoft.VisualStudio.Debugger;
4+
using Microsoft.VisualStudio.Debugger.CallStack;
25
using Microsoft.VisualStudio.Debugger.ComponentInterfaces;
6+
using Microsoft.VisualStudio.Debugger.Evaluation;
37

48
namespace PmipMyCallStack
59
{
610
public class PmipCallStackFilter : IDkmCallStackFilter
711
{
8-
12+
Guid ContextBeingWalked = new Guid();
913
public DkmStackWalkFrame[] FilterNextFrame(DkmStackContext stackContext, DkmStackWalkFrame input)
1014
{
11-
if (input == null) // after last frame
12-
return null;
15+
if (input == null) // after last frame
16+
return null;
1317

1418
if (input.InstructionAddress == null) // error case
1519
return new[] { input };
1620

1721
if (input.InstructionAddress.ModuleInstance != null && input.InstructionAddress.ModuleInstance.Module != null) // code in existing module
1822
return new[] { input };
1923

20-
var runner = new PmipRunner(stackContext, input);
21-
return new[] { runner.PmipStackFrame() };
24+
PmipFunctionDataItem pmipPrettyDump;
25+
if (!TryGetPmipPrettyDumpFunction(stackContext, input, out pmipPrettyDump))
26+
return new[] { input };
27+
28+
if (stackContext.UniqueId != ContextBeingWalked)
29+
{
30+
ContextBeingWalked = stackContext.UniqueId;
31+
pmipPrettyDump.RefreshStackData(input);
32+
}
33+
34+
return new[] { pmipPrettyDump.PmipStackFrame(input) };
2235
}
23-
}
36+
37+
private bool TryGetPmipPrettyDumpFunction(DkmStackContext stackContext, DkmStackWalkFrame frame, out PmipFunctionDataItem pmipFunction)
38+
{
39+
pmipFunction = stackContext.GetDataItem<PmipFunctionDataItem>();
40+
if (pmipFunction != null)
41+
return true;
42+
43+
var pmipPrettyDump = PmipUtils.FindInstructionAddress("mono_dump_pmip_pretty", frame);
44+
45+
if (pmipPrettyDump == null)
46+
return false;
47+
48+
pmipFunction = new PmipFunctionDataItem(stackContext, frame, "0x" + pmipPrettyDump.CPUInstructionPart.InstructionPointer.ToString("X"));
49+
stackContext.SetDataItem(DkmDataCreationDisposition.CreateAlways, pmipFunction);
50+
51+
return true;
52+
}
53+
}
2454
}

PmipFunctionDataItem.cs

Lines changed: 105 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,112 @@
1+
using System;
2+
using System.Collections;
3+
using System.Collections.Generic;
4+
using System.Diagnostics;
5+
using System.Globalization;
6+
using System.IO;
7+
using System.Linq.Expressions;
8+
using System.Runtime.CompilerServices;
9+
using System.Runtime.InteropServices;
10+
using System.Security.Cryptography;
111
using Microsoft.VisualStudio.Debugger;
12+
using Microsoft.VisualStudio.Debugger.CallStack;
13+
using Microsoft.VisualStudio.Debugger.Evaluation;
214

315
namespace PmipMyCallStack
416
{
517
class PmipFunctionDataItem : DkmDataItem
618
{
7-
public string PmipFunction { get; set; }
8-
}
19+
private string m_pmipFunctionString;
20+
private readonly DkmStackContext m_stackContext;
21+
private SortedList<int, string> MapIPsToDescriptions = new SortedList<int, string>(5000);
22+
23+
public PmipFunctionDataItem(DkmStackContext ctx, DkmStackWalkFrame mFrame, string mPmipFunctionString)
24+
{
25+
m_stackContext = ctx;
26+
m_pmipFunctionString = mPmipFunctionString;
27+
}
28+
29+
public string GetDescriptionForIP(string ip)
30+
{
31+
int ipKey = int.Parse(ip, NumberStyles.HexNumber);
32+
IList<int> ipKeys = MapIPsToDescriptions.Keys;
33+
34+
int left = 0;
35+
int right = ipKeys.Count;
36+
while (right > left)
37+
{
38+
int pivot = (left + right) / 2;
39+
if (ipKeys[pivot] <= ipKey)
40+
right = pivot;
41+
else
42+
left = pivot + 1;
43+
}
44+
int keyOfFirstIdxGreaterThanOrEqualToIp = ipKeys[right];
45+
return MapIPsToDescriptions[keyOfFirstIdxGreaterThanOrEqualToIp];
46+
}
47+
48+
public void RefreshStackData(DkmStackWalkFrame frame)
49+
{
50+
var call = $"((char*(*)()){m_pmipFunctionString})()";
51+
var stackTraceFile = "";
52+
var eval = PmipUtils.EvaluateExpression(PmipUtils.CreateInspectionContext(m_stackContext, frame), frame, call, r =>
53+
{
54+
stackTraceFile = r.Value;
55+
});
56+
57+
try
58+
{
59+
using (StreamReader file = new StreamReader(stackTraceFile))
60+
{
61+
HashSet<string> visitedFunctions = new HashSet<string>();
62+
string line;
63+
while ((line = file.ReadLine()) != null)
64+
{
65+
const char delemiter = ';';
66+
string[] tokens = line.Split(delemiter);
67+
68+
//should never happen, but lets be safe and not get array out of bounds if it does
69+
if (tokens.Length != 3)
70+
continue;
71+
72+
string startip = "0x" + tokens[0];
73+
string endip = "0x" + tokens[1];
74+
string description = tokens[2];
75+
76+
//if we've already indexed this description, continue
77+
if (visitedFunctions.Contains(description))
78+
continue;
79+
visitedFunctions.Add(description);
80+
81+
int startipint = int.Parse(startip, NumberStyles.HexNumber);
82+
int endipint = int.Parse(startip, NumberStyles.HexNumber);
83+
84+
MapIPsToDescriptions.Add(startipint, description);
85+
MapIPsToDescriptions.Add(endipint, description);
86+
}
87+
}
88+
}
89+
catch (Exception ex)
90+
{
91+
Console.WriteLine("Unable to read dumped pmip file: " + ex.Message);
92+
}
93+
94+
}
95+
96+
public DkmStackWalkFrame PmipStackFrame(DkmStackWalkFrame frame)
97+
{
98+
var ip = $"0x{frame.InstructionAddress.CPUInstructionPart.InstructionPointer:X}";
99+
100+
return DkmStackWalkFrame.Create(
101+
m_stackContext.Thread,
102+
frame.InstructionAddress,
103+
frame.FrameBase,
104+
frame.FrameSize,
105+
frame.Flags,
106+
GetDescriptionForIP(ip),
107+
frame.Registers,
108+
frame.Annotations);
109+
}
110+
111+
}
9112
}

PmipMyCallStack.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@
6161
<Compile Include="PmipCallStackFilter.cs" />
6262
<Compile Include="PmipFunctionDataItem.cs" />
6363
<Compile Include="PmipRunner.cs" />
64+
<Compile Include="PmipUtils.cs" />
6465
<Compile Include="Properties\AssemblyInfo.cs" />
6566
</ItemGroup>
6667
<ItemGroup>

PmipRunner.cs

Lines changed: 46 additions & 133 deletions
Original file line numberDiff line numberDiff line change
@@ -6,138 +6,51 @@
66

77
namespace PmipMyCallStack
88
{
9-
class PmipRunner
10-
{
11-
private static readonly DkmLanguage CppLanguage = DkmLanguage.Create("C++", new DkmCompilerId(DkmVendorId.Microsoft, DkmLanguageId.Cpp));
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 = "<ERROR>";
34-
var isNull = true;
35-
36-
var eval = EvaluateExpression(call, r =>
37-
{
38-
isNull = r.Address.InstructionAddress.CPUInstructionPart.InstructionPointer == 0;
39-
if (r.Value != null)
40-
{
41-
try
42-
{
43-
int afterBeginQuote = r.Value.IndexOf("\"", StringComparison.Ordinal) + 1;
44-
int beforeEndQuote = r.Value.Length - 1;
45-
result = r.Value.Substring(afterBeginQuote, beforeEndQuote - afterBeginQuote);
46-
}
47-
catch (Exception)
48-
{
49-
}
50-
51-
}
52-
53-
});
54-
55-
if (!eval || isNull)
56-
return _frame;
9+
//class PmipRunner
10+
//{
11+
// private readonly DkmStackContext _stackContext;
12+
// private readonly DkmStackWalkFrame _frame;
13+
// private readonly DkmInspectionContext _inspectionContext;
14+
15+
// public PmipRunner(DkmStackContext stackContext, DkmStackWalkFrame frame)
16+
// {
17+
// _stackContext = stackContext;
18+
// _frame = frame;
19+
// _inspectionContext = PmipUtils.CreateInspectionContext(stackContext, frame);
20+
// }
21+
22+
// public DkmStackWalkFrame PmipStackFrame()
23+
// {
24+
// PmipFunctionDataItem pmipFunction;
25+
// if (!TryGetPmipFunction(out pmipFunction))
26+
// return _frame;
27+
28+
// var ip = $"0x{_frame.InstructionAddress.CPUInstructionPart.InstructionPointer:X}";
29+
// var call = $"((char*(*)(void*)){pmipFunction.PmipFunction})((void*){ip})";
30+
31+
// var result = "<ERROR>";
32+
// var isNull = true;
33+
34+
// var eval = PmipUtils.EvaluateExpression(_inspectionContext, _frame ,call, r =>
35+
// {
36+
// isNull = r.Address.InstructionAddress.CPUInstructionPart.InstructionPointer == 0;
37+
// result = r.Value;
38+
// });
39+
40+
// if (!eval || isNull)
41+
// return _frame;
5742

58-
return DkmStackWalkFrame.Create(
59-
_stackContext.Thread,
60-
_frame.InstructionAddress,
61-
_frame.FrameBase,
62-
_frame.FrameSize,
63-
_frame.Flags,
64-
result,
65-
_frame.Registers,
66-
_frame.Annotations);
67-
}
68-
69-
private DkmNativeInstructionAddress FindInstructionAddress(string functionName)
70-
{
71-
foreach (var module in this._frame.RuntimeInstance.GetModuleInstances())
72-
{
73-
var address = (module as DkmNativeModuleInstance)?.FindExportName(functionName,
74-
IgnoreDataExports: true);
75-
if(address != null)
76-
return address;
77-
}
78-
return null;
79-
}
80-
81-
private bool TryGetPmipFunction(out PmipFunctionDataItem pmipFunction)
82-
{
83-
pmipFunction = _stackContext.GetDataItem<PmipFunctionDataItem>();
84-
if (pmipFunction != null)
85-
return true;
86-
87-
var pmipOrig = FindInstructionAddress("mono_pmip");
88-
var pmipPretty = FindInstructionAddress("mono_pmip_pretty");
89-
90-
var pmipFnToUse = pmipPretty ?? pmipOrig;
91-
92-
if (pmipFnToUse == null)
93-
return false;
94-
95-
var item = new PmipFunctionDataItem { PmipFunction = "0x" + pmipFnToUse.CPUInstructionPart.InstructionPointer.ToString("X") };
96-
pmipFunction = item;
97-
_stackContext.SetDataItem(DkmDataCreationDisposition.CreateAlways, item);
98-
99-
return true;
100-
}
101-
102-
private static DkmLanguageExpression CppExpression(string expression)
103-
{
104-
return DkmLanguageExpression.Create(CppLanguage, DkmEvaluationFlags.None, expression, null);
105-
}
106-
107-
private static DkmInspectionContext CreateInspectionContext(DkmStackContext stackContext, DkmStackWalkFrame frame)
108-
{
109-
return DkmInspectionContext.Create(
110-
stackContext.InspectionSession,
111-
frame.RuntimeInstance,
112-
frame.Thread,
113-
1000,
114-
DkmEvaluationFlags.None,
115-
DkmFuncEvalFlags.None,
116-
10,
117-
CppLanguage,
118-
null);
119-
}
120-
121-
private bool EvaluateExpression(string expression, Action<DkmSuccessEvaluationResult> onSuccess)
122-
{
123-
var workList = DkmWorkList.Create(null);
124-
var success = false;
125-
126-
_inspectionContext.EvaluateExpression(workList, CppExpression(expression), _frame, res =>
127-
{
128-
var resObj = res.ResultObject;
129-
var result = resObj as DkmSuccessEvaluationResult;
130-
if (result != null)
131-
{
132-
success = true;
133-
onSuccess(result);
134-
}
135-
136-
resObj.Close();
137-
});
138-
139-
workList.Execute();
140-
return success;
141-
}
142-
}
43+
// return DkmStackWalkFrame.Create(
44+
// _stackContext.Thread,
45+
// _frame.InstructionAddress,
46+
// _frame.FrameBase,
47+
// _frame.FrameSize,
48+
// _frame.Flags,
49+
// result,
50+
// _frame.Registers,
51+
// _frame.Annotations);
52+
// }
53+
54+
55+
//}
14356
}

0 commit comments

Comments
 (0)