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

SamboyCoding / Cpp2IL / 30178263727

25 Jul 2026 10:48PM UTC coverage: 36.302% (-0.8%) from 37.144%
30178263727

push

github

SamboyCoding
Decompiler: Recover static fields, throw helpers, and rgctx, fix bool flags, fix this param in IL, fix float handling somewhat

2890 of 9069 branches covered (31.87%)

Branch coverage included in aggregate %.

28 of 319 new or added lines in 17 files covered. (8.78%)

10 existing lines in 6 files now uncovered.

5291 of 13467 relevant lines covered (39.29%)

164158.62 hits per line

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

0.0
/Cpp2IL.Core/Analysis/ThrowHelperRecovery.cs
1
using System;
2
using System.Collections.Generic;
3
using Cpp2IL.Core.Model.Contexts;
4
using Cpp2IL.Core.Utils;
5
using Iced.Intel;
6

7
namespace Cpp2IL.Core.Analysis;
8

9
/// <summary>
10
/// Finds exception throw helper functions. These eventually look up the type they throw by name
11
/// (via <c>Class::FromName(corlib, "System", "NullReferenceException")</c>), so the type name appears
12
/// as a plain C string in the helper's body.
13
/// </summary>
14
public static class ThrowHelperRecovery
15
{
16
    private const int MaxDepth = 5;
17
    private const int MaxStringLength = 64;
18

19
    public static TypeAnalysisContext? GetThrownException(ApplicationAnalysisContext appContext, ulong address)
20
    {
NEW
21
        var name = ResolveName(appContext, address, 0);
×
22

NEW
23
        if (name == null)
×
NEW
24
            return null;
×
25

NEW
26
        var type = appContext.LibCpp2IlContext.ReflectionCache.GetType(name);
×
27

NEW
28
        return type == null ? null : appContext.ResolveContextForType(type);
×
29
    }
30

31
    private static string? ResolveName(ApplicationAnalysisContext appContext, ulong address, int depth)
32
    {
NEW
33
        if (appContext.ThrowHelperNamesByAddress.TryGetValue(address, out var cached))
×
NEW
34
            return cached;
×
35

NEW
36
        if (address == 0 || depth >= MaxDepth)
×
NEW
37
            return null;
×
38

39
        // Insert before recursing so a cycle terminates
NEW
40
        appContext.ThrowHelperNamesByAddress[address] = null;
×
41

42
        InstructionList body;
43

44
        try
45
        {
NEW
46
            body = X86Utils.GetMethodBodyAtVirtAddressNew(address, true, appContext.Binary);
×
NEW
47
        }
×
NEW
48
        catch
×
49
        {
NEW
50
            return null;
×
51
        }
52

NEW
53
        var name = FindExceptionName(appContext, body);
×
54

NEW
55
        if (name == null)
×
56
        {
NEW
57
            foreach (var instruction in body)
×
58
            {
NEW
59
                if (instruction.Mnemonic != Mnemonic.Call || instruction.Op0Kind != OpKind.NearBranch64)
×
60
                    continue;
61

NEW
62
                name = ResolveName(appContext, instruction.NearBranchTarget, depth + 1);
×
63

NEW
64
                if (name != null)
×
NEW
65
                    break;
×
66
            }
67
        }
68

NEW
69
        appContext.ThrowHelperNamesByAddress[address] = name;
×
NEW
70
        return name;
×
NEW
71
    }
×
72

73
    private static string? FindExceptionName(ApplicationAnalysisContext appContext, InstructionList body)
74
    {
NEW
75
        foreach (var instruction in body)
×
76
        {
NEW
77
            if (instruction.Mnemonic != Mnemonic.Lea || !instruction.IsIPRelativeMemoryOperand)
×
78
                continue;
79

NEW
80
            if (ReadCStringAtVirtualAddress(appContext, instruction.IPRelativeMemoryAddress) is { } text && text.EndsWith("Exception", StringComparison.Ordinal))
×
NEW
81
                return text;
×
82
        }
83

NEW
84
        return null;
×
NEW
85
    }
×
86

87
    //TODO didn't we have a helper for this somewhere? Can't find it. Maybe got deleted. Maybe it's just too late
88
    private static string? ReadCStringAtVirtualAddress(ApplicationAnalysisContext appContext, ulong address)
89
    {
90
        long offset;
91

92
        try
93
        {
NEW
94
            offset = appContext.Binary.MapVirtualAddressToRaw(address, false);
×
NEW
95
        }
×
NEW
96
        catch
×
97
        {
NEW
98
            return null;
×
99
        }
100

NEW
101
        if (offset <= 0)
×
NEW
102
            return null;
×
103

NEW
104
        var content = appContext.Binary.GetRawBinaryContent();
×
NEW
105
        var end = offset;
×
106

NEW
107
        while (end < content.Length && end - offset < MaxStringLength && content[(int)end] != 0)
×
108
        {
NEW
109
            var c = content[(int)end];
×
110

NEW
111
            if (c < 32 || c >= 127)
×
NEW
112
                return null;
×
113

NEW
114
            end++;
×
115
        }
116

NEW
117
        if (end == offset || end >= content.Length || content[(int)end] != 0)
×
NEW
118
            return null;
×
119

NEW
120
        var characters = new char[end - offset];
×
121

NEW
122
        for (var i = 0; i < characters.Length; i++)
×
NEW
123
            characters[i] = (char)content[(int)offset + i];
×
124

NEW
125
        return new string(characters);
×
NEW
126
    }
×
127
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc