原文地址:https://blog.unity.com/engine-platform/il2cpp-internals-debugging-tips-for-generated-code

这是 IL2CPP Internals 系列的第三篇博文。在本篇博文中,我们将探讨一些技巧,让调试 IL2CPP 生成的 C++ 代码变得更容易一些。我们将了解如何设置断点、查看字符串和用户定义类型的内容以及确定异常发生的位置。

当我们进入这个问题时,请考虑到我们正在调试由 .NET IL 代码生成的 C++ 代码。因此,调试它可能不会是最愉快的体验。不过,只要掌握了其中的一些技巧,就有可能深入了解 Unity 项目的代码在实际目标设备上的执行情况(我们将在本篇文章的最后谈谈托管代码的调试)。

此外,请做好准备,您的项目中生成的代码可能与此代码不同。随着 Unity 的每一个新版本的推出,我们都在想方设法使生成的代码更好、更快、更小。

The setup

在这篇文章中,我使用的是 OSX 上的 Unity 5.0.1p3。我将使用与 "生成代码 "一文中相同的示例项目,但这次我将使用 IL2CPP 脚本后台构建 iOS 目标。与上一篇文章一样,我将在构建时选择 "Development Player "选项,这样 il2cpp.exe 就会根据 IL 代码中的名称生成带有类型和方法名称的 C++ 代码。

Unity 生成 Xcode 项目后,我可以在 Xcode 中打开它(我使用的是 6.3.1 版,但任何最新版本都可以),选择目标设备(iPad Mini 3,但任何 iOS 设备都可以),然后在 Xcode 中构建项目。

Setting breakpoints

在运行项目之前,我首先要在 HelloWorld 类中的 Start 方法顶部设置一个断点。正如我们在上一篇文章中所看到的,在生成的 C++ 代码中,该方法的名称是 HelloWorld_Start_m3。我们可以使用 Cmd+Shift+O 开始键入该方法的名称,以便在 Xcode 中找到它,然后在其中设置断点。

Untitled

我们还可以在 XCode 中选择 "调试 > 断点 > 创建符号断点",并将其设置为在此方法处断开。

Untitled

现在,当我运行 Xcode 项目时,我立即看到它在方法的开始处中断了。

如果我们知道方法的名称,就可以像这样在生成代码中的其他方法上设置断点。在 Xcode 中,我们还可以在生成的代码文件中的某一行设置断点。事实上,所有生成的文件都是 Xcode 项目的一部分。您可以在项目导航器中的 Classes/Native 目录下找到它们。

Untitled

Viewing strings

有两种方法可以在 Xcode 中查看 IL2CPP 字符串的表示。我们可以直接查看字符串的内存,或者调用 libil2cpp 中的字符串实用程序之一将字符串转换为 std::字符串,以便 Xcode 显示。让我们来看看名为 _stringLiteral1 的字符串的值(剧透:其内容为 "Hello, IL2CPP!")。

在内置 Ctags 的生成代码中(或在 Xcode 中使用 Cmd+Ctrl+J),我们可以跳转到 _stringLiteral1 的定义,看到其类型是 Il2CppString_14:

struct Il2CppString_14
{
	Il2CppDataSegmentString header;
	int32_t length;
	uint16_t chars[15];
};

事实上,IL2CPP 中的所有字符串都是这样表示的。您可以在 object-internals.h 头文件中找到 Il2CppString 的定义。这些字符串包括 IL2CPP 中任何托管类型的标准头文件 Il2CppObject(可通过 Il2CppDataSegmentString 类型定义访问),然后是一个四字节长度的字符串,接着是一个由两个字节字符组成的数组。在编译时定义的字符串(如 _stringLiteral1)最终使用固定长度的字符数组,而在运行时创建的字符串则使用分配的数组。字符串中的字符以 UTF-16 编码。