Now that Devscovery is over, it’s time to get back to answering questions about one of my favorite subjects: PDB files! Yes, I lead an extremely exciting life if PDB files set my heart racing. Maybe they have a pill for that.

In my blog post on PDBs and remote debugging Patrick asked an interesting question about .NET PDB files:

Hi John,

I find it rather strange that the PDB files for .Net applications should be on the remote machine, not the local machine.

After our release builds, we store all PDB and EXE files on a symbol server. That way we can easily debug crash dump (.DMP) files sent to us by customers.

Sometimes we use remote debugging to solve a problem at a customer (using VPN over the Internet), and for native applications, the debugger nicely gets the .PDB file from the symbol server.

However, if we would introduce .Net in our applications, would this mean that we have to send the .PDB file to our customer?

This will not only be a rather slow task (our PDB files can easily be 200 MB), but also this means that we have to give all of our debug information in the hands of our customer.

Aren’t PDB files meant to be ‘sensitive’; something that you want to keep within the walls of your company?

What do you think?

Thanks,

Patrick

While I would love to have .NET PDB files treated the same way as native PDB files we don’t have any choice in the matter as that’s just how it is. I’m sure the debugger teams at Microsoft have heard numerous comments like Patrick’s through the years. Maybe we’ll see everything fixed in a future version of Visual Studio.

Patrick is extremely lucky to be able to remote debug into a customer machines through VPN. I’m sure most of you reading would love to have that scenario! For most of us, just getting a user/admin to turn on logging and send us the output is near as hard as traveling to the moon.

Native binary PDB files are extremely sensitive. As I pointed out in my original article on PDB files, native PDB files contain the following data (if they are not stripped):

  • Public, private, and static function addresses
  • Global variable names and addresses
  • Parameter and local variable names and offsets where to find them on the stack
  • Type data consisting of class, structure, and data definitions
  • Frame Pointer Omission (FPO) data, which is the key to native stack walking on x86
  • Source file names and their lines

If you hand those over to a customer, you’ve given them everything short of source files. In fact, armed with the full native PDB file, it’s not too hard to write a tool with the public DBGHELP symbol API to write a tool that recreates your header files. If you value your job, you never want to let your native PDB files find their way outside your firewall.

.NET PDB files, on the other hand, only contain the following information:

  • Source file names and their lines
  • Local variable names

So how does the debugger know all about your .NET types? From the metadata that’s inside the binary so, there’s no need to duplicate the metadata inside a .NET PDB file. The beauty of .NET is “self describing objects” so you need much more information about your types inside the binary. The metadata is how using reflection you can load a binary you have never seen before and start instantiating it’s types. As you can imagine, that means it’s not too hard to decompile a .NET binary right back to your preferred language of choice because of that same metadata. Choosing the ease of use of .NET means you have to give up something as there is no such thing as a free lunch.

Because .NET PDB files don’t contain anything sensitive, I say give them freedom! In Patrick’s case, I’d give the .NET PDB files to the customer so he can do remote debugging of both native and .NET. All source files are loaded on the local machine where the Visual Studio UI is running so you’re not giving those up.

Preemptive comment strike: Yes, if you do something crazy dumb like embed the domain admin name and login password as part of your build path, that will show up in the .NET PDB file you give to your customers. I’m talking about the normal case here <big smile!>

In fact, I recommend that you create an installer for your .NET PDB files so you can install them into the same directory as the binaries. The debugger, either local or remote, always looks first in the directory where the binary was loaded for the matching .NET PDB file. Asking your customers to manually copy each .NET PDB file to the appropriate directories is a recipe for disaster. Installers are good things, even though the Windows Installer API is a bit painful.

Let me change my “recommend” to “extremely strongly recommend” for creating a .NET PDB file installer. Have you ever noticed an interesting difference between unhandled exceptions on your development machine and test or customer machines? When you look at the unhandled exception on your development machine, you see the call stack along with some very useful information: the source and line for each item in the call stack. On your development machine you have the local build PDB files in the same directory as the binary and the .NET StackTrace field in the Exception class automatically reads them for the source and line information. When you have a co-worker who writes 300 line methods, having the exact line massively helps in the call stack.

By having that .NET PDB file installer, you can have the customer that’s duplicating the unhandled exception install the symbols so when you dump the exception to your log you’ve got the source and line right there. That’s what I call debugging faster!

Keep in mind that every exception thrown uses the StackTrace class so there will be a bit of a performance hit when calculating the call stack because of the symbol look up. As you can guess there’s many variables that affect the performance so I can’t give you an exact number, but the fact you’ll have the exact source and line of your code in the stack means you will debug the problem faster, which, in the end, is the ultimate performance improvement.

Thanks to Patrick for an excellent question and the opportunity to show that giving .NET PDB files to your customers won’t hurt. I expect each of you to have installers for your .NET PDBs done in the next two weeks and I will be checking up on you. Please help my heart keep racing by not hesitating to ask any more questions you might have about PDB files or debugging in general!