Converting .pdb files to .mdb for Unity3D.
TL;DR: For in-depth info skip to next paragraph. Use the standalone pdb2mdb.exe converter:
"<PATH_TO_EXE_DIR>\pdb2mdb.exe" MyAssembly.dll
to create MyAssembly.dll.mdb from the MyAssembly.pdb which must be in the same directory as the DLL. Optionally if VSTU are installed you can import the DLL and PDB into Unity to generate the MDB file from Unity.
Introduction
With people working in Unity3D I often see a certain pattern regarding script files in the project. You could say it is the life cycle of scripts. It’s all about having a clean project structure, make code reusable and keep compile times small.
- Scripts live in the Unity Assets directory and compile happily when any other script changes.
- Some scripts get pushed to the Assembly-CSharp-firstpass.dll (explained below) so there are two separate compiled assemblies and not everything has to recompile.
- Scripts get compiled to a DLL outside of Unity and imported into the project as managed DLLs
The second step is often skipped. To get Unity to compile your code into the Assembly-CSharp-firstpass.dll you have to place your scripts in a special directory. Unity explains it in their manual (Special Folders and Script Compilation Order). By the way this is extra useful when you have a Unity plugin that does not change often.
Of course the 3rd step is the most important for this post. You throw all your code into Visual Studio and compile a DLL out of it. Hooray. You throw the DLL anywhere in your projects Assets directory and your code is available to your scripts that are inside the Assets directory.
Everything seems fine, but when you get an error inside your DLL, Unity cannot tell you where exactly the error occurred. Debugging code inside the DLL is not working. Unity needs to know the debug symbols of your DLL code. Visual Studio generates a PDB (program database) file next to your DLL. This file has everything to track compiled code back to the source file. So we are good right? No. Unfortunately Unity cannot read this format because Unity is using the mono compiler and debugger. Unity wants a MDB (Mono debug information) file that we can generate from the PDB file.
Generating MDB from PDB
The Unity documentation touches on this very shortly (Managed Plugins->Setting Up a Debugging Session for the DLL). Unfortunately at the time of this writing the documentation is outdated and sparse. First of all the documentation states that you have to copy the MDB files into the Assets/Plugins directory. This is not the case with managed plugins. Since Unity 5 it is not even the case with native plugins because Unity now has a plugin importer (Previously the directory naming (e.g. Plugins/iOS) defined where native plugins are used.). Next, running the proposed command %UNITY_PATH%\Editor\Data\Mono\lib\mono\2.0\pdb2mdb.exe
on Windows will result in an error:
Microsoft.Cci.Pdb.PdbDebugException: Unknown custom metadata item kind: 6
or
Unhandled Exception: System.IO.FileNotFoundException: Could not load file or assembly 'Mono.Cecil, Version=0.9.5.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756' or one of its dependencies. The system cannot find the file specified.
Just recently Josh solved this issue in a forum post.
The problem is that the pdb2mdb.exe is executed using the .NET framework. But the .exe was actually build with the Mono framework. So this gives us the problem. The solution is to call the pdb2mdb.exe with the Mono runtime. Josh proposes to either use the direct call:
"C:\Program Files\Unity\Editor\Data\MonoBleedingEdge\bin\mono" "C:\Program Files\Unity\Editor\Data\MonoBleedingEdge\lib\mono\4.5\pdb2mdb.exe" <assembly to convert>
Or download a standalone exe file that wraps the pdb2mdb and calls it with mono. I believe it is the latest and greatest directly from the Mono project. You can find it here.
I think the first solution is the better one because you don’t have to manage a separate version of pdb2mdb.exe on every dev machine. Unfortunately the first version isn’t working with Visual Studio 2015. Microsoft changed the layout of the PDB files in VS2015 and the pdb2mdb converter delivered with Unity can’t handle it. If using VS2015 you have no other choice than to use the standalone exe file that is updated to understand the VS2015 PDB file layout until Unity updates: "<PATH_TO_EXE_DIR>\pdb2mdb.exe" MyAssembly.dll
You can now copy the DLL and the MDB into your Unity project. Debugging and line numbers in stack traces should work.
The VSTU (Visual Studio Tools for Unity) already have the standalone pdb2mdb converter from above on board. If you have the VSTU installed you can import the DLL and PDB into Unity which will create the MDB file automatically. You could delete the PDB files in the project. But they don’t harm anyone. They are only included in development builds.
If you have any questions, please ask them in the comments section. I will keep this post updated if the landscape of this topic changes.