Skip to content

Commit 0aa3226

Browse files
committed
Add --whatis command line switch to convert runtime function table index to index/name
Improve graphviz output
1 parent 218d331 commit 0aa3226

File tree

2 files changed

+115
-59
lines changed

2 files changed

+115
-59
lines changed

Program.cs

Lines changed: 114 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
using ModuleSaw;
1414
using System.Threading.Tasks;
1515
using System.Threading;
16+
using System.Net;
1617

1718
namespace WasmStrip {
1819
class ReferenceComparer<T> : IEqualityComparer<T> {
@@ -51,6 +52,8 @@ class Config {
5152
public bool DumpFunctions = true, DisassembleFunctions = true;
5253
public string DumpFunctionsPath;
5354
public List<Regex> DumpFunctionRegexes = new List<Regex>();
55+
56+
public string WhatIs;
5457
}
5558

5659
class NamespaceInfo {
@@ -168,6 +171,29 @@ public static int Main (string[] _args) {
168171
if (config.DumpSectionsPath != null)
169172
DumpSections(config, wasmBytes, wasmReader);
170173

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+
171197
ClearLine("Analyzing module.");
172198

173199
AnalysisData data = null;
@@ -255,6 +281,7 @@ public static int Main (string[] _args) {
255281
Console.Error.WriteLine(" --strip-list=regexes.txt");
256282
Console.Error.WriteLine(" --retain=regex [...]");
257283
Console.Error.WriteLine(" --retain-list=regexes.txt");
284+
Console.Error.WriteLine(" --whatis=(func-index)|0x(hex-func-index)|(func-name)");
258285
}
259286

260287
if (Debugger.IsAttached) {
@@ -992,9 +1019,9 @@ private Dictionary<string, object> ComputeRawData (Config config, byte[] wasmByt
9921019
{"SetLocalRuns", listener.SetLocalRuns },
9931020
{"DupCandidates", listener.DupCandidates },
9941021
{"MaxRunSize", listener.MaxRunSize },
995-
{"AverageRunLength", listener.AverageRunLengthSum / (double)listener.RunCount },
1022+
{"AverageRunLength", listener.AverageRunLengthSum / (double)Math.Max(listener.RunCount, 1) },
9961023
{"SimpleI32Memops", listener.SimpleI32Memops },
997-
{"AverageBlockSize", listener.AverageBlockLengthSum / (double)listener.BlockCount },
1024+
{"AverageBlockSize", listener.AverageBlockLengthSum / (double)Math.Max(listener.BlockCount, 1) },
9981025
{"Num2OpBlocks", listener.SmallBlockCounts[2] },
9991026
{"Num3OpBlocks", listener.SmallBlockCounts[3] },
10001027
{"Num4OpBlocks", listener.SmallBlockCounts[4] },
@@ -1008,88 +1035,114 @@ private static void GenerateGraph (
10081035
EnsureValidPath(path);
10091036

10101037
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;
10141039
const int minCount = 2;
1040+
const double sizeTo1Inch = 10240;
1041+
const bool namespaceMode = false;
10151042

1016-
var namespaceDependencies = data.DependencyGraph.Where(dgn => dgn.NamespaceName != null).ToLookup(dgn => dgn.NamespaceName);
1043+
if (namespaceMode) {
1044+
output.WriteLine("digraph namespaces {");
10171045

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);
10221047

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;
10251052

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);
10281058

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();
10311061

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+
}
10341065
}
1035-
}
10361066

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);
10401070

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();
10431073

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+
}
10461077
}
1047-
}
10481078

1049-
var labelsNeeded = new HashSet<NamespaceInfo>(NamespaceInfo.Comparer);
1079+
var labelsNeeded = new HashSet<NamespaceInfo>(NamespaceInfo.Comparer);
10501080

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;
10551085

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+
}
10591089

1060-
labelsNeeded.Add(nsi);
1090+
labelsNeeded.Add(nsi);
10611091

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;
10651095

1066-
output.WriteLine($"\t\"ns{nsi.Index.ToString()}\" -> \"ns{cns.Index.ToString()}\";");
1096+
output.WriteLine($"\t\"ns{nsi.Index.ToString()}\" -> \"ns{cns.Index.ToString()}\";");
10671097

1068-
labelsNeeded.Add(nsi);
1069-
labelsNeeded.Add(cns);
1070-
}
1098+
labelsNeeded.Add(nsi);
1099+
labelsNeeded.Add(cns);
1100+
}
10711101

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();
10741104

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+
}
10791110
}
10801111
}
1081-
}
10821112

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) + "...";
10871117

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+
}
10911136

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+
}
10931146
}
10941147
}
10951148

@@ -1852,6 +1905,9 @@ public static void ParseOption (string arg, Config config) {
18521905
case "dumponly":
18531906
config.DisassembleFunctions = false;
18541907
break;
1908+
case "whatis":
1909+
config.WhatIs = operand;
1910+
break;
18551911
default:
18561912
Console.Error.WriteLine($"Invalid argument: '{arg}'");
18571913
break;

WasmStrip.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
<PropertyGroup>
44
<OutputType>Exe</OutputType>
5-
<TargetFramework>netcoreapp2.1</TargetFramework>
5+
<TargetFramework>net7.0</TargetFramework>
66
<LangVersion>latest</LangVersion>
77
</PropertyGroup>
88

0 commit comments

Comments
 (0)