# Windows 调试

> Debug native C++ and managed C# game and Editor processes on Windows using Program Database symbols.

Unity 提供了几个在 Windows 上进行调试的选项，从而方便进行游戏或编辑器进程的取证或实时调试。Unity 允许两种类型的调试：原生 C++ 调试和 C# 托管调试。

* 原生调试将相关二进制文件（例如 exe 和 dll）的符号存储在程序数据库 (PDB) 中。
* 在 Windows 上，标准 .NET 托管符号也存储在 PDB 文件中，扩展名为 a .pdb。

## 符号

您可以使用 Unity 的[符号商店](http://symbolserver.unity3d.com/)在 Windows 调试器 (WinDbg) 或 Visual Studio 2019 及更高版本中访问 Unity 服务器 URL，从而自动解析和下载符号。

### Windows 调试器 (WinDbg) 设置

要在 WinDbg 上添加符号存储，请使用 `.sympath` 命令：

> `.sympath+ SRV*c:\symbols-cache*http://symbolserver.unity3d.com/`

其中： > `.sympath+`

* 添加操作，仅保留现有的符号路径，并附加此符号存储库查找。

> `SRV*c:\symbols-cache`

SRV 表示用于获取符号的远程服务器，而 `c:\symbols` 是本地路径，用于缓存下载的符号并在再次下载之前先查看该位置。

> `*http://symbolserver.unity3d.com/`

用于获取符号的符号存储库的路径。

### Visual Studio 设置

要配置 Visual Studio 进行调试，请执行以下步骤：

1. 前往**工具 (Tools) > 选项 (Options)**。
2. 展开**调试 (Debugging)** 部分，然后选择**符号 (Symbols)**。
3. 指定缓存目录（如果尚未指定）。
4. 添加 **Symbol 文件 (.pdb) 位置**，例如 Unity 的[符号商店](http://symbolserver.unity3d.com/)。

## 实时调试

实时调试是将调试器连接到已在运行的进程或连接到已捕获异常的进程的方案。要使调试器发现问题，必须使用 [Visual Studio 设置](#vs-setup)部分中所述的步骤在构建中包含符号。此外，如果游戏可执行文件的名称与游戏名称相同，调试器可能会在查找正确的 `.pdb` 文件时出现问题，尤其是在无法访问重命名的可执行文件时。

#### 设置自动异常调试

在 Windows 上，Microsoft 会自动设置应用程序崩溃，以发送到 Dr Watson/向 Microsoft 报告错误。但是，如果安装了 Visual Studio 或 WinDbg，Microsoft 会提供选项来改为选择[调试崩溃](https://msdn.microsoft.com/en-us/library/windows/desktop/bb204634\(v=vs.85\).aspx)。

按照以下注册表文件内容进行安装：

```
Windows Registry Editor Version 5.00
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AeDebug]
 "Auto"="1"
[HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows NT\CurrentVersion\AeDebug]
 "Auto"="1"
```

编辑器调试的其他内容：

> `Unity.exe -dbgbreak`

将会启动 Unity 并立即提供要连接的调试器（如果设置了自动崩溃处理）。

### 事后分析/取证调试

Windows 提供了调查故障转储文件（.dmp 或 .mdmp）的工具。根据崩溃转储，您可能会看到堆栈信息或整个进程内存。转储文件的内容决定了崩溃的原因，通常至少有一个堆栈要调查（只要是有效堆栈）。

要调查转储文件，可以通过 Visual Studio 或 WinDbg 来加载该文件。虽然 Visual Studio 易于使用，但 WinDbg 提供了其他功能，使其成为首选的调试工具。

### 调试提示和技巧

在运行 Visual Studio 时，您可以使用 [UnityMixedCallstack](https://github.com/Unity-Technologies/UnityMixedCallstack) 扩展来实现 Unity 的 VS Code，使调试更加容易。

#### 在本机托管的异常

`NullReferenceException` 通常如下所示：

```
    1b45558c()	
&gt;	mono-2.0-bdwgc.dll!malloc(unsigned int size=12)  Line 163 + 0x5f bytes	C  
    mono-2.0-bdwgc.dll!g_hash_table_insert_replace(_GHashTable * hash=0x065c3960, void * key=0x0018cba4, void * value=0x0018cb8c, int replace=457528232)  Line 204 + 0x7 bytes	C  
 	mono-2.0-bdwgc.dll!mono_jit_runtime_invoke(_MonoMethod * method=0x242bf8b0, void * obj=0x065c3960, void ** params=0x0018cba4, MonoObject * * exc=0x0018cb8c)  Line 4889 + 0xc bytes	C  
```

#### 托管堆栈帧

托管堆栈帧通常如下所示：

```
    1b45558c()	
&gt;	mono-2.0-bdwgc.dll!malloc(unsigned int size=12)  Line 163 + 0x5f bytes	C  
    mono-2.0-bdwgc.dll!g_hash_table_insert_replace(_GHashTable * hash=0x065c3960, void * key=0x0018cba4, void * value=0x0018cb8c, int replace=457528232)  Line 204 + 0x7 bytes	C  
 	mono-2.0-bdwgc.dll!mono_jit_runtime_invoke(_MonoMethod * method=0x242bf8b0, void * obj=0x065c3960, void ** params=0x0018cba4, MonoObject * * exc=0x0018cb8c)  Line 4889 + 0xc bytes	C  
```

不含任何信息的行即为托管帧。您可以在 mono 中使用其名为 `mono_pmip` 的内置函数途径获取托管堆栈信息，该函数接受堆栈帧的地址并返回附带信息的 char\*。可在 Visual Studio 即时窗口中调用 `mono_pmip` 进行调试。

> `?(char*){,,mono-2.0-bdwgc.dll}mono_pmip((void*)0x1b45558c)`

0x26a296c0 " Tiles:OnPostRender () + 0x1e4 (1B4553A8 1B4555DC) \[065C6BD0 - Unity Child Domain]"\`

\*\*注意：\*\*这仅适用于 `mono-2.0-bdwgc.dll` 符号正确加载的情况。

#### 强制应用程序创建转储

偶尔，即使已连接调试器，应用程序也不会崩溃，或者在调试器不可用的远程设备上崩溃。在这种情况下，可使用以下步骤从转储文件获取有用信息：

**注意：**这些说明同时适用于 **Windows 独立**平台和**通用 Windows** 平台（在桌面端运行时）。

1. 打开 Windows 注册表。

2. 导航至 `HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\Windows Error Reporting`。

3. 创建 `LocalDumps` 文件夹（如果不存在）。

4. 添加以下注册表项：

   * `"DumpFolder"=<FolderPath goes here> , e.g., C:\Temp`
   * `“DumpCount”=dword:00000010`
   * `“DumpType”=dword:00000002`

5. 通过通用 Windows 平台或 Windows 独立可执行文件启动应用程序。

6. 重现崩溃。转储文件是在先前指定的文件夹中创建的。您可以使用首选调试工具（例如 Visual Studio 或 WinDbg）打开转储文件。
