<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://blogs.msdn.com/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>Rick Byers : PDBs</title><link>http://blogs.msdn.com/rmbyers/archive/tags/PDBs/default.aspx</link><description>Tags: PDBs</description><dc:language>en-US</dc:language><generator>CommunityServer 2.1 SP1 (Build: 61025.2)</generator><item><title>My school assignment required parsing PDB files</title><link>http://blogs.msdn.com/rmbyers/archive/2009/06/09/university-of-washington-class-assignment-requires-parsing-pdb-files.aspx</link><pubDate>Tue, 09 Jun 2009 20:15:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9716684</guid><dc:creator>rmbyers</dc:creator><slash:comments>3</slash:comments><comments>http://blogs.msdn.com/rmbyers/comments/9716684.aspx</comments><wfw:commentRss>http://blogs.msdn.com/rmbyers/commentrss.aspx?PostID=9716684</wfw:commentRss><description>&lt;P&gt;I'm just finishing up my Masters in Computer Science, and was surprised when I recently got an &lt;A href="http://pbradley.fhcrc.org/genome541/" mce_href="http://pbradley.fhcrc.org/genome541/"&gt;assignment&lt;/A&gt; that involved parsing PDB files.&amp;nbsp; Over the years I've been involved in many discussions about why the Microsoft PDB format isn't public.&amp;nbsp; John Robbins recently went as far as to say "&lt;A href="http://www.wintellect.com/CS/blogs/jrobbins/archive/2009/05/11/pdb-files-what-every-developer-must-know.aspx" mce_href="http://www.wintellect.com/CS/blogs/jrobbins/archive/2009/05/11/pdb-files-what-every-developer-must-know.aspx"&gt;The actual file format of a PDB file is a closely guarded secret&lt;/A&gt;", but that's probably and overstatement given that the &lt;A href="http://ccimetadata.codeplex.com/" mce_href="http://ccimetadata.codeplex.com/"&gt;CCI&lt;/A&gt; code which contains a C# managed-PDB reader has now been released on CodePlex.&amp;nbsp; So needless to say, I didn't expect to be having to parse PDB files for school ... especially in a computational biology class.&lt;/P&gt;
&lt;P&gt;Ok, so if you do a web-search now for "&lt;A href="http://www.bing.com/search?q=PDB+file+format&amp;amp;form=QBRE" mce_href="http://www.bing.com/search?q=PDB+file+format&amp;amp;form=QBRE"&gt;PDB file format&lt;/A&gt;", the first hit you get isn't for &lt;A href="http://en.wikipedia.org/wiki/Program_database" mce_href="http://en.wikipedia.org/wiki/Program_database"&gt;Microsoft's Program Database file format&lt;/A&gt;, but for the &lt;A href="http://www.wwpdb.org/docs.html" mce_href="http://www.wwpdb.org/docs.html"&gt;Protein Data Bank file format&lt;/A&gt;.&amp;nbsp; Who ever came up with the idea that file types should be uniquely determined by a 3-letter extension that isn't coordinated by any central registry anyway?&amp;nbsp; Now I've got to decide which way I want windows to treat PDB files (and both have been pretty important to me lately):&lt;/P&gt;
&lt;P&gt;&lt;A href="http://blogs.msdn.com/blogfiles/rmbyers/WindowsLiveWriter/UniversityofWashingtonclassassignmentreq_9918/pdb1_2.png"&gt;&lt;IMG style="BORDER-BOTTOM: 0px; BORDER-LEFT: 0px; DISPLAY: inline; BORDER-TOP: 0px; BORDER-RIGHT: 0px" title=pdb1 border=0 alt=pdb1 src="http://blogs.msdn.com/blogfiles/rmbyers/WindowsLiveWriter/UniversityofWashingtonclassassignmentreq_9918/pdb1_thumb.png" width=206 height=54&gt;&lt;/A&gt;&amp;nbsp;&lt;/P&gt;&lt;A href="http://blogs.msdn.com/blogfiles/rmbyers/WindowsLiveWriter/UniversityofWashingtonclassassignmentreq_9918/pdb2_2.png"&gt;&lt;IMG style="BORDER-BOTTOM: 0px; BORDER-LEFT: 0px; DISPLAY: inline; BORDER-TOP: 0px; BORDER-RIGHT: 0px" title=pdb2 border=0 alt=pdb2 src="http://blogs.msdn.com/blogfiles/rmbyers/WindowsLiveWriter/UniversityofWashingtonclassassignmentreq_9918/pdb2_thumb.png" width=244 height=224&gt;&lt;/A&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9716684" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/rmbyers/archive/tags/PDBs/default.aspx">PDBs</category></item><item><title>Customizing PDB lookup for source information in StackTrace</title><link>http://blogs.msdn.com/rmbyers/archive/2007/06/21/customizing-pdb-lookup-for-source-information-in-stacktrace.aspx</link><pubDate>Fri, 22 Jun 2007 08:49:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:3453411</guid><dc:creator>rmbyers</dc:creator><slash:comments>1</slash:comments><comments>http://blogs.msdn.com/rmbyers/comments/3453411.aspx</comments><wfw:commentRss>http://blogs.msdn.com/rmbyers/commentrss.aspx?PostID=3453411</wfw:commentRss><description>&lt;P&gt;The &lt;A href="http://msdn2.microsoft.com/en-us/library/system.diagnostics.stacktrace.aspx" mce_href="http://msdn2.microsoft.com/en-us/library/system.diagnostics.stacktrace.aspx"&gt;System.Diagnostics.StackTrace class&lt;/A&gt; in .NET can be used to generate a textual representation of the current callstack.&amp;nbsp; This is used, for example, by &lt;A href="http://msdn2.microsoft.com/en-us/library/system.exception.tostring.aspx" mce_href="http://msdn2.microsoft.com/en-us/library/system.exception.tostring.aspx"&gt;Exception.ToString()&lt;/A&gt;. If requested by the caller, StackTrace can include source file locations (file names and line numbers, etc.) for each frame whose module has a &lt;A href="http://msdn2.microsoft.com/en-us/library/ms241903.aspx" mce_href="http://msdn2.microsoft.com/en-us/library/ms241903.aspx"&gt;PDB file&lt;/A&gt; available to the CLR.&amp;nbsp; PDB files are designed to be used primarily in development-time scenarios, and so the idea here is that when you're developing or testing your application and it spits out an exception (eg. to a log file, or an unhandled exception to the console), it will help you to debug the issue if you can see exactly where in the leaf method the exception was thrown, and where exactly each child function was called (actually it's not technically "exactly" - if &lt;A href="http://msdn2.microsoft.com/en-us/library/t0hfscdc(vs.71).aspx" mce_href="http://msdn2.microsoft.com/en-us/library/t0hfscdc(vs.71).aspx"&gt;JIT optimizations&lt;/A&gt; are enabled the results may be approximate, and frames may be missing completely due to inlining).&amp;nbsp; If you've done much .NET programming, you probably knew all this already.&amp;nbsp; &lt;/P&gt;
&lt;P&gt;The more interesting (and less well documented) question I want to address is where exactly you must place your PDB files for this to work.&amp;nbsp; The CLR will look next to the corresponding module (DLL or EXE), and also check a few other standard locations (those local paths specified by the _NT_SYMBOL_PATH environment variable for example, and I believe the Windows system directory).&amp;nbsp; In fact, it's not really the CLR controlling any of this, but the &lt;A href="http://msdn2.microsoft.com/en-us/library/ms230866.aspx" mce_href="http://msdn2.microsoft.com/en-us/library/ms230866.aspx"&gt;ISymUnmanagedBinder::GetReaderForFile&lt;/A&gt; API from diasymreader.dll, which itself is implemented on top of the &lt;A href="http://msdn2.microsoft.com/en-us/library/12kk9t39(VS.71).aspx" mce_href="http://msdn2.microsoft.com/en-us/library/12kk9t39(VS.71).aspx"&gt;IDiaDataSource::loadDataForExe&lt;/A&gt;&amp;nbsp;API.&amp;nbsp; Since this support for source locations is designed for development time, when you're generally running binaries you've just built - the PDBs are almost always next to the binaries and this works great.&lt;/P&gt;
&lt;P&gt;Occasionally we get requests from people who like this feature but complain that the CLR isn't flexible enough to find their PDB files where they want to put them.&amp;nbsp; Sometimes this stems from wanting to use this feature for something it wasn't designed, such as shipping PDBs with your product and logging/reporting errors from the field.&amp;nbsp; For that scenario you're usually MUCH better off using &lt;A href="http://winqual.microsoft.com/" mce_href="http://winqual.microsoft.com/"&gt;Windows Error Reporting&lt;/A&gt;&amp;nbsp;and minidumps.&amp;nbsp; You generally do not want to ship your PDBs to your customers (they're big, and can make it easier to reverse engineer your code - although this is a much bigger concern for unmanaged C++ code than .NET code).&amp;nbsp; In other cases, you may want to generate machine-readable stack traces (with module names, method tokens and IL offsets), and then post-process them using PDB files at your location to get source location information.&lt;/P&gt;
&lt;P&gt;But, there are a few scenarios where it does really make sense to want more flexibility in how PDBs are located for the StackTraces generated at runtime.&amp;nbsp; For example, I recently got a request through product support from a customer with a large test environment where they were deploying their actual product.&amp;nbsp; They keep all their PDBs (1TB+ of them!) on a &lt;A href="http://www.microsoft.com/whdc/devtools/debugging/debugstart.mspx" mce_href="http://www.microsoft.com/whdc/devtools/debugging/debugstart.mspx"&gt;symbol server&lt;/A&gt;, and they would like to be able to use them to generate stack traces with source info without having to deploy PDBs to all their test machines (in the proper directories).&amp;nbsp; Although the CLR doesn't support this directly, there isn't any reason you can't implement this yourself.&amp;nbsp; The CLR StackTrace class exposes StackFrame objects which have all the information you need to map back to source addresses given an ISymbolReader instance.&amp;nbsp; ISymbolReader instances can be created directly (controlling PDB location policy manaually with ISymbolUnmanagedBinder2::GetReaderForFile2) by calling into diasymreader.dll through COM interop.&amp;nbsp; I've posted sample code for a StackTraceSymbolProvider class that does this &lt;A href="http://blogs.msdn.com/rmbyers/pages/code-sample-stacktrace-with-manual-symbol-lookup.aspx" mce_href="http://blogs.msdn.com/rmbyers/pages/code-sample-stacktrace-with-manual-symbol-lookup.aspx"&gt;here&lt;/A&gt; (using &lt;A href="http://www.microsoft.com/downloads/details.aspx?familyid=38449a42-6b7a-4e28-80ce-c55645ab1310&amp;amp;displaylang=en" mce_href="http://www.microsoft.com/downloads/details.aspx?familyid=38449a42-6b7a-4e28-80ce-c55645ab1310&amp;amp;displaylang=en"&gt;MDbg's&lt;/A&gt; COM interop wrappers for diasymreader.dll).&amp;nbsp; &lt;/P&gt;
&lt;P&gt;Here's an example of how this code can be used to print out a StackTrace from an Exception while explicitly controlling the directories searched (searchPath is a semi-colon separated list of directories including &lt;A href="http://support.microsoft.com/kb/311503" mce_href="http://support.microsoft.com/kb/311503"&gt;SRV* entries&lt;/A&gt; for symbol servers), and whether things like a symbol server will be checked:&lt;/P&gt;&lt;PRE class=code&gt;            &lt;SPAN style="COLOR: rgb(0,0,255)"&gt;catch&lt;/SPAN&gt; (System.&lt;SPAN style="COLOR: rgb(43,145,175)"&gt;Exception&lt;/SPAN&gt; e)
            {
                st = &lt;SPAN style="COLOR: rgb(0,0,255)"&gt;new&lt;/SPAN&gt; &lt;SPAN style="COLOR: rgb(43,145,175)"&gt;StackTrace&lt;/SPAN&gt;(e, &lt;SPAN style="COLOR: rgb(0,0,255)"&gt;true&lt;/SPAN&gt;);
                &lt;SPAN style="COLOR: rgb(43,145,175)"&gt;StackTraceSymbolProvider&lt;/SPAN&gt; stsp = &lt;SPAN style="COLOR: rgb(0,0,255)"&gt;new&lt;/SPAN&gt; &lt;SPAN style="COLOR: rgb(43,145,175)"&gt;StackTraceSymbolProvider&lt;/SPAN&gt;(searchPath,
                    &lt;SPAN style="COLOR: rgb(43,145,175)"&gt;SymSearchPolicies&lt;/SPAN&gt;.AllowSymbolServerAccess |
                    &lt;SPAN style="COLOR: rgb(43,145,175)"&gt;SymSearchPolicies&lt;/SPAN&gt;.AllowOriginalPathAccess |
                    &lt;SPAN style="COLOR: rgb(43,145,175)"&gt;SymSearchPolicies&lt;/SPAN&gt;.AllowReferencePathAccess |
                    &lt;SPAN style="COLOR: rgb(43,145,175)"&gt;SymSearchPolicies&lt;/SPAN&gt;.AllowRegistryAccess);

                &lt;SPAN style="COLOR: rgb(43,145,175)"&gt;Console&lt;/SPAN&gt;.WriteLine(&lt;SPAN style="COLOR: rgb(163,21,21)"&gt;"Custom stack trace:"&lt;/SPAN&gt;);
                &lt;SPAN style="COLOR: rgb(43,145,175)"&gt;Console&lt;/SPAN&gt;.WriteLine(stsp.StackTraceToStringWithSourceInfo(st));
            }
&lt;/PRE&gt;
&lt;P&gt;To get this flexibility you have to re-implement some of the formatting done by StackTrace.ToString(), but you might want the flexibility to control this anyway (for example, it's easy to include column numbers in addition to line numbers).&amp;nbsp; It's non-trivial to wire this all up (especially if you're not familiar with &lt;A href="http://msdn2.microsoft.com/en-us/library/sd10k43k(VS.71).aspx" mce_href="http://msdn2.microsoft.com/en-us/library/sd10k43k(VS.71).aspx"&gt;COM-interop&lt;/A&gt;), but it's all plumbing really.&amp;nbsp; Hopefully &lt;A href="http://blogs.msdn.com/rmbyers/pages/code-sample-stacktrace-with-manual-symbol-lookup.aspx" mce_href="http://blogs.msdn.com/rmbyers/pages/code-sample-stacktrace-with-manual-symbol-lookup.aspx"&gt;this sample code&lt;/A&gt; will save some of you the hassle of figuring out this plumbing yourself.&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=3453411" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/rmbyers/archive/tags/CLR/default.aspx">CLR</category><category domain="http://blogs.msdn.com/rmbyers/archive/tags/PDBs/default.aspx">PDBs</category></item><item><title>DebuggingModes.IgnoreSymbolStoreSequencePoints</title><link>http://blogs.msdn.com/rmbyers/archive/2005/09/08/debuggingmodes-ignoresymbolstoresequencepoints.aspx</link><pubDate>Fri, 09 Sep 2005 03:01:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:462676</guid><dc:creator>rmbyers</dc:creator><slash:comments>3</slash:comments><comments>http://blogs.msdn.com/rmbyers/comments/462676.aspx</comments><wfw:commentRss>http://blogs.msdn.com/rmbyers/commentrss.aspx?PostID=462676</wfw:commentRss><description>&lt;P&gt;In my &lt;A href="http://blogs.msdn.com/rmbyers/archive/2005/06/26/432922.aspx" mce_href="http://blogs.msdn.com/rmbyers/archive/2005/06/26/432922.aspx"&gt;last post&lt;/A&gt;&amp;nbsp;I gave an overview of the DebuggableAttribute, what values the C# compiler gives it, and how the CLR uses those values.&amp;nbsp; I mentioned that with /debug+, the C# compiler sets the IgnoreSymbolStoreSequencePoints DebuggingModes bit, but I didn't describe what this bit does.&amp;nbsp; Understanding sequence points and ths IgnoreSymbolStoreSequencePoints bit is important for anyone writing a compiler for .NET (including one that uses Reflection.Emit).&lt;/P&gt;
&lt;P&gt;A sequence point is used to mark a spot in the IL code that corresponds to a specific location in the original source.&amp;nbsp; For Reflection.Emit, they are emitted by the ILGenerator.MarkSequencePoint method.&amp;nbsp; This serves two purposes.&amp;nbsp; First to allow debuggers (and the StackTrace class) to map IL offsets back to source and line information.&amp;nbsp; Secondly to tell the JIT compiler that it must preserve this location uniquely in the generated native code so that a user could, for example, set a breakpoint on it (see Mike's &lt;A href="http://blogs.msdn.com/jmstall/archive/2004/10/03/237137.aspx" mce_href="http://blogs.msdn.com/jmstall/archive/2004/10/03/237137.aspx"&gt;blog entry&lt;/A&gt; for more details).&amp;nbsp; &lt;/P&gt;
&lt;P&gt;Since they're only needed for debugging scenarios, the location of sequence points, and their mapping back to source locations, are stored in the PDB file.&amp;nbsp; Unfortunately this means that the JIT compiler has to open the PDB file and read this data any time it compiles a method with optimizations disabled (if JIT optimizations are enabled, then it doesn't care about sequence points in order to get the best codegen possible).&amp;nbsp; The PDB file format is quite complicated, and has a long legacy.&amp;nbsp; So as you might imagine, there is an unfortunate&amp;nbsp;performance penalty here.&lt;/P&gt;
&lt;P&gt;Now in addition to the sequence points specified in the PDB file ("explicit sequence points"), the JIT also infers additional sequence points based on the IL code ("implicit sequence points").&amp;nbsp; For example, it adds an implicit sequence at every point where the IL evaluation stack is empty, or on any&amp;nbsp;"nop" instruction.&amp;nbsp; So in Whidbey we added the IgnoreSymbolStoreSequencePoints bit to allow compilers to indicate to the JIT that they are content with the JITs rules for implicit sequence points, and there is no need for the JIT to look in the PDB file for more.&amp;nbsp; &lt;/P&gt;
&lt;P&gt;So our official recommendation is that all compilers (including those using Reflection.Emit) set the IgnoreSymbolStoreSequencePoints bit and rely on "nop" instructions to ensure the JIT places sequence points at the right place.&amp;nbsp; This can make a nice JIT performance improvement,&amp;nbsp;and also has some other benefits related to not needing to read the PDB file at JIT time (eg. it may not be available).&amp;nbsp; The Whidbey C# and VB compilers do this, but unfortunately the managed C++ compiler does not.&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=462676" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/rmbyers/archive/tags/CLR/default.aspx">CLR</category><category domain="http://blogs.msdn.com/rmbyers/archive/tags/PDBs/default.aspx">PDBs</category></item></channel></rss>