To debug C# code with IL2CPPA Unity-developed scripting back-end which you can use as an alternative to Mono when building Projects for some platforms. More info
See in Glossary, enable Script Debugging in the Build Settings before building the Project, and enable the InternetClient, InternetClientServer and PrivateNetworkClientServer capabilities in the Player settingsSettings that let you set various player-specific options for the final game built by Unity. More info
See in Glossary or the manifest. The manifest is not overwrriten when you build on top of a previous build, so if you want to change the capabilities, you need to do it from Visual Studio manifest editor.
The debugging procedure is the same as any other Unity platform. For more information, see Debugging C# code in Unity.
In addition to debugging C# code, you can debug generated C++ code using Visual Studio.
IL2CPP classes look like this: <ClassName>_t#number
, where <ClassName>
is plain name of a class, while #number is a unique type number. #number is not present on some of the core types. For example:
String_t
Object_t
Type_t
Char_t34
StringBuilder_t26
GuidParser_t1539
IL2CPP methods look like this: <ClassName>_<MethodName>_m#number
, where <ClassName>
is the plain class name of methods declaring type, <MethodName>
is a plain method name and #number
is unique method number. For example:
GuidParser_ParseHex_m10003
ConfigurationSection_DoDeserializeSection_m1275
String_Format_m4102
Mathf_Sqrt_m289
Thing_Start_m1
Static field structures are named like this: <ClassName>_t#number_StaticFields
, where the first part of the structure name is identical to the declaring type, for example:
StringBuilder_t26_StaticFields
Thing_t24_StaticFields
Furthermore, above each class/method definition there is a C++ comment stating full class/method name. For example:
// System.String
struct String_t : public Object_t
{
// System.Int32 System.String::length
int32_t _length_0;
// System.Char System.String::start_char
uint16_t _start_char_1;
};
// System.Text.StringBuilder
struct StringBuilder_t26 : public Object_t
{
// System.Int32 System.Text.StringBuilder::_length
int32_t length_1;
// System.String System.Text.StringBuilder::_str
String_t* str_2;
// System.String System.Text.StringBuilder::_cached_str
String_t* cached_str_3;
// System.Int32 System.Text.StringBuilder::_maxCapacity
int32_t maxCapacity_4;
};
// System.Void MyData::.ctor()
extern "C" void MyData_ctor_m0 (MyData_t2 * this, const MethodInfo* method)
{
...
}
// Thing
struct Thing_t24 : public MonoBehaviour_t25
{
// MyData Thing::m_Data
MyData_t2 * _m_Data_2;
// System.Text.StringBuilder Thing::m_Builder
StringBuilder_t26 * _m_Builder_3;
};
struct Thing_t24_StaticFields
{
// System.Int32 Thing::s_SomeStaticField
int32_t _s_SomeStaticField_4;
};
One of the most important parts of debugging is observing values of various variables. Visual Studio allows to do that relatively easily by either mousing over the variable of adding it into the watch window. For example:
Observing static fields is a little bit harder. In IL2CPP, static fields are stored on a Il2CppClass instance itself. So in order to observe a static field, we’ll first need a pointer to Il2CppClass structure of that type. These pointers are in scope of methods that use them, but after observing it once, it will remain at the same memory address for the duration of application run. Il2CppClass structure has “static_fields” field, which is a pointer to a memory block containing static fields for that particular type. To view the actual values, this pointer has to be cast to appropriate static field structure: each type has its own. For example, let’s observe the static fields of class Thing_t24
:
IL2CPP uses native C++ exceptions to implement .NET exceptions. When any exception is supposed to be thrown, IL2CPP throws Il2CppExceptionWrapper object, which is defined as the following:
struct Il2CppExceptionWrapper
{
Il2CppException* ex;
Il2CppExceptionWrapper (Il2CppException* ex) : ex (ex) {}
};
These exception objects can be easily investigated in the watch window:
Lastly, it might be beneficial to enable debugger-break on exception so the source of the exception can be caught red-handed. To do so, hit CTRL+ALT+E in Visual Studio, and make sure that C++ exceptions checkbox is checked in the opened window:
After enabling this setting, Visual Studio will automatically stop execution whenever an exception is thrown:
• 2018–10–18 Page amended with no editorial review
C# debugging for IL2CPP on Universal Windows Platform added in 2018.2 NewIn20182
Did you find this page useful? Please give it a rating:
Thanks for rating this page!
What kind of problem would you like to report?
Is something described here not working as you expect it to? It might be a Known Issue. Please check with the Issue Tracker at issuetracker.unity3d.com.
Thanks for letting us know! This page has been marked for review based on your feedback.
If you have time, you can provide more information to help us fix the problem faster.
Provide more information
You've told us this page needs code samples. If you'd like to help us further, you could provide a code sample, or tell us about what kind of code sample you'd like to see:
You've told us there are code samples on this page which don't work. If you know how to fix it, or have something better we could use instead, please let us know:
You've told us there is information missing from this page. Please tell us more about what's missing:
You've told us there is incorrect information on this page. If you know what we should change to make it correct, please tell us:
You've told us this page has unclear or confusing information. Please tell us more about what you found unclear or confusing, or let us know how we could make it clearer:
You've told us there is a spelling or grammar error on this page. Please tell us what's wrong:
You've told us this page has a problem. Please tell us more about what's wrong:
Thanks for helping to make the Unity documentation better!