IL2CPP를 사용하여 C# 코드를 디버깅하려면 프로젝트를 빌드하기 전에 빌드 설정에서 Script Debugging 을 활성화한 후 플레이어 설정 또는 매니페스트에서 InternetClient, InternetClientServer 및 PrivateNetworkClientServer 기능을 활성화하십시오. 이전 빌드 위에 빌드하는 경우에는 매니페스트를 덮어쓰지 않으므로, 기능을 변경하려는 경우 Visual Studio 매니페스트 에디터에서 직접 변경해야 합니다.
디버깅 절차는 다른 Unity 플랫폼과 동일합니다. 자세한 내용은 Unity의 C# 코드 디버깅을 참조하십시오.
C# 코드 디버깅 외에도 Visual Studio를 사용하여 생성된 C++ 코드를 디버깅할 수 있습니다.
IL2CPP 클래스의 이름은 <ClassName>_t#number
형식을 가집니다. 여기서 <ClassName>
은 클래스 이름이며, #number는 고유 타입 번호입니다. #number는 몇몇 코어 타입에는 없습니다. 아래의 예시를 참조하십시오.
String_t
Object_t
Type_t
Char_t34
StringBuilder_t26
GuidParser_t1539
IL2CPP 메서드의 이름은 <ClassName>_<MethodName>_m#number
형식을 가집니다. 여기서 <ClassName>
은 메서드 선언 타입의 클래스 이름이며, <MethodName>
은 메서드 이름이고, #number
는 고유 메서드 번호입니다. 아래 예제를 참조하십시오.
GuidParser_ParseHex_m10003
ConfigurationSection_DoDeserializeSection_m1275
String_Format_m4102
Mathf_Sqrt_m289
Thing_Start_m1
정적 필드 구조는 <ClassName>_t#number_StaticFields
형식을 가집니다. 여기서 구조 이름의 첫 부분은 선언 타입과 동일합니다. 아래 예제를 참조하십시오.
StringBuilder_t26_StaticFields
Thing_t24_StaticFields
또한 각 클래스와 메서드 정의 위에는 전체 클래스와 메서드의 이름을 명시하는 C++ 코멘트가 있습니다. 아래 예제를 참조하십시오.
// 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;
};
디버깅의 중요한 부분 중 하나는 다양한 변수의 값을 관측하는 것입니다. Visual Studio를 사용하면 변수 위에 마우스를 올리거나 보기 창에 추가하는 방식으로 간단하게 할 수 있습니다. 아래의 예시를 참조하십시오.
정적 필드 관측은 조금 더 어렵습니다. IL2CPP의 경우 정적 필드는 Il2CppClass 인스턴스 내에 저장됩니다. 따라서 정적 필드를 관측하려면 우선 해당 타입의 Il2CppClass 구조에 대한 포인터가 필요합니다. 이 포인터는 사용하는 메서드 범위 내에 있지만 한 번 관측하고 나면 애플리케이션이 실행되는 동안은 동일한 메모리 주소에 머물게 됩니다. Il2CppClass 구조는 “static_fields” 필드가 있습니다. 이 필드는 해당 특정 타입에 대한 정적 필드를 포함하는 메모리 블록 포인터입니다. 실제 값을 보려면 포인터가 올바른 정적 필드 구조에 캐스트되어야하며, 각 타입은 그에 맞는 구조를 가지고 있습니다. 아래의 예시는 Thing_t24
클래스의 정적 필드 관측에 대한 것입니다.
IL2CPP는 .NET 예외를 구현하기 위해 네이티브 C++ 예외를 사용합니다. 예외 오류가 발생하는 경우 IL2CPP는 아래와 같이 정의되는 Il2CppExceptionWrapper 오브젝트를 발생시킵니다.
struct Il2CppExceptionWrapper
{
Il2CppException* ex;
Il2CppExceptionWrapper (Il2CppException* ex) : ex (ex) {}
};
이러한 예외 오브젝트는 보기 창에서 아래와 같이 쉽게 분석할 수 있습니다.
마지막으로 예외가 발생하면 디버거 브레이크를 활성화하는게 도움이 될 수 있습니다. 예외 원인을 바로 파악할 수 있기 때문입니다. Visual Studio에서 CTRL+ALT+E를 누르면 되며, 열린 창에서 C++ 예외 체크박스가 선택되어 있는지 확인해야 합니다.
이 설정을 활성화하면 Visual Studio는 아래와 같이 예외가 발생하면 자동으로 실행을 멈추게 됩니다.