3

I have Windbg setup properly as per MSDN. The problem is that when I get a dump file in debug mode I can see the call stack properly (symbols are loaded properly).

000000f758b6eac0 00007ffb5be60559 System.Number.StringToNumber(System.String, System.Globalization.NumberStyles, NumberBuffer ByRef, System.Globalization.NumberFormatInfo, Boolean)
000000f758b6eb20 00007ffb5b0cd791 System.Number.ParseInt32(System.String, System.Globalization.NumberStyles, System.Globalization.NumberFormatInfo)
000000f758b6ec70 00007ffafcc60214 ConsoleApplication1.Program.ConvertToInt(System.String)
000000f758b6ecb0 00007ffafcc60105 ConsoleApplication1.Program.Main()
000000f758b6f030 00007ffb5c3b4113 [GCFrame: 000000f758b6f030] 

When I get a dump file in release mode some of the information is missing, specially the method name, "ConvertToInt" which is visible on the debug mode.

00000081df98c710 00007ffafcc701e1 ConsoleApplication1.Program.Main() [C:\Written Programs\ConsoleApplication1\ConsoleApplication1\Program.cs @ 29]
00000081df98e6a8 00007ffb5c3eb915 [HelperMethodFrame: 00000081df98e6a8] 
00000081df98e790 00007ffb5be60559 System.Number.StringToNumber(System.String, System.Globalization.NumberStyles, NumberBuffer ByRef, System.Globalization.NumberFormatInfo, Boolean)
00000081df98e7f0 00007ffb5b0cd791 System.Number.ParseInt32(System.String, System.Globalization.NumberStyles, System.Globalization.NumberFormatInfo)
00000081df98e940 00007ffafcc700e0 ConsoleApplication1.Program.Main() [C:\Written Programs\ConsoleApplication1\ConsoleApplication1\Program.cs @ 23]

Am I doing something wrong here?
Plus what does HelperMethodFrame mean? In addition to this in debug mode, even without the program .pdb file, I can still see the call stack properly. What exactly is the .pdb file used for. I have read the definitions and everything, just need a practical answer on how it works with Windbg?

Thomas Weller
  • 55,411
  • 20
  • 125
  • 222
user3547774
  • 1,621
  • 3
  • 20
  • 46
  • Could you please ready my question first, before providing a generic answer. – user3547774 Jul 21 '14 at 07:36
  • @user3547774: EdChum provides valuable answers for the WinDbg topic. I'm sure he read the question. And he's right on this topic: have you tried debugging the dump on a computer where you don't have the PDBs or you have public PDBs only? – Thomas Weller Jul 21 '14 at 09:16
  • Your stacks look exactly the opposite way as they should. You have line numbers in debug build and you're missing line numbers in release build. Are you sure you didn't mix them up? Can you write an SSCCE for everyone to reproduce this behavior? – Thomas Weller Jul 21 '14 at 09:19
  • 1
    PDBs are not necessary for an accurate managed stack trace. – Steve Johnson Jul 21 '14 at 17:23

1 Answers1

7

This is entirely normal, your Release built program has the jitter optimizer enabled. Read this answer for the kind of optimizations that it performs.

Your Program.ConvertToInt() method fell victim to the first bullet in that list. It got inlined. Inlining is a very basic optimization strategy, instead of emitting a CALL to call the method, the optimizer injected the code of the method. It will occur for small methods that don't generate a lot of machine code. It is an important optimization, it can avoid having to setup the call stack and make the branch, it can easily save a handful of nanoseconds. And makes more optimizations available, including and not limited to make the entire method overhead disappear if the optimizer can determine that specific arguments makes running the code unnecessary.

The HelperMethodFrame is a deep CLR implementation detail, it occurs on so-called FCall calls into functions in the CLR. Calls that don't setup their own stack frame but piggy-back onto the program's stack frame. FCall == "fast call", mental image is of C# code directly calling native C++ code without any interop. But when that function determines that a stack frame is needed anyway in order to properly emit an exception then it dynamically builds one. No name is associated with it. There's a bit of opaque background on fcalls in this blog post.

These kind of optimizations can significantly complicate debugging Release built code of course. Which is the core reason that a Debug configuration exists, it disables optimization so the program is easier to debug. You can apply the [MethodImpl(MethodImplOptions.NoInlining)] attribute to a method to prevent it from getting inlined. Not something you ought to do profusely since it is perf killer but entirely reasonable for this kind of code since parsing strings to numbers is expensive anyway.

Community
  • 1
  • 1
Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
  • My other question is, even when I delete the .pdb file from the file system, it still displays the call stack properly in debug mode. How does this happen? – user3547774 Jul 21 '14 at 10:47
  • Hat tip to Scott Hanselman because today I learned that `[MethodImpl(MethodImplOptions.NoInlining)]` tends to work reliably in 32-bit JIT but is hit or miss when running in 64-bit mode -- http://www.hanselman.com/blog/ReleaseISNOTDebug64bitOptimizationsAndCMethodInliningInReleaseBuildCallStacks.aspx. – Tim Lewis Mar 27 '15 at 18:22