Friday, October 11, 2019

Debugging woes with symbols: bug or feature?

I've struggled with this myself for a while during the betas of "AX7". Sometimes, symbols aren't loaded for your code and your breakpoints aren't hit. It's clear that the Dynamics 365 option "Only load symbols for your solution" has something to do with it, but still there's strange behavior. It took me a few years at Microsoft for someone to explain the exact logic there. Since I've been sitting on this knowledge for a while and I've recently ran into some customer calls where debugging trouble was brought up, I realized it's overdue for me to share this knowledge.

Summary: it's in fact a feature, not a bug. But I would like to see this behavior changed assuming we don't introduce performance regressions.

There's a piece of compiler background information that is not well understood which is actually at the root of this problem. We all know there are two ways to compile your code: from the Dynamics 365 "Full build" menu, or from the project. The project build, if you right-click on your project, has two options: build and rebuild. Now, the "rebuild" feature does NOT do the same thing as the full build menu - and that is the crux of the issue here. Both build and rebuild from the project only compile the objects in your project. Rebuild will force a build of everything in your project but not the whole package it belongs to. To do this, our Visual Studio tools and the compiler make good use of netmodules for .NET assemblies. Think of a netmodule as a sub-assembly of an assembly, I guess.

Now, the point is this. The "load symbols only for your solution" option only loads the symbols of the binaries for the objects in your project - aka the netmodules. So when you do a full build from the Dynamics 365 menu, you actually HAVE NO symbols only for the objects in your project (only the full binary of the package). And as a result after doing a full build and debugging with the "symbols for solution only" option turned on, your breakpoints will NOT be hit due to the symbols not having loaded.

I think we should change this option to work more like "load symbols for the packages containing your solution's objects" or something to that effect. We'll have to see if that affects the performance for large packages in a significant way, since it will now load all the symbols for that package. That is ultimately why this feature was introduced (see? it's a feature!). Worst case we may need a new option so you can use the old behavior or the more inclusive behavior...

I'd love to hear your thoughts on this, here or on Twitter @JorisdG.

4 comments:

  1. In my experience, in most cases when you are debugging you need symbols from other (standard) packages as well and usually you don't know what packages those are. So I always deactivate the "Load smyobls only for items in the solution" option. Downside of course is that starting a debugging session takes a long time.
    So instead of improving the behavior around that option, maybe the time would be better spent in doing a smarter dynamic loading of symbols?

    ReplyDelete
    Replies
    1. Same here!

      I do not know details where are the symbols loaded, but maybe the symbols from standard packages could be always preloaded as we do not modify this code. Only time for the reload could be when new application update is installed.

      Delete
  2. Maybe improve this by adding a bit of code on start debugging that ensures that netmodule symbols exists for all project objects? Of give a warning.

    ReplyDelete
  3. Thanks for this post, I have looked quite a bit into the various build options that we have but I always wondered what the "Build Models" was doing differently. In regards to this article, I always turn off the `Load symbols only for items in the solution`, but I tend to step through a lot of Microsoft code while trying to understand how something works. Example: trade agreement validations.

    I can see that for some teams an improvement could be made, but for myself I think I would tend to keep that unchecked so that I can follow the debugger down various rabbit holes.

    ReplyDelete