[MUSIC].
>> Hi, my name is Chuck Rees.
I'm a senior software engineer on the Visual Studio debugger.
I've been working on Visual Studio for almost 10 years now.
In that time, I've gotten to work
on some really exciting features
related to debug symbols and debug sources.
Today we're going to take a look at some of
the awesome new features in Visual Studio
2022 related to debug symbols and external code debugging,
as well as looking at some common symbol
related scenarios that you might run into in your everyday life.
Come with me, let's explore.
Debug symbols are an essential part of debugging.
Here I have a simple Console app
where I'm stopped at a break point.
I can see the local variables,
and I can see the call stack.
While the values of these local variables
are coming from the target application,
things like their names and the line info
that allows us to set this breakpoint and stop at it,
are coming from the debug symbols,
which is the PDB file.
If we want information about the symbols
that are currently loaded for the target process,
we can get this through the Modules Window,
which we find through Debug, Windows, Modules.
Here we can see every DLL that's loaded into the target process,
as well as its symbol status.
For our app DLL symbol demo
console.DLL we can see that we have loaded symbols,
and we can see that path symbols were loaded from.
This path is the build output that was
generated when we built the application as part of F5.
We can see that this module is not optimized,
while the other dotnet runtime modules are.
Therefore, our app is considered user code because we built it.
While at the dotnet runtime which we did not
build is not considered user code.
As such, we can see that through symbol status,
that symbols were not loaded for the dotnet runtime DLLs.
If we ever want more information about why symbols weren't loaded,
we can use the Context menu in
the modules window to look at Symbol Load Information.
This will give us a log or list of reasons of
where the debugger looked for
symbols or why it didn't look at all.
In this case, we can see that the option,
just my code is enabled.
Just my code is a debugger feature that keeps us
hyper-focused on only the code that we write.
We don't have to be distracted by code that we didn't write,
such as the dotnet runtime in this case.
Just my code is one of several features or
several debugger settings that can affect
symbol load behavior that we'll look at today.
Visual Studio gives us complete control over where
the debugger will look for
symbol files and whether or not they should be loaded.
These options are available through Debug, Options Symbols.
Here we've opted into Microsoft symbol servers
as well as NuGets symbol servers.
This will allow us to download symbols for
popular Microsoft dependencies and
NuGet packages from the Internet.
You can also set the location on disk where
these symbols will be downloaded and cached.
I like to use a simple short path
that I can share with other diagnostic tools
that will require symbols.
Finally, we can choose whether we always want to load symbols for
every module or if we want to
specify exactly which module symbol should be loaded for.
Using this list can help to scope down
how many symbol files are downloaded and loaded by the debugger.
Even though we've opted into load all modules
and we've selected the public symbol servers,
we can see that our current app has still not loaded
symbols for things like Newtonsoft.JSON,
or the dotnet runtime.
If we look at Symbol Load Information,
this is because just my code is enabled.
None of these dependencies were built by us,
and therefore the debugger is trying to keep us out of that code.
If we do however one to debug into external code,
we can disable just my code through Options,
General, Enable Just My Code.
Once we do this, we can see that symbols will begin
to download for external dependencies,
and now we have symbols loaded for Newtonsoft.
Once we have Just My Code disabled,
and we have symbols loaded for Newtonsoft,
we can even begin to step into its code and
download it using SourceLink from its GitHub repo.
Now we can debug into Newtonsoft.JSON and
explore or find the issue that we were originally looking for.
We can even go one step further and step
into the dotnet runtime itself, also from GitHub.
This is an easy way to debug External Code in Visual Studio.
For simple console apps,
loading all symbols at all times may work fine.
But for larger more complex apps with more external dependencies,
this can cause a performance issue on start debugging as
the debugger tries to download all symbols from the Internet.
For example, here we have an ASP.Net Core
MVC app with just my code disabled and set to load all modules.
When we start debugging we can see that
it actually takes much longer than we
would expect for the server to start.
This is because Visual Studio is downloading
symbols from the Internet for everything in the ASP.Net framework.
Normally our breakpoint would be hit by now.
We can work around this by going back to our Symbols menu and
changing from Load all modules to Load only specified modules.
All the code that we built ourselves will still be loaded.
If we want any external symbols to load we can list them here.
For now let's just start.
We'll hit our breakpoint very quickly because we're
not downloading all symbols from the Internet.
The server spins up. We see
our web page load, and we hit our breakpoint.
Now because we have JMC disabled,
because we have just my code disabled,
we can see all of the non-user code frames in the call stack.
However, none of these have symbols loaded.
If we try to navigate to one,
we will see the No Symbols Loaded page,
which gives us an explanation of why this PDB was not loaded.
In this case, it is not in our Include List.
We can load symbols directly from here.
Thanks to SourceLink, will immediately get
source code for the ASP.Net Core framework.
If we want to load symbols
automatically all the time
for any module from the call stack window,
we can right-click and say Always Load Automatically.
This will automatically add things to our symbols list.
I like to use this feature to build up the list of symbols that I
care about over time as I find them in the wild.
One of my favorite new features in Visual Studio
2022 is the debugger external sources node.
Once we start debugging,
you can see a new node appearance in
Solution Explorer called external sources.
This node allows us to view all the source files
for a given dependency and even load symbols.
Here we'll load symbols for Newtonsoft.JSON,
once the symbols load we can see
all the C# files that were built to create Newtonsoft.JSON.
We can also do this for System.Private.CoreLib.
Now it's as if we're looking at
the entire dotnet runtime GitHub repo.
In fact, we can go to System.Collections.Generic,
and even set breakpoints.
Here in dictionary.c,
we can search for the add function.
Once we find it, we can set a break point and we can run to it.
This is a great way to go exploring and read code
in external libraries that you may not be familiar with.
It's awesome for debugging and code exploration.
I'm really excited about it.
When just my code is enabled,
Visual Studio will not step into External Code.
For example, if I try to step into the dotnet dictionary class,
it will become a step over.
This is because symbols are not loaded for
the dotnet runtime and it is considered external code.
Visual Studio 2022 has
some awesome new behavior to make this experience better.
If we want to step into External Code,
we can disable just my code,
and then for performance reasons that we've discussed previously,
we'll switch to Load only specified modules.
When Visual Studio is in this symbols configuration,
it will do some awesome deferred symbol load for us.
For example, we can see that for
System.Private.CoreLib symbols are not currently loaded,
so we didn't pay the cost to load them on F5.
However, when we try to step into dictionary,
Visual Studio knows that we need
symbols it will download them automatically,
get source from SourceLink and
put us right into the dictionary class.
We can continue to step in and we can see that symbols reloaded,
and this allows us to go exploring
an external code without paying
the upfront cost of downloading and loading symbols.
This behavior is really awesome and it's
brand new in Visual Studio 2022.
Sometimes symbols just aren't
available for an external dependency.
Either they haven't been published or we don't
have access to anywhere that they were published.
These cases Visual Studio can help us by decompiling
the external dependency and showing us decompiled source code.
In this case, we can see that we have
an external dependency for which
Visual Studio could not find the PDB.
If we check out the symbol load information,
it will tell us everywhere that it looked,
but it's simply unavailable to us,
or maybe the PDB doesn't even exist anymore.
This case is we can right-click from
the modules window and choose Decompile Source to Simple File.
Once the decompilation is finished,
we can even step into our external dependency
and see decompiled source code.
We can even step through it and view values in
the watch window and all debugging simply works.
Is an awesome feature and a great way
to explore external code in Visual Studio.
One of the most important uses of
debug symbols is for dumped debugging.
Here I have a crash dump for a managed app that I made.
I didn't build the version of this app on my machine and in fact,
I don't even have the repo clone currently.
When I try to debug this with dump debugging,
it can't find the PDB.
Like I said, I didn't build it on this machine.
Luckily, this app was built through Azure DevOps.
I can see here that I use the publishsimplesteps in pipelines to
publish the symbols that we had
created to Azure DevOps symbol server.
In Visual Studio, I can go to
New Azure DevOps Symbol Server and add my Azure DevOps instance.
Once that's added, I can load symbols from Azure DevOps.
Because the application was built with
SourceLink, everything just works.
Now I can debug this silly issue that I had.
Thanks for joining me today.
In Visual Studio 2022,
we're making it the easiest it's ever been to debug
external sources through the external sources node,
deferred symbol loading and decompilation.
I also hope that you learned something about how to get
the best symbol related experience
out of Visual Studio. Happy coding.