使用 Android 游戏开发扩展时,通过 Visual Studio 调试器 (LLDB) 调试您的项目。
运行调试器
在运行调试器之前,您必须能够在 Android 上构建、部署和运行您的游戏。有关详细信息,请参阅“运行示例”部分。
确认您可以在不使用调试器的情况下运行游戏后,您可以按 F5 或在调试菜单中选择开始调试项来使用调试器。调试器附加到游戏时,您应该会看到一个对话框。
启动调试器需要 10 秒到 1 分钟或更长时间,具体取决于应用大小以及启动时需要加载的符号数量。首次附加到新设备时会花费更多时间,因为调试器必须将一些 Android 库从设备下载到主机。如果首次在新设备上尝试时花费了 1 分钟以上,请考虑取消调试会话,然后重新启动。
以这种方式运行调试器时,游戏会以等待调试器模式启动,并且在调试器连接之前,游戏不会执行任何代码。这使您还可以调试游戏的初始化部分。
您可以通过阅读 Visual Studio 文档,找到有关特定 Visual Studio 调试器功能的更多信息。
附加到进程
如果要调试已在物理设备或虚拟设备上运行的游戏,可以从 Visual Studio 将调试器附加到该进程。
在 Visual Studio 中,确保已打开 Android 解决方案,然后
- 转到调试菜单,然后选择附加到进程...。
- 从传输下拉列表中,选择 Android 游戏开发扩展。
- 从限定符下拉列表中,选择您的 Android 设备。
- 从可用进程列表中选择游戏进程,然后点击附加。
执行 LLDB.Shell 命令
在调试会话处于活动状态时,使用 Visual Studio 的命令窗口运行 LLDB.Shell 命令。
命令格式
LLDB.Shell [command]
示例
>LLDB.Shell expr myIntVariable = 9
Status: Success
Output Message:
(int) $2 = 9
数据可视化
格式说明符
您可以使用格式说明符更改自动、局部变量、监视和变量数据提示窗口中值的显示格式。
格式说明符位于表达式的末尾。它们以逗号开头,后跟一个短字符串。例如,表达式 _myInt,x
中的 ,x
说明符会将 myInt 格式化为小写十六进制。
格式说明符可以直接在监视窗口中使用,也可以通过将其添加到 Natvis 表达式中,在自动、局部变量和数据提示窗口中使用。有关详细信息,请参阅 Natvis。
支持的说明符列表
格式名称 | 说明符 | 说明 |
---|---|---|
布尔值 | B | 将此显示为 true/false 布尔值,通常规则是 0 为 false,其他所有值都为 true |
二进制 | b | 将此显示为位序列 |
二进制,无前导 0b | bb | 将此显示为不带 0b 前缀的位序列 |
字节 | y | 显示字节,但同时尝试将其显示为 ASCII 字符 例如:(int *) c.sp.x = 50 f8 bf 5f ff 7f 00 00 P.._.... |
带 ASCII 的字节 | Y | 显示字节,但同时尝试将其显示为 ASCII 字符 例如:(int *) c.sp.x = 50 f8 bf 5f ff 7f 00 00 P.._.... |
字符 | c | 将字节显示为 ASCII 字符 例如:(int *) c.sp.x = P\xf8\xbf_\xff\x7f\0\0 |
可打印字符 | C | 将字节显示为可打印 ASCII 字符 例如:(int *) c.sp.x = P.._.... |
复浮点数 | F | 将此值解释为复浮点数的实部和虚部 例如:(int *) c.sp.x = 2.76658e+19 + 4.59163e-41i |
十进制 | d, i | 将此显示为带符号整数(不执行类型转换,仅将字节显示为带符号整数) |
枚举 | E,en | 将此显示为枚举,如果可用则打印值的名称,否则打印整数值 例如:(enum enumType) val_type = eValue2 |
十六进制 - 小写 | x, h | 以小写十六进制表示法显示(不执行类型转换,仅将字节显示为十六进制) |
十六进制 - 大写 | X, H | 以大写十六进制表示法显示(不执行类型转换,仅将字节显示为十六进制) |
十六进制 - 小写,无前导 0x | xb, hb | 以不带 0x 前缀的小写十六进制表示法显示(不执行类型转换,仅将字节显示为十六进制) |
十六进制 - 大写,无前导 0x | Xb, Hb | 以不带 0x 前缀的大写十六进制表示法显示(不执行类型转换,仅将字节显示为十六进制) |
浮点数 | f | 将此显示为浮点数(不执行类型转换,仅将字节解释为 IEEE754 浮点值) |
八进制 | o | 以八进制表示法显示 |
操作系统类型 | O | 将此显示为 MacOS OSType 例如:(float) x = '\n\x1f\xd7\n' |
字符串 - C 字符串 | s | 将此显示为以 0 终止的 C 字符串 例如:“hello world” |
字符串 - C 字符串,无引号 | sb | 将此显示为不带引号的以 0 终止的 C 字符串, 例如:hello world |
字符串 - UTF-8 | s8 | 将此显示为以 0 终止的 UTF-8 字符串 例如:u8"hello world ☕" |
字符串 - UTF-8,无引号 | s8b | 将此显示为不带引号的以 0 终止的 UTF-8 字符串 例如:hello world ☕ |
字符串 - UTF-16 | su | 将此显示为以 0 终止的 UTF-16 字符串 例如:u"hello world ☕" |
字符串 - UTF-16,无引号 | sub | 将此显示为不带引号的以 0 终止的 UTF-16 字符串 例如:hello world ☕ |
字符串 - UTF-32 | s32 | 将此显示为以 0 终止的 UTF-32 字符串 例如:U"hello world ☕" |
字符串 - UTF-32,无引号 | s32b | 将此显示为不带引号的以 0 终止的 UTF-32 字符串 例如:hello world ☕ |
Unicode16 | U | 将此显示为 UTF-16 字符 例如:(float) x = 0xd70a 0x411f |
Unicode32 | U32 | 将此显示为 UTF-32 字符 例如:(float) x = 0x411fd70a |
无符号十进制 | u | 将此显示为无符号整数(不执行类型转换,仅将字节显示为无符号整数) |
指针 | p | 将此显示为原生指针(除非这确实是一个指针,否则结果地址可能无效) |
复整数 | I | 将此值解释为复整数的实部和虚部 例如:(int *) pointer = 1048960 + 1i |
字符数组 | a | 将此显示为字符数组 例如:(char) *c.sp.z = {X} |
原始格式 | ! | 原始格式,忽略任何数据类型视图自定义 |
Natvis
Natvis 框架允许您自定义 Visual Studio 在调试器变量窗口中显示原生类型的方式。例如,可以使用 Natvis 自定义监视、局部变量和数据提示窗口的显示。
Natvis 功能默认启用,但您可以通过在 Visual Studio 中将工具 > 选项 > Android 游戏开发扩展 > Natvis 标志设置为已停用来将其停用。
加载 Natvis 文件
Visual Studio 从下面列出的三个位置加载 Natvis 文件,并在每次启动调试会话时重新加载它们。文件必须符合 Visual Studio 2017 Natvis 架构。
- 作为已加载项目或顶级解决方案项一部分的
.natvis
文件。 - 用户特定目录 (
%USERPROFILE%\Documents\Visual Studio 2017\Visualizers
) - 系统范围目录 (
%VSINSTALLDIR%\Common7\Packages\Debugger\Visualizers
)
重新加载 Natvis 文件
在调试会话期间,通过在命令窗口或监视窗口中评估 .natvisreload
来重新加载 Natvis 文件。
Natvis 示例文件
此 Natvis 示例文件包含目前支持的所有标签和属性。
<?xml version="1.0" encoding="utf-8"?>
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
<Type Name="demo::Vector<*>">
<AlternativeType Name="MySimilarVectorType<*>"/>
<!-- Included to show the <SmartPointer> feature is supported. -->
<SmartPointer Optional="true" Usage="Minimal">ptr</SmartPointer>
<!-- Included to show the <DisplayString> feature is supported. -->
<DisplayString Condition="_size == 0" Optional="true">()</DisplayString>
<DisplayString Condition="_size == 1">(x={_items[0]})</DisplayString>
<DisplayString Condition="_size == 2">(x={_items[0]}, y={_items[1]})</DisplayString>
<DisplayString Condition="_size == 3">(x={_items[0]}, y={_items[1]}, z={_items[2]})</DisplayString>
<DisplayString>[Size={_size,x}] (x={_items[0]}, y={_items[1]}, z={_items[2]}, ...)</DisplayString>
<!-- Included to show the <StringView> feature is supported. -->
<StringView Condition="true" Optional="true">_stringViewText</StringView>
<Expand HideRawView="false">
<!-- Included to show the <Item> feature is supported. -->
<Item Name="X" Condition="_size < 4 && _size >= 1" Optional="true">_items[0]</Item>
<Item Name="Y" Condition="_size < 4 && _size >= 2" Optional="true">_items[1]</Item>
<Item Name="Z" Condition="_size < 4 && _size >= 3" Optional="true">_items[2]</Item>
<!-- Included to show the <ArrayItems> feature is supported. -->
<ArrayItems Condition="_size >= 4" Optional="true">
<Size Condition="true" Optional="true">_size</Size>
<ValuePointer Condition="true">_items</ValuePointer>
</ArrayItems>
<!-- Included to show the <IndexListItems> feature is supported. -->
<IndexListItems Condition="true" Optional="true">
<Size Condition="true" Optional="true">_listSize</Size>
<ValueNode Condition="true">_list[%i]</ValueNode>
</IndexListItems>
<!-- Included to show the <LinkedListItems> feature is supported. -->
<LinkedListItems Condition="true" Optional="true">
<Size Optional="true">_listSize</Size>
<HeadPointer>_head</HeadPointer>
<NextPointer>_next</NextPointer>
<ValueNode>_value</ValueNode>
</LinkedListItems>
<!-- Included to show the <ExpandedItem> feature is supported. -->
<ExpandedItem Condition="true" Optional="true">_childVar</ExpandedItem>
<!-- Included to show the <Synthetic> feature is supported. -->
<Synthetic Name="[Size]" Condition="true" Optional="true">
<DisplayString>_size</DisplayString>
<Expand HideRawView="true">
<!-- Any supported <Expand> sub-tags. -->
</Expand>
</Synthetic>
<!-- Included to show the <TreeItems> feature is supported. -->
<TreeItems Condition="true" Optional="true">
<Size>_treeSize</Size>
<HeadPointer>_head</HeadPointer>
<LeftPointer>_left</LeftPointer>
<RightPointer>_right</RightPointer>
<ValueNode>_value</ValueNode>
</TreeItems>
<!-- Included to show format specifiers are supported. -->
<Item Name="[Hex Dump at {_index,x}]">myInt[_index],x</Item>
</Expand>
</Type>
</AutoVisualizer>
编写 Natvis 文件
Visual Studio 支持自行编写 Natvis 文件。有关自定义调试器变量窗口的详细信息,请参阅 MSDN。
调试 Natvis 文件
在某些情况下,错误会以变量值的形式显示(例如,在自动、监视等窗口中)。例如:<error: use of undeclared identifier 'missingVar'>
您可以通过从 Android 游戏开发扩展工具栏中打开 GoogleAndroid.log
文件来访问有关错误的更多详细信息。
已知限制
如果您的标签或属性未在上面的示例文件中列出,则表示目前不支持。Visual Studio 会忽略不受支持的标签和属性,因此您可以将其保留在现有的 Natvis 文件中,只要该文件使用我们的架构,它就会正常工作。
尽管架构要求
Usage
属性,但它不受<SmartPointer>
支持。然而,LLDB 不限制对 C++ 中定义的操作符的访问,因此任何所需的操作符都可以在 C++ 中定义。