11using System ;
22using System . Collections . Generic ;
3- using Microsoft . VisualStudio . Debugger ;
3+ using System . Globalization ;
4+ using System . IO ;
45using Microsoft . VisualStudio . Debugger . CallStack ;
56using Microsoft . VisualStudio . Debugger . ComponentInterfaces ;
6- using Microsoft . VisualStudio . Debugger . Evaluation ;
77
88namespace PmipMyCallStack
99{
1010 public class PmipCallStackFilter : IDkmCallStackFilter
1111 {
12- Guid ContextBeingWalked = new Guid ( ) ;
13- public DkmStackWalkFrame [ ] FilterNextFrame ( DkmStackContext stackContext , DkmStackWalkFrame input )
14- {
12+ private static Range [ ] IPs ;
13+ private static long previousFileLength ;
14+ static FuzzyRangeComparer comparer = new FuzzyRangeComparer ( ) ;
15+
16+ public DkmStackWalkFrame [ ] FilterNextFrame ( DkmStackContext stackContext , DkmStackWalkFrame input )
17+ {
1518 if ( input == null ) // after last frame
1619 return null ;
1720
18- if ( input . InstructionAddress == null ) // error case
19- return new [ ] { input } ;
21+ if ( input . InstructionAddress == null ) // error case
22+ return new [ ] { input } ;
23+
24+ if ( input . InstructionAddress . ModuleInstance != null && input . InstructionAddress . ModuleInstance . Module != null ) // code in existing module
25+ return new [ ] { input } ;
2026
21- if ( input . InstructionAddress . ModuleInstance != null && input . InstructionAddress . ModuleInstance . Module != null ) // code in existing module
22- return new [ ] { input } ;
27+ if ( ! stackContext . Thread . IsMainThread ) // error case
28+ return new [ ] { input } ;
2329
24- PmipFunctionDataItem pmipPrettyDump ;
25- if ( ! TryGetPmipPrettyDumpFunction ( stackContext , input , out pmipPrettyDump ) )
26- return new [ ] { input } ;
2730
28- if ( stackContext . UniqueId != ContextBeingWalked )
31+ return new [ ] { PmipStackFrame ( stackContext , input ) } ;
32+ }
33+ struct Range
34+ {
35+ public ulong Start ;
36+ public ulong End ;
37+ public string Name ;
38+ }
39+
40+ class FuzzyRangeComparer : IComparer < Range >
41+ {
42+ public int Compare ( Range x , Range y )
2943 {
30- ContextBeingWalked = stackContext . UniqueId ;
31- pmipPrettyDump . RefreshStackData ( input ) ;
32- }
44+ if ( x . Name == null && y . Start <= x . Start && y . End >= x . Start )
45+ {
46+ return 0 ;
47+ }
3348
34- return new [ ] { pmipPrettyDump . PmipStackFrame ( input ) } ;
35- }
49+ if ( y . Name == null && x . Start <= y . Start && x . End >= y . Start )
50+ {
51+ return 0 ;
52+ }
3653
37- private bool TryGetPmipPrettyDumpFunction ( DkmStackContext stackContext , DkmStackWalkFrame frame , out PmipFunctionDataItem pmipFunction )
54+ return x . Start . CompareTo ( y . Start ) ;
55+ }
56+ }
57+
58+ public static bool TryGetDescriptionForIP ( ulong ip , out string name )
3859 {
39- pmipFunction = stackContext . GetDataItem < PmipFunctionDataItem > ( ) ;
40- if ( pmipFunction != null )
41- return true ;
60+ name = string . Empty ;
61+ if ( IPs == null )
62+ return false ;
63+ int index = Array . BinarySearch ( IPs , new Range ( ) { Start = ip } , comparer ) ;
64+ int linearIndex = - 1 ;
65+ for ( var i = 0 ; i < IPs . Length ; i ++ )
66+ {
67+ var item = IPs [ i ] ;
68+ if ( ip > item . Start && ip < item . End )
69+ {
70+ linearIndex = i ;
71+ break ;
72+ }
73+ }
4274
43- var pmipPrettyDump = PmipUtils . FindInstructionAddress ( "mono_dump_pmip_pretty" , frame ) ;
4475
45- if ( pmipPrettyDump == null )
76+ if ( linearIndex == - 1 )
77+ {
78+ if ( index >= 0 )
79+ GC . KeepAlive ( name ) ;
4680 return false ;
81+ }
4782
48- pmipFunction = new PmipFunctionDataItem ( stackContext , frame , "0x" + pmipPrettyDump . CPUInstructionPart . InstructionPointer . ToString ( "X" ) ) ;
49- stackContext . SetDataItem ( DkmDataCreationDisposition . CreateAlways , pmipFunction ) ;
83+ if ( linearIndex != index )
84+ GC . KeepAlive ( name ) ;
5085
86+ name = IPs [ linearIndex ] . Name ;
5187 return true ;
5288 }
89+
90+ public static void RefreshStackData ( DkmStackWalkFrame frame )
91+ {
92+ try
93+ {
94+ var fileName = "D:\\ jon.txt" ;
95+ var fileInfo = new FileInfo ( fileName ) ;
96+ if ( fileInfo . Length == previousFileLength )
97+ return ;
98+
99+ var list = new List < Range > ( IPs ? . Length * 2 ?? 1000 ) ;
100+ using ( var inStream = new FileStream ( fileName , FileMode . Open , FileAccess . Read , FileShare . ReadWrite ) )
101+ using ( var file = new StreamReader ( inStream ) )
102+ {
103+ string line ;
104+ while ( ( line = file . ReadLine ( ) ) != null )
105+ {
106+ const char delemiter = ';' ;
107+ string [ ] tokens = line . Split ( delemiter ) ;
108+
109+ //should never happen, but lets be safe and not get array out of bounds if it does
110+ if ( tokens . Length != 3 )
111+ continue ;
112+
113+ string startip = tokens [ 0 ] ;
114+ string endip = tokens [ 1 ] ;
115+ string description = tokens [ 2 ] ;
116+
117+ var startipint = ulong . Parse ( startip , NumberStyles . HexNumber ) ;
118+ var endipint = ulong . Parse ( endip , NumberStyles . HexNumber ) ;
119+
120+ list . Add ( new Range ( ) { Name = description , Start = startipint , End = endipint } ) ;
121+ }
122+ }
123+
124+ list . Sort ( ( r1 , r2 ) => r1 . Start . CompareTo ( r2 . Start ) ) ;
125+ IPs = list . ToArray ( ) ;
126+ previousFileLength = fileInfo . Length ;
127+ }
128+ catch ( Exception ex )
129+ {
130+ Console . WriteLine ( "Unable to read dumped pmip file: " + ex . Message ) ;
131+ }
132+
133+ }
134+
135+ public static DkmStackWalkFrame PmipStackFrame ( DkmStackContext stackContext , DkmStackWalkFrame frame )
136+ {
137+ RefreshStackData ( frame ) ;
138+ string name = null ;
139+ if ( TryGetDescriptionForIP ( frame . InstructionAddress . CPUInstructionPart . InstructionPointer , out name ) )
140+ return DkmStackWalkFrame . Create (
141+ stackContext . Thread ,
142+ frame . InstructionAddress ,
143+ frame . FrameBase ,
144+ frame . FrameSize ,
145+ frame . Flags ,
146+ name ,
147+ frame . Registers ,
148+ frame . Annotations ) ;
149+
150+ return frame ;
151+ }
53152 }
54153}
0 commit comments