13
13
using ModuleSaw ;
14
14
using System . Threading . Tasks ;
15
15
using System . Threading ;
16
+ using System . Net ;
16
17
17
18
namespace WasmStrip {
18
19
class ReferenceComparer < T > : IEqualityComparer < T > {
@@ -51,6 +52,8 @@ class Config {
51
52
public bool DumpFunctions = true , DisassembleFunctions = true ;
52
53
public string DumpFunctionsPath ;
53
54
public List < Regex > DumpFunctionRegexes = new List < Regex > ( ) ;
55
+
56
+ public string WhatIs ;
54
57
}
55
58
56
59
class NamespaceInfo {
@@ -168,6 +171,29 @@ public static int Main (string[] _args) {
168
171
if ( config . DumpSectionsPath != null )
169
172
DumpSections ( config , wasmBytes , wasmReader ) ;
170
173
174
+ if ( ! string . IsNullOrEmpty ( config . WhatIs ) ) {
175
+ int index = 0 ;
176
+ bool isIndex = false ;
177
+ if ( config . WhatIs . StartsWith ( "0x" ) )
178
+ isIndex = int . TryParse ( config . WhatIs . Substring ( 2 ) , System . Globalization . NumberStyles . HexNumber , null , out index ) ;
179
+ else
180
+ isIndex = int . TryParse ( config . WhatIs , out index ) ;
181
+
182
+ if ( isIndex ) {
183
+ var biasedIndex = index - wasmReader . FunctionIndexOffset ;
184
+ if ( functions . TryGetValue ( ( uint ) biasedIndex , out var fi ) )
185
+ Console . WriteLine ( $ "table entry { index } = #{ fi . Index } { fi . Name } ") ;
186
+ else
187
+ Console . WriteLine ( $ "No table entry for { index } ") ;
188
+ } else {
189
+ var fi = functions . Values . FirstOrDefault ( f => f . Name . Equals ( config . WhatIs , StringComparison . OrdinalIgnoreCase ) ) ;
190
+ if ( fi != null )
191
+ Console . WriteLine ( $ "#{ fi . Index } { fi . Name } ") ;
192
+ else
193
+ Console . WriteLine ( $ "No functions named { config . WhatIs } ") ;
194
+ }
195
+ }
196
+
171
197
ClearLine ( "Analyzing module." ) ;
172
198
173
199
AnalysisData data = null ;
@@ -255,6 +281,7 @@ public static int Main (string[] _args) {
255
281
Console . Error . WriteLine ( " --strip-list=regexes.txt" ) ;
256
282
Console . Error . WriteLine ( " --retain=regex [...]" ) ;
257
283
Console . Error . WriteLine ( " --retain-list=regexes.txt" ) ;
284
+ Console . Error . WriteLine ( " --whatis=(func-index)|0x(hex-func-index)|(func-name)" ) ;
258
285
}
259
286
260
287
if ( Debugger . IsAttached ) {
@@ -992,9 +1019,9 @@ private Dictionary<string, object> ComputeRawData (Config config, byte[] wasmByt
992
1019
{ "SetLocalRuns" , listener . SetLocalRuns } ,
993
1020
{ "DupCandidates" , listener . DupCandidates } ,
994
1021
{ "MaxRunSize" , listener . MaxRunSize } ,
995
- { "AverageRunLength" , listener . AverageRunLengthSum / ( double ) listener . RunCount } ,
1022
+ { "AverageRunLength" , listener . AverageRunLengthSum / ( double ) Math . Max ( listener . RunCount , 1 ) } ,
996
1023
{ "SimpleI32Memops" , listener . SimpleI32Memops } ,
997
- { "AverageBlockSize" , listener . AverageBlockLengthSum / ( double ) listener . BlockCount } ,
1024
+ { "AverageBlockSize" , listener . AverageBlockLengthSum / ( double ) Math . Max ( listener . BlockCount , 1 ) } ,
998
1025
{ "Num2OpBlocks" , listener . SmallBlockCounts [ 2 ] } ,
999
1026
{ "Num3OpBlocks" , listener . SmallBlockCounts [ 3 ] } ,
1000
1027
{ "Num4OpBlocks" , listener . SmallBlockCounts [ 4 ] } ,
@@ -1008,88 +1035,114 @@ private static void GenerateGraph (
1008
1035
EnsureValidPath ( path ) ;
1009
1036
1010
1037
using ( var output = new StreamWriter ( path , false , Encoding . UTF8 ) ) {
1011
- output . WriteLine ( "digraph namespaces {" ) ;
1012
-
1013
- const int maxLength = 24 ;
1038
+ const int maxLength = 64 ;
1014
1039
const int minCount = 2 ;
1040
+ const double sizeTo1Inch = 10240 ;
1041
+ const bool namespaceMode = false ;
1015
1042
1016
- var namespaceDependencies = data . DependencyGraph . Where ( dgn => dgn . NamespaceName != null ) . ToLookup ( dgn => dgn . NamespaceName ) ;
1043
+ if ( namespaceMode ) {
1044
+ output . WriteLine ( "digraph namespaces {" ) ;
1017
1045
1018
- var referencedNamespaces = new HashSet < NamespaceInfo > ( NamespaceInfo . Comparer ) ;
1019
- foreach ( var kvp in data . Namespaces ) {
1020
- if ( ( config . GraphRegexes . Count > 0 ) && ! config . GraphRegexes . Any ( gr => gr . IsMatch ( kvp . Key ) ) )
1021
- continue ;
1046
+ var namespaceDependencies = data . DependencyGraph . Where ( dgn => dgn . NamespaceName != null ) . ToLookup ( dgn => dgn . NamespaceName ) ;
1022
1047
1023
- if ( kvp . Value . FunctionCount < minCount )
1024
- continue ;
1048
+ var referencedNamespaces = new HashSet < NamespaceInfo > ( NamespaceInfo . Comparer ) ;
1049
+ foreach ( var kvp in data . Namespaces ) {
1050
+ if ( ( config . GraphRegexes . Count > 0 ) && ! config . GraphRegexes . Any ( gr => gr . IsMatch ( kvp . Key ) ) )
1051
+ continue ;
1025
1052
1026
- foreach ( var cns in kvp . Value . ChildNamespaces )
1027
- referencedNamespaces . Add ( cns ) ;
1053
+ if ( kvp . Value . FunctionCount < minCount )
1054
+ continue ;
1055
+
1056
+ foreach ( var cns in kvp . Value . ChildNamespaces )
1057
+ referencedNamespaces . Add ( cns ) ;
1028
1058
1029
- if ( namespaceDependencies . Contains ( kvp . Key ) ) {
1030
- var dgn = namespaceDependencies [ kvp . Key ] . First ( ) ;
1059
+ if ( namespaceDependencies . Contains ( kvp . Key ) ) {
1060
+ var dgn = namespaceDependencies [ kvp . Key ] . First ( ) ;
1031
1061
1032
- foreach ( var cn in dgn . ReferencedNamespaces )
1033
- referencedNamespaces . Add ( data . Namespaces [ cn . NamespaceName ] ) ;
1062
+ foreach ( var cn in dgn . ReferencedNamespaces )
1063
+ referencedNamespaces . Add ( data . Namespaces [ cn . NamespaceName ] ) ;
1064
+ }
1034
1065
}
1035
- }
1036
1066
1037
- var namespaces = new HashSet < NamespaceInfo > ( NamespaceInfo . Comparer ) ;
1038
- foreach ( var kvp in data . Namespaces ) {
1039
- namespaces . Add ( kvp . Value ) ;
1067
+ var namespaces = new HashSet < NamespaceInfo > ( NamespaceInfo . Comparer ) ;
1068
+ foreach ( var kvp in data . Namespaces ) {
1069
+ namespaces . Add ( kvp . Value ) ;
1040
1070
1041
- if ( namespaceDependencies . Contains ( kvp . Key ) ) {
1042
- var dgn = namespaceDependencies [ kvp . Key ] . First ( ) ;
1071
+ if ( namespaceDependencies . Contains ( kvp . Key ) ) {
1072
+ var dgn = namespaceDependencies [ kvp . Key ] . First ( ) ;
1043
1073
1044
- foreach ( var rn in dgn . ReferencedNamespaces )
1045
- namespaces . Add ( data . Namespaces [ rn . NamespaceName ] ) ;
1074
+ foreach ( var rn in dgn . ReferencedNamespaces )
1075
+ namespaces . Add ( data . Namespaces [ rn . NamespaceName ] ) ;
1076
+ }
1046
1077
}
1047
- }
1048
1078
1049
- var labelsNeeded = new HashSet < NamespaceInfo > ( NamespaceInfo . Comparer ) ;
1079
+ var labelsNeeded = new HashSet < NamespaceInfo > ( NamespaceInfo . Comparer ) ;
1050
1080
1051
- foreach ( var nsi in namespaces ) {
1052
- if ( ! referencedNamespaces . Contains ( nsi ) ) {
1053
- if ( nsi . FunctionCount < minCount )
1054
- continue ;
1081
+ foreach ( var nsi in namespaces ) {
1082
+ if ( ! referencedNamespaces . Contains ( nsi ) ) {
1083
+ if ( nsi . FunctionCount < minCount )
1084
+ continue ;
1055
1085
1056
- if ( ( config . GraphRegexes . Count > 0 ) && ! config . GraphRegexes . Any ( gr => gr . IsMatch ( nsi . Name ) ) )
1057
- continue ;
1058
- }
1086
+ if ( ( config . GraphRegexes . Count > 0 ) && ! config . GraphRegexes . Any ( gr => gr . IsMatch ( nsi . Name ) ) )
1087
+ continue ;
1088
+ }
1059
1089
1060
- labelsNeeded . Add ( nsi ) ;
1090
+ labelsNeeded . Add ( nsi ) ;
1061
1091
1062
- foreach ( var cns in nsi . ChildNamespaces ) {
1063
- if ( cns . FunctionCount < minCount )
1064
- continue ;
1092
+ foreach ( var cns in nsi . ChildNamespaces ) {
1093
+ if ( cns . FunctionCount < minCount )
1094
+ continue ;
1065
1095
1066
- output . WriteLine ( $ "\t \" ns{ nsi . Index . ToString ( ) } \" -> \" ns{ cns . Index . ToString ( ) } \" ;") ;
1096
+ output . WriteLine ( $ "\t \" ns{ nsi . Index . ToString ( ) } \" -> \" ns{ cns . Index . ToString ( ) } \" ;") ;
1067
1097
1068
- labelsNeeded . Add ( nsi ) ;
1069
- labelsNeeded . Add ( cns ) ;
1070
- }
1098
+ labelsNeeded . Add ( nsi ) ;
1099
+ labelsNeeded . Add ( cns ) ;
1100
+ }
1071
1101
1072
- if ( namespaceDependencies . Contains ( nsi . Name ) ) {
1073
- var dgn = namespaceDependencies [ nsi . Name ] . First ( ) ;
1102
+ if ( namespaceDependencies . Contains ( nsi . Name ) ) {
1103
+ var dgn = namespaceDependencies [ nsi . Name ] . First ( ) ;
1074
1104
1075
- foreach ( var rn in dgn . ReferencedNamespaces ) {
1076
- var rni = data . Namespaces [ rn . NamespaceName ] ;
1077
- labelsNeeded . Add ( rni ) ;
1078
- output . WriteLine ( $ "\t \" ns{ nsi . Index . ToString ( ) } \" -> \" ns{ rni . Index . ToString ( ) } \" ;") ;
1105
+ foreach ( var rn in dgn . ReferencedNamespaces ) {
1106
+ var rni = data . Namespaces [ rn . NamespaceName ] ;
1107
+ labelsNeeded . Add ( rni ) ;
1108
+ output . WriteLine ( $ "\t \" ns{ nsi . Index . ToString ( ) } \" -> \" ns{ rni . Index . ToString ( ) } \" ;") ;
1109
+ }
1079
1110
}
1080
1111
}
1081
- }
1082
1112
1083
- foreach ( var nsi in labelsNeeded ) {
1084
- var label = nsi . Name . Replace ( "*" , "" ) ;
1085
- if ( label . Length > maxLength )
1086
- label = label . Substring ( 0 , maxLength ) + "..." ;
1113
+ foreach ( var nsi in labelsNeeded ) {
1114
+ var label = nsi . Name . Replace ( "*" , "" ) ;
1115
+ if ( label . Length > maxLength )
1116
+ label = label . Substring ( 0 , maxLength ) + "..." ;
1087
1117
1088
- var color = config . GraphRegexes . Any ( gr => gr . IsMatch ( nsi . Name ) ) ? "AAAAAA" : "DFDFDF" ;
1089
- output . WriteLine ( $ "\t \" ns{ nsi . Index . ToString ( ) } \" [label=\" { label } \" , style=\" filled\" , color=\" #{ color } \" ];") ;
1090
- }
1118
+ var color = config . GraphRegexes . Any ( gr => gr . IsMatch ( nsi . Name ) ) ? "AAAAAA" : "DFDFDF" ;
1119
+ output . WriteLine ( $ "\t \" ns{ nsi . Index . ToString ( ) } \" [label=\" { label } \" , style=\" filled\" , SizeBytes={ nsi . SizeBytes } , FunctionCount={ nsi . FunctionCount } ];") ;
1120
+ }
1121
+
1122
+ output . WriteLine ( "}" ) ;
1123
+ } else {
1124
+ output . WriteLine ( "digraph functions {" ) ;
1125
+
1126
+ foreach ( var dgn in data . DependencyGraph ) {
1127
+ if ( dgn . Function == null )
1128
+ continue ;
1129
+
1130
+ if ( dgn . DirectDependencies != null )
1131
+ foreach ( var dd in dgn . DirectDependencies ) {
1132
+ if ( dd . Function == null )
1133
+ continue ;
1134
+ output . WriteLine ( $ "\t \" fn{ dgn . Function . Index } \" -> \" fn{ dd . Function . Index } \" ;") ;
1135
+ }
1091
1136
1092
- output . WriteLine ( "}" ) ;
1137
+ var label = dgn . Function . Name . Replace ( "*" , "" ) ;
1138
+ if ( label . Length > maxLength )
1139
+ label = label . Substring ( 0 , maxLength ) + "..." ;
1140
+
1141
+ output . WriteLine ( $ "\t \" fn{ dgn . Function . Index } \" [label=\" { label } \" , style=\" filled\" , ShallowSize={ dgn . ShallowSize } , DeepSize={ dgn . DeepSize } ];") ;
1142
+ }
1143
+
1144
+ output . WriteLine ( "}" ) ;
1145
+ }
1093
1146
}
1094
1147
}
1095
1148
@@ -1852,6 +1905,9 @@ public static void ParseOption (string arg, Config config) {
1852
1905
case "dumponly" :
1853
1906
config . DisassembleFunctions = false ;
1854
1907
break ;
1908
+ case "whatis" :
1909
+ config . WhatIs = operand ;
1910
+ break ;
1855
1911
default :
1856
1912
Console . Error . WriteLine ( $ "Invalid argument: '{ arg } '") ;
1857
1913
break ;
0 commit comments