I can still remember the first time I encountered PDB files. “Should I be concerned about PDB files?” and was quickly replied to as “it’s just another file used in the debugging process”, by a colleague. Till yesterday, I had the same definition with me. Let me share with you what more I found about it.
A PDB (Program Data Base) file generated by Visual Studio is used by a debugger and it contains mapping information. It maps the identifier and the statements in the source code to the ones present in the generated executable or DLL. Out of this mapping information, it concludes two pieces of information: the source file name and the line number that is displayed in the Visual Studio IDE; and the location in the executable to stop at when you set a breakpoint. (If you want to programmatically inspect the PDF file, take a look at Marc's article.)
The debugger in order to find the matching PDB file, looks for PDB file having the same name as executable/DLL. If the DLL is named as “Web.dll”, the debugger looks for “Web.pdb”. Another piece of information that makes the PDB file as the exact match for the binary, is by the use of a GUID that’s embedded in both the PDB file and the binary. The process of compilation puts the GUID into the binary and PDB. The debugger loads only a PDB file for an executable that exactly matches the PDB file that was created when the executable was built. Now if we lose the PDB files for some build, then we won’t be able to debug that build. For this, we can setup a Symbol Server that stores the PDBs and binaries.
In order to find the correct PDB file, the debugger searches for it at these locations:
- The debugger first checks inside the location that is specified inside the DLL or the executable file. This happens at the time of build when the linker places the full path and file name of the associated PDB file inside the DLL or the executable file.
- Then it searches inside the directory where the DLL or executable file, is present.
- If it is not found in the above two locations, it checks for the presence of any symbol sever setup for the machine. If yes, it looks inside the symbol server cache directory.
- If the PDB is not found in the cache, it then looks inside the symbol server.
After getting the correct PDB file, now the debugger searches for the source file, it looks for it at these locations in the following order:
- Any files that are opened in the Visual Studio instance that launched the debugger.
- Inside the solution folder that is opened in the Visual Studio instance that launched the debugger.
- Directories that are specified in the Common Properties / Debug Source Files page in the properties of the solution.
- The matched PDB file also contains the original location of the source file or it can be a command to a source server from where it can be retrieved.
A PDB file gets generated both in case of “Debug” and “Release” builds. Yes, for “Release” builds also, it gets generated by default. However, there’s less information in a “Release” build than in a “Debug” build anyway. But we can also control its generation from “Project Properties -> Build -> Advanced…-> Output -> Debug Info”. Three options are available “none”, “full” and “pdb-only”. One difference between “full” and “pdb-only” is that with “pdb-only” selected, the compiler emits the DebuggableAttribute ( which tells the JIT compiler that debug information is available) and the generated PDB file allows viewing of information such as source file names and line numbers in the application’s stacktrace. One thing to keep in mind while using “full” option is that, you will get an error if your code contains the “
DebuggableAttribute” set to
false and we select the “
full” option. (John Robbins has shared some different views about the differences. I will hold on to the MSDN info till I get some new updates. Surely, you can share with me your findings.) Also, the generation of PDBs have zero performance impact.
Another benefit that PDBs give is a detail stack trace report for a crash. In order to better understand, let's create an ASP.NET empty web application, named as “
PDBDemo”. To this project, add an aspx page, named as “TestPage.aspx” and to the “
Page_Load()” event handler, add a line of code to throw an exception.
public partial class TestPage : System.Web.UI.Page
protected void Page_Load(object sender, EventArgs e)
throw new ApplicationException();
And this is the result we got with and without the presence of a PDB file.
Certainly we won't be showing the ASP.NET yellow page of death to the end user. But the log files will be missing the line number and the source path, which can help us to zero in and fix the issue.
In my opinion, it's always good to generate PDBs for the “Release” builds. It is not that we need to have PDBs along with binaries deployed to get that extra information about the exception. The same can also be achieved using Symbol Server and Source Indexing. To conclude, for me, the PDBs are as valuable as the source code.
Filed under: .NET Framework
, Visual Studio
Tagged: .NET Framework
, Visual Studio