• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

SamboyCoding / Cpp2IL / 12223020379

08 Dec 2024 03:28PM UTC coverage: 28.172% (-0.2%) from 28.362%
12223020379

push

github

web-flow
Wasm name section output format (#388)

1265 of 6236 branches covered (20.29%)

Branch coverage included in aggregate %.

2 of 88 new or added lines in 2 files covered. (2.27%)

3385 of 10270 relevant lines covered (32.96%)

124946.92 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.85
/Cpp2IL.Core/OutputFormats/WasmNameSectionOutputFormat.cs
1
using System;
2
using System.IO;
3
using System.Linq;
4
using System.Text;
5
using Cpp2IL.Core.Api;
6
using Cpp2IL.Core.Logging;
7
using Cpp2IL.Core.Model.Contexts;
8
using Cpp2IL.Core.Utils;
9
using LibCpp2IL;
10
using LibCpp2IL.Wasm;
11

12
namespace Cpp2IL.Core.OutputFormats;
13

14
public class WasmNameSectionOutputFormat : Cpp2IlOutputFormat
15
{
16
    public override string OutputFormatId => "wasm_name_section";
1✔
NEW
17
    public override string OutputFormatName => "Webassembly name section";
×
18

19
    public override void DoOutput(ApplicationAnalysisContext context, string outputRoot)
20
    {
21
        // Outputs a binary file matching the standardized "name" WebAssembly custom section.
22
        // If the game's binary doesn't already have the same type of section (which is practically always),
23
        // all that's needed to combine the two is a simple `cat main.wasm section.dat > out.wasm`.
24
        // Using this modified binary in place of the original one provides extra information for debuggers.
25

26
        // The spec can be found here: https://webassembly.github.io/spec/core/appendix/custom.html#name-section
27
        // Some additional subsections have been proposed (already implemented in v8 & spidermonkey), but they don't seem to be helpful as of now.
28
        // The proposal overview can be found here: https://github.com/WebAssembly/extended-name-section/blob/main/proposals/extended-name-section/Overview.md
29

NEW
30
        if (context.Binary.GetType() != typeof(WasmFile))
×
NEW
31
            throw new Exception("This output format only works with WebAssembly files");
×
32

NEW
33
        if (!Directory.Exists(outputRoot))
×
NEW
34
            Directory.CreateDirectory(outputRoot);
×
35

NEW
36
        var outputFile = File.Create(Path.Combine(outputRoot, "namesection.dat"));
×
37

NEW
38
        var section =
×
NEW
39
            new MemoryStream(); // This stream is separate from outputFile because we need to know the size of the section before writing it
×
NEW
40
        section.WriteName("name"); // The section's name (`name`)
×
41

NEW
42
        var moduleNameSubsection = new MemoryStream();
×
NEW
43
        moduleNameSubsection.WriteName("Unity");
×
NEW
44
        section.WriteSizedData(moduleNameSubsection, 0x0); // Subsection id 0
×
NEW
45
        moduleNameSubsection.Dispose();
×
46

NEW
47
        var paramSuccessCount = 0;
×
NEW
48
        var paramFailCount = 0;
×
49

NEW
50
        var functionData = context.AllTypes.SelectMany(t => t.Methods)
×
NEW
51
            .Select(method => (method, definition: WasmUtils.TryGetWasmDefinition(method)))
×
NEW
52
            .Where(v => v.definition is not null)
×
NEW
53
            .Select(v =>
×
NEW
54
            {
×
NEW
55
                var trueParamCount = v.definition!.GetType((WasmFile)LibCpp2IlMain.Binary!).ParamTypes.Length;
×
NEW
56

×
NEW
57
                // Also see WasmUtils.BuildSignature
×
NEW
58
                var parameters = v.method.Parameters.Select(param => param.Name).ToList();
×
NEW
59

×
NEW
60
                if (!v.method.IsStatic)
×
NEW
61
                    parameters.Insert(0, "this");
×
NEW
62

×
NEW
63
                if (v.method.ReturnTypeContext is
×
NEW
64
                    { IsValueType: true, IsPrimitive: true, Definition: null or { Size: > 8 } })
×
NEW
65
                    parameters.Insert(0, "out");
×
NEW
66

×
NEW
67
                parameters.Add("methodInfo"); // Only for some methods...?
×
NEW
68

×
NEW
69
                if (trueParamCount != parameters.Count)
×
NEW
70
                {
×
NEW
71
                    // Logger.WarnNewline($"Failed param matching for {v.method.FullNameWithSignature}, calculated {parameters.Count} with there actually being {trueParamCount} ({string.Join(" ", parameters)})");
×
NEW
72
                    parameters.Clear();
×
NEW
73
                    paramFailCount++;
×
NEW
74
                }
×
NEW
75
                else
×
NEW
76
                {
×
NEW
77
                    paramSuccessCount++;
×
NEW
78
                }
×
NEW
79

×
NEW
80
                return (
×
NEW
81
                    Index: v.definition!.FunctionTableIndex,
×
NEW
82
                    Name: v.method.FullName,
×
NEW
83
                    Parameters: parameters
×
NEW
84
                );
×
NEW
85
            })
×
NEW
86
            .GroupBy(v => v.Index)
×
NEW
87
            .OrderBy(grouping => grouping.Key)
×
NEW
88
            .ToDictionary(
×
NEW
89
                grouping => grouping.Key,
×
NEW
90
                grouping => grouping.Select(v => (v.Name, v.Parameters)).ToList()
×
NEW
91
            );
×
92
        
NEW
93
        Logger.InfoNewline(
×
NEW
94
            $"Estimated parameter naming success rate: {(float)paramSuccessCount / (paramSuccessCount + paramFailCount) * 100:N2}%");
×
95

NEW
96
        var functionNameSubsection = new MemoryStream();
×
NEW
97
        functionNameSubsection.WriteLEB128Unsigned((ulong)functionData.Count); // vector length
×
98

NEW
99
        var localNameSubsection = new MemoryStream();
×
NEW
100
        localNameSubsection.WriteLEB128Unsigned((ulong)functionData.Count); // vector length
×
101

NEW
102
        foreach (var (idx, data) in functionData)
×
103
        {
NEW
104
            functionNameSubsection.WriteLEB128Unsigned((ulong)idx);
×
NEW
105
            localNameSubsection.WriteLEB128Unsigned((ulong)idx);
×
106

NEW
107
            functionNameSubsection.WriteName(data.Count == 1 ? data[0].Name : $"multiple_{data.Count}_{data[0].Name}");
×
108

NEW
109
            localNameSubsection.WriteLEB128Unsigned((ulong)data[0].Parameters.Count); // vector length
×
NEW
110
            for (var i = 0; i < data[0].Parameters.Count; i++)
×
111
            {
NEW
112
                localNameSubsection.WriteLEB128Unsigned((ulong)i);
×
113
                // Possible to include type here, but may make names excessively long
NEW
114
                localNameSubsection.WriteName(data.Count == 1
×
NEW
115
                    ? data[0].Parameters[i]
×
NEW
116
                    : $"multiple_{data.Count}_{data[0].Parameters[i]}");
×
117
            }
118
        }
119

NEW
120
        section.WriteSizedData(functionNameSubsection, 0x1); // Subsection id 1
×
NEW
121
        section.WriteSizedData(localNameSubsection, 0x2); // Subsection id 2
×
122

NEW
123
        outputFile.WriteSizedData(section, 0x0); // Section id 0 - custom
×
NEW
124
    }
×
125
}
126

127
public static class Extensions
128
{
129
    public static void WriteName(this Stream memoryStream, string name)
130
    {
NEW
131
        var bytes = Encoding.Default.GetBytes(name);
×
NEW
132
        memoryStream.WriteLEB128Unsigned((ulong)bytes.Length);
×
NEW
133
        memoryStream.Write(bytes, 0, bytes.Length);
×
NEW
134
    }
×
135

136
    public static void WriteSizedData(this Stream memoryStream, MemoryStream data, byte? prependByte = null)
137
    {
NEW
138
        if (prependByte.HasValue)
×
139
        {
NEW
140
            memoryStream.WriteByte(prependByte.Value);
×
141
        }
142

NEW
143
        memoryStream.WriteLEB128Unsigned((ulong)data.Length);
×
NEW
144
        data.WriteTo(memoryStream);
×
NEW
145
    }
×
146
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc