Power Debugging
Advanced .NET Debugging
John
Robbins
john@wintellect.com
who
we are
Founded
by top technical and business experts, we are a fast-growing
group of outstanding consulting and training professionals who pull
out all the stops to solve their clients’ problems.
Consulting
& Debugging
- Architecture,
analysis, and design services
- Full
Lifecycle custom software development
- Content
creation
- Project
management
- Debugging
& performance tuning |
Training
- On-site
instructor-led training
- Virtual
instructor-led training
- Devscovery
conferences |
About
the Presenter – John Robbins
- Email: john@wintellect.com
/ v-jorobb@microsoft.com
- Blog:
http://www.wintellect.com/wintellog.aspx
- Co-founder
of Wintellect
- A
consulting and education firm dedicated to helping clients ship better
software faster
- Concentrate
on debugging impossible bugs
- Author
- Debugging
Microsoft .NET 2.0 Applications,
Microsoft Press, 2006
- Debugging
Microsoft .NET and Microsoft Windows Applications,
Microsoft Press, 2003
- Debugging
Applications, Microsoft Press, 2000
- MSDN
Magazine Contributing Editor and Bugslayer Columnist
- Formerly
worked at NuMega Technologies-Engineer, Architect, and Product Manager
- BoundsChecker
(versions 3.0, 4.0 and 5.0)
- TrueTime
(versions 1.0 and 1.1)
- TrueCoverage
(version 1.0)
- SoftICE
(version 3.24)
- TrueCoverage
for Device Drivers (version 1.0)
Session
Code
- Download
all the stuff mentioned in class
- http://www.wintellect.com/downloads/DotNetDebuggingCode.zip
Prerequisites
- Build
both Debug and Release builds with PDB symbols
- Debugging
at the assembly level gets old quick (unless you get paid by the hour!)
- Set
up a company symbol server to hold your PDB files
- msdn.microsoft.com/msdnmag/issues/02/06/Bugslayer/
- Will
always keep your symbols lined up
- Set
up each machine you touch to at least use the public Microsoft symbol
servers
- See
my Set-VS2010SymbolServer.ps1 script in the session code
Turn
off Just My Code
- The
“feature” is to isolate your debugging to only code that is built
non-optimized and/or has no debugging symbols
- In
real world development, it hides way too much from you
- Disable
in Tools, Options dialog, Debugging, General property page
Setting
Debugging Properties
- Project
Properties Debug property page
- You
can set
- Command
line arguments to pass to the application
- The
working directory of the application
- If
you want remote debugging
- Native,
SQL, and hosting options
What’s
that VSHOST thing?
- Makes
debugging faster by loading your binary into an already running process
- Allows
partial trusted debugging and design time expression evaluation
- Be
aware
- AppDomain.CurrentDomain.FriendlyName
and Assembly.GetCallingAssembly().FullName will return different
values when running under the host process
- Disable
in the project properties, Debug page, by unchecking Enable the Visual
Studio hosting process
Debugging
Partially Trusted
- Now
super simple with the Security tab in the project properties
- Enable
ClickOnce Security Settings
- Select
the exact permissions your application needs
- All
debugging will be done with those permissions
- Any
security exceptions will suggest what you need to fix
Debugging
EXE Programs Without Compiling
- To
open an EXE to debug by itself
- From
the File, Open, menu, select Project/Solution
- Browse
to the EXE directory in the Open Solution dialog
- In
the Files of Type combo box, select All Project Files
- Open
the EXE
- You
now have a solution with just the EXE
- Open
source files for the project and set breakpoints just like normal
Debugging
EXE Program without Compiling
- The
type of the EXE determines what debugging will be done
- If
it’s a native EXE, native debugging is the default
- To
change
- Right
click on the EXE and select Properties
- The
dialog is actually the native debugging property page
- Change
the Debugger Type combo box
- Auto
= based on EXE type (the default)
- Mixed
= both managed and native at the same time
The
.SUO Problem
- All
settings like breakpoints, Watch window values, window layouts, and
exception settings, are stored in a hidden file,
<Solution Name>.SUO
- Occasionally,
this file can become corrupted and lead to serious problems
- Problems
caused by corrupt .SUO files
- Breakpoints
no longer hit
- Crashes
attempting to display Watch windows
- Exception
stopping no longer works
- Visual
Studio crashes when loading a solution
- If
Visual Studio is flaking out in any way
- Delete
the .SUO and that will probably clear up the problem
- Get
in the habit of saving your breakpoints!
Advanced
Breakpoints
- In
the debugging dark ages, you had to run your program until it crashed
and look at a hex dump listing because there were no breakpoints
- The
debugger renaissance age allowed you to set a breakpoint on an address
and view a disassembly
- In
the debugging modern age, setting a breakpoint on a source line was
something magical
- The
post-modern age of debugging is all about Advanced Breakpoints
Before
Setting Advanced Breakpoints
- Always
start debugging first
- If
you are not debugging, only Intellisense is used to determine the breakpoint
- Once
debugging, you have both Intellisense and symbol tables
Breakpoint
Window Codes
Glyph |
Meaning |
|
Normal
breakpoint [enabled and disabled] |
|
Advanced
BP (hit count, condition, filter) property set |
|
Mapped
BP in ASP/ASP.NET and mapped to an HTML page |
|
Normal
tracepoint |
|
Advanced
tracepoint (hit count, condition, filter) property set |
|
Mapped
TP in ASP/ASP.NET and mapped to an HTML page |
|
Breakpoint
or tracepoint error (the BP or TP will never be set) |
|
Breakpoint
or tracepoint warning (generally means the source location is not currently
in any loaded module) |
Location
Breakpoints
- Right
clicking in the margin or pressing F9 on a line sets what's called a
location breakpoint
- The
breakpoint does not trigger until that location executes
- .NET
does not support data breakpoints like native code
Advanced
Location Breakpoints
- Don't
forget about Run to Cursor
- You
can set one-shot breakpoints with it
- While
debugging, right click on the line and select Run To Cursor
- Default
keyboard keystroke: CTRL+F10
- If
you're not debugging, you'll start debugging and run to that location
Advanced
Location Breakpoints (cont.)
- Select
the location up the stack you want to stop on
- Press
F9 to set a breakpoint
- If
you right click on the stack item, you can also choose Run to Cursor
Sub
Expression Breakpoints
- You
can easily set breakpoints on sub expressions on the same line
- Clicking
the margin only sets a breakpoint on the first sub expression on the
line
- Select
the sub expression you want to stop on and press F9
- Only
that sub expression will be highlighted as a breakpoint when debugging
- The
Breakpoint window shows the character start of the sub expression
Sub
Expression Breakpoints
- When
you stop on that sub expression, it will be highlighted yellow
- Clicking
in the margin clears the breakpoints in character order
Quickly
Breaking on Any Function
- Opening
files and scrolling all over the place just to press F9 on a line is
a big waste of time
- The
debugger is smart enough to hunt down your functions for you
- The
magic is all in the Breakpoints dialog
- CTRL+B
on the default keyboard
Quickly
Breaking on Any Function (cont.)
- In
the Breakpoint dialog, Function edit control
- Type
the class name and method/property to break on
- The
name is dependent on the language
- Use
“Module.Function” for VB and C#
- Use
“Module::Function” for C++/CLI
- The
name is case sensitive for C# and C++/CLI
- Check
Use Intellisense to verify the function name
- If
debugging will use Intellisense and the symbols to find the method/property
- Set
the Language combo box to the appropriate language
- Leave
the column and line set to 1
- This
sets the breakpoint on the first instruction in the method/property
Choose
Breakpoints Dialog
- The
New Breakpoints dialog has even more smarts built into it if a project
is loaded
- Instead
of typing in the complete class and method, try just the method/property
name
- If
that method exists in any classes in the solution, the Choose Breakpoints
dialog will pop up
Choose
Breakpoints Dialog (cont.)
- From
the Choose Breakpoints dialog
- All
methods of that name from all classes are shown
- Clicking
the All button will set breakpoints on all of them
- Clicking
the check box next to an item will set or clear it
- If
you're debugging a Visual Basic project
- You
can specify the parameters in the Breakpoints dialog to skip the Choose
Breakpoints dialog
- Unfortunately,
unlike native C++, typing just the class name will not pop up the Choose
Breakpoints dialog with all the methods and parameters
- Use
the BreakpointHeler macros
Setting
Breakpoints without Source
- Interestingly,
you can set breakpoints on Framework API functions
- Or
any other assemblies you don't have source code for
- The
reason why this is cool is that you can get stopped at a known point
in the application
- It's
also a great way to learn about how things fit together in the .NET
Framework
Setting
Breakpoints without Source (cont.)
- Steps
to setting breakpoints
- Bring
up the New Breakpoints dialog
- Type
in the fully qualified name of the method or property you want to stop
on in the Function tab, Function edit control
- Don't
worry about case sensitivity
- For
properties, prefix with "get_" or "set_"
as appropriate
- Click
the Ok button
- In
Use Intellisense is checked, you'll get a message about Intellisense
not being able to set the breakpoint
- Press
OK and your breakpoint will be set
Setting
Breakpoints without Source (cont.)
- Steps
to setting breakpoints (cont.)
- Go
to the Breakpoints window and verify the breakpoint has a red circle
next to it
- If
its got a question mark or warning icon in it, the breakpoint is not
set correctly
Setting
Breakpoints without Source (cont.)
- In
the Breakpoints window you might see something interesting next to the
breakpoint
- A
“+”, indicating a root tree element you can expand
- May
not always see it, more on this later
- What
you're looking at are called "child breakpoints"
Setting
Breakpoints without Source (cont.)
- When
you run your application, you'll notice you stop in the bowels of the
jitted assembly language
- Pull
out the Call Stack window and you'll see how you got there
- The
number of child breakpoints correspond to the number of overloads for
that method
- These
breakpoints are set again when you restart debugging
Fun
with the Find Combo Box
- If
the Breakpoints dialog is too slow for you, use the Find combo box on
the toolbar
- CTRL+D
with the default keyboard (Edit.GoToFindCombo)
- Enter
the class and method/property
- Press
F9
- This
sets a breakpoint on that function/class
- If
you enter just an overloaded method/property breakpoints will be set
on all of them
Fun
with the Find Combo Box (cont.)
- You
can open system header and project files from the Find combo box
- Type
in the filename and press CTRL+SHIFT+G (Edit.OpenFile)
- Press
CTRL+SHIFT+G
- You
can issue Command window commands from the Find combo box
- Enter
">" and the Find Combo turns into a mini Command window
- Neat
Command window tricks
- Enter
“>open ” or “>of ” (notice space) followed by the first
letter of the project file you want to open
- CTRL+/
(Tools.GoToCommandLine) fills in Find Combo Box with last command executed
Location
Breakpoint Modifiers
- These
are the real power in the debugger
- The
more you practice these, the faster you'll debug
- The
idea is to make the debugger stop only when you want it to stop
- In
other words, the debugger only stops when you exactly match your hypothesis
- Supports,
hit counts, conditions, and filters
Breakpoint
Hit Count
- Skips
a breakpoint a specific number of times when running full speed
- Conditions
for skipping
- Equal
to
- Stop
only when hit count equals initial value
- Multiple
of
- Stop
every x times (think modulo)
- Greater
than or equal
- Continues
to stop after equaling initial count
Breakpoint
Hit Count Steps
- Set
a location breakpoint
- Right
click on the margin red breakpoint dot
- From
the context menu chose “Hit Count...”
- In
the Breakpoint Hit Count dialog, combo box, select the condition
- In
the edit control that appears, set the number to skip, etc.
- Click
OK
Breakpoint
Hit Count Steps (cont.)
- The
Breakpoints window will show the total execution count
- Use
it to see how far you are in loops, etc.
- You
can also reset the skip count back to zero at any time by accessing
the Breakpoint Hit Count dialog for the breakpoint
Breakpoint
Condition
- Probably
the modifier you will use the most
- Stops
when a conditional expression evaluates to true
- Also,
can stop when a variable changes
- The
source language determines the expression operators
- If
Visual Basic, “<>” is not equal, etc
- If
C#, C++/CLI, “!=” is not equal, etc
Breakpoint
Condition Steps
- Set
a location breakpoint
- Right
click on the margin red breakpoint dot
- From
the context menu choose “Condition...”
- In
the Breakpoints dialog, ensure the Condition button is checked
- Select
the "is true" radio button to stop when the condition is true
- In
the edit control type the complete expression to evaluate
- Click
OK
Breakpoint
Condition Steps (cont.)
- If
you enter just a variable in the Condition edit control and select the
"has changed" radio button
- You
can break when a variable value changes on that location
- Additionally,
you can specify hit counts to stop on the specific time the condition
is true
- The
Breakpoints window shows the condition for the breakpoint
Be
Careful Setting Breakpoint Conditionals
- Given
the following C# code:
- What
would happen if you set a conditional BP on the WriteLine with the condition
“i = 3”?
- Remember:
“i == 3” is the correct condition for C#
- My
guess would have been the conditional bug discussed two slides ago
- Nope!
You get stuck in an infinite loop!
- Isn’t
that the coolest thing ever!?
int i = 0 ;
for ( i = 0 ; i < 10 ; i++ )
{
Console.WriteLine ( “i = {0}” , i ) ;
}
What
Does It Mean?
- The
breakpoint condition is evaluated inside the running application
- Not
inside the debugger context
- What
would happen if you try to call a method in the conditional?
- The
method call executes when evaluating the breakpoint!
- This
is tremendous power; use it wisely
- You
can really mess up your application
- Yes,
you can copy a 3GB DB from a breakpoint
- You
now can have assertions on the fly!
Assertions
On the Fly
- With
the ability to call methods, now you can have debug only methods that
return true when something’s wrong
- Using
that method as a conditional means you’ll only stop when that condition
is met
- Essentially,
this is like poking in an assertion check before the statement
- But
there’s no code changing
Assertions
On the Fly (cont.)
- Add
a method that returns a Boolean
- Returns
true if there is a problem
- Surround
the method with #ifdef DEBUG…#endif
- Can’t
use [Conditional(“DEBUG”)] as that only works for void return types
- Use
the method in any BP condition you want to stop on if the condition
is met
#if DEBUG
public bool CheckName ( )
{
if
( null == m_Name )
{
return ( true ) ;
}
return
( false ) ;
}
#endif
Filter
Breakpoint Modifier
- Easily
set per machine, process, and/or thread breakpoints
- Setting
a Filter Breakpoint Modifier
- Set
a location breakpoint
- Right
click on the breakpoint glyph and select “Filter…”
- In
the Breakpoint Filter dialog, fill in your condition
- Undocumented
syntax
- “==“
is supported
- The
machine/process/thread keywords are case insensitive
Tracepoints
- Basically
breakpoints with a different name
- Intended
to continue execution
- Custom
actions
- Print
a message (jam in a TRACE statement)
- Put
variables in “{}” to evaluate
- “\{“
to print a curly brace, “\\” to print a backslash
- Special
codes in tracepoint dialog
- Execute
a VSA macro
The
Watch Window (AKA Expression Evaluator)
- The
Watch window is one of the finest pieces of software engineering you'll
see
- It
offers almost infinite flexibility
- The
most important thing is that in the Watch window and its cousins (Autos,
Locals, Quick Watch, etc) you can click on the value of a variable and
change it
- The
awesome new data tips are the Watch window in tool tips
- All
data is fully editable
- Pressing
the CTRL key makes the Data Tip window see through
- Pin
the tips to the source code
Calling
Methods in the Watch Window
- It's
a great trick for two reasons
- It
allows you to see data structures that the Watch window does not display
well
- You
can also have assertions completely on the fly
- Every
time you view a property, you're calling the getter method in the Watch
window
- Calling
a method is as simple as adding the parenthesis and any parameters needed
Calling
Methods in the Watch Window (cont.)
- Where
does the method/property execute?
- There
are a few rules
- Don't
do anything more than reading memory
- The
method must execute in less than 10 seconds
- Interestingly,
this same restriction does not apply to methods called by breakpoints
- Does
not stop on breakpoints when called from the Watch window
- If
you want to stop, use the Immediate window
Great
Testing Trick
- Drag
the expression in a condition down to the Watch window
- This
allows you to evaluate and see exactly what variables will trigger the
condition you need
- An
excellent trick for driving that code coverage as high as possible
- I've
changed my coding style to avoid function calls in expressions to make
this easier to evaluate
What
If the Expression Uses Objects?
- How
do you change the ae variable since it is an object?
- You
could change the individual property, but sometimes you need to change
the entire object
- The
Immediate window to the rescue
- Open
the Immediate window
- Type
in an expression to allocate an object
- Open
the Watch window
- Add
the variable you want to change to the Watch window
- In
the Value cell, enter the variable prefixed with a ‘$’ sign
if ( false ==
String.IsNullOrEmpty ( ae.Name ) ) ...
SomeClass x
= new SomeClass ( ) ;
Data
Tips/Watch Window Tricks
- Right
click on the data tip to bring up a context menu
- Standard
options of cut, copy, paste, adding the object to the watch window and
setting hex display
- Make
Object ID is the very interesting option
- Tells
the debugger to watch a particular object in memory no matter where
it goes
- Can
ID the object with a number
- Use
1# in the Watch window for object one, etc.
- Allows
you to watch objects even out of scope
- If
it says “Can’t evaluate” that means the object has been garbage
collected
- Can
even use the object id in conditional breakpoints
- Allows
specific instance breakpoints
- C#
only feature
What
Generation is This Object In?
- Nothing’s
stopping you from calling GC.GetGeneration in the Watch window
- Even
cooler!
- Use
Make Object ID to watch an object that’s not in scope
- Pass
the Object ID to GC.GetGeneration
- The
expression evaluator handles it just fine
Watch
Window Format Specifiers
- Like
C++, C# lets you format the data display with “,<op>” formatting
after the item
Specifiers |
Format |
,d |
Decimal
integer |
,h |
Hexadecimal
integer |
,nq |
String
not bound by quotes |
Watch
Window Pseudovariables
- $user
- Shows
account information for the current thread
- $exception
(C# only)
- Automatically
shown in the Locals window if the Exception Assistant is disabled
Auto
Expanding Your Own Types
- C#
only: If your class has an overridden ToString method, the debugger
automatically uses it
- This
alone will let you see much better information with no extra work on
your part
- The
big magic is in DebuggerDisplayAttribute
- In
System.Diagnostic namespace
- Now
we need an Code Analysis rule that looks for either
- Overridden
ToString
- DebuggerDisplayAttribute
- If
neither found, triggers an error
Using
DebuggerDisplayAttribute
- Example,
a complex number class
- Contains
the numbers in two private variables, _Real, and _Imaginary
- Anything
inside “{}” is evaluated using the instance of the class
- What’s
even cooler?
- If
a class does not have a DebuggerDisplayAttribute
- The
debugger walks the derivation chain looking for the first class that
has one set
- If
a base class has one, that one is used
[DebuggerDisplay
( "{_Real}.{_Imaginary}i" )]
public class ComplexNumber { . . .}
Using
DebuggerDisplayAttribute (cont.)
- Can
be applied to anything other than a method
- Can
call methods and access properties in the string
- Be
careful because syntax evaluation can be different between languages
- The
following works in C#, but not Visual Basic
- Visual
Basic also does not support calling methods, C# does
[DebuggerDisplay(“Object
{count - 2}: {(flag) ? \"yes\" : \"no\"}”)]
Advanced
DebuggerDisplayAttribute
- Accepts
named parameters
- Name
– The value to place in the name column
- Type
– The value to place in the type column
- Example:
a KeyPair class that sets the Name named parameter to
show the key in the Name column
[DebuggerDisplay
( "{value}" , Name = "{key}" )]
class KeyValuePairs
Advanced
DebuggerDisplayAttribute (cont.)
- Hiding
fields and roots can make your Watch window display much cleaner
- Use
the DebuggerBrowseableAttribute
to set state
- Never
– don’t ever display
- RootHidden
– Don’t display the proxy type, expand the array items (more on
this in a moment)
- Collapsed
– Don’t expand the class, hide internal members
Advanced
DebuggerDisplayAttribute (cont.)
- Example:
the complex number class where the fields are returned by appropriate
properties
[DebuggerDisplay
( "{_Real}.{_Imaginary}i" )]
public class ComplexNumber
{
[DebuggerBrowsable ( DebuggerBrowsableState.Never
)]
private int _Real = 0;
public int Real
{ get { return ( _Real ) ; }
set { _Real = value ; }
}
. . .
Advanced
DebuggerDisplayAttribute (cont.)
- DebuggerTypeProxyAttribute
tells the debugger to instantiate a different class to display the type
- In
general, use a private class inside the main type to handle the display
- Will
be rare you use this
- See
the Using DebuggerDisplayAttribute example in the documentation
Expanding
Types with No Source
- Debugger
supports expanding types even if you don’t have source
- Through
AUTOEXP.DLL in Visualizer directories
- Magic
is Target parameter to DebuggerDisplayAttribute
- See
AutoExp project in the session source code
[assembly: DebuggerDisplay
( "Count={Count}" ,
Target = typeof ( WebCaching.Cache ) )]
Default
Visualizers
- Tired
of not seeing your strings, HTML, and XML in a normal format in the
debugger?
- The
default visualizers are here to help
- Click
on the magnifier in the string type magnifier and choose how you want
to see the data
- A
huge productivity boost
Custom
Visualizers
- The
killer reason for upgrading
- Allows
you to simply write code to display types in a more identifiable way
- Amazingly
simple to write
- Amazingly
easy to test
- Microsoft
ships the DataViewManager, DataView, DataTable,
DataSet visualizers, WPF visualizer, and LINQ SQL Queries in the
box
Installing
Custom Visualizers
- Globally
for all users
- <VS
Dir>\Common7\Packages\Debugger\Visualizers
- For
individual users
- My
Documents\Visual Studio 2010\Visualizers
- Only
supports modal dialog visualizers
Writing
Visualizers
- After
you determine the type you want to display
- Create
a class library
- Add
references to
- System.Windows.Forms
- Microsoft.VisualStudio.DebuggerVisualizers
- Put
those in using directives
- Add
an assembly level attribute that describes the type you’re interested
in displaying
- You
can have as many visualizers as you want in a single assembly
Writing
Visualizers (cont.)
- Parameter
1: The visualizer type you are writing
- Parameter
2: The serializer to use
- VisualizerObjectSource
is the debugger supplied serializer
- Can
write custom serializers if you want
- Target
named param: the type you’re providing a visualizer for
- Desc
named param: the display name of your visualizer
[assembly: DebuggerVisualizer
(
typeof ( Wintellect.Visualizers.ImageVisualizer
) ,
typeof ( VisualizerObjectSource )
,
Target = typeof ( System.Drawing.Image )
,
Description = "Wintellect Image Visualizer" )
]
Writing
Visualizers (cont.)
- Derive
your class from DialogDebuggerVisualizer
- Implement
the trivial Show method
protected override
void Show (
IDialogVisualizerService windowService ,
IVisualizerObjectProvider objectProvider )
{
// This is all it takes to get the actual object from the
// debuggee address space into the debugger.
// How simple is that!?
Image dbgImage = (Image)objectProvider.GetObject ( );
// Create your dialog here..
// Show it.
windowService.ShowDialog ( form );
}
Writing
Visualizers (cont.)
- Implement
a test method you can test the visualizer without the hassle of debugging
Visual Studio itself
- Create
a console app to call the test method
public static
void TestImageVisualizer ( object itemToVisualize )
{
VisualizerDevelopmentHost visualizerHost =
new VisualizerDevelopmentHost ( itemToVisualize ,
typeof ( ImageVisualizer ) );
visualizerHost.ShowVisualizer ( );
}
Cool
Free Visualizers
- Regular
Expression Visualizers
- regex.osherove.com/Articles/RegexKit.html
- Dynamic
IL Visualizer
- blogs.msdn.com/haibo_luo/archive/2005/10/25/484861.aspx
- ASP.NET
Cache Visualizer
- http://blog.bretts.net/?p=11
- Mole
Visualizer
- www.codeproject.com/KB/macros/MoleForVisualStudioEdit.aspx
- View
anything with drill down
- Really
nice for ASP.NET and WPF
Set
Next Statement Command
- A
cool hidden trick in the debugger
- It
allows you to change the instruction pointer to a different location
- A
great debugging trick for two reasons
- You
can drive your code coverage higher
- You
can re-execute code to double check conditions
- Be
careful, as Set Next Statement can easily crash your program if you
put the IP in the wrong place
Using
Set Next Statement Command
- Select
the yellow instruction arrow and drag it to a different location
- Right
click on an executing line when debugging and choose Set Next Statement
Step
Over Properties and Operators
- Debugger
converts step into a property/operator into a step over
- Looks
at the code and if it’s small enough, does the step over
- Toggle
on and off on the fly while debugging
- Right
click in source code and select on context menu
- Always
enable Show Threads in Source
- Turns
on margin icon that shows you what other threads are executing in the
application
Threads
Window
Threads
Window (cont.)
- Can
change the name of a thread in the Name column
- Right
click on thread and select Rename
- Makes
filter breakpoints much easier
- Freeze
threads to avoid bouncing around when single stepping
- Use
the FreezeThawThreads macros to make it easy
- Use
InterestingThreads macros to switch all breakpoints to stop only on
a specific thread
The
.NET Reference Source Code
- Seeing
the .NET source is wonderful when debugging
- Setting
up your IDE
- In
Options dialog, Debugging General
- Uncheck
“Enable Just My Code (Managed only)”
- Check
“Enable source server support”
The
.NET Reference Source Code (cont.)
- In
Options dialog,
- In
“Symbol file (.pdb) locations” check
- Environment
variable: _NT_SYMBOL_PATH
- Microsoft
Symbol Servers
- Add
“C:\SYMBOLS\PUBLIC\MicrosoftPublicSymbols*
http://referencesource.microsoft.com/symbols”
- In
“Cache symbols from symbol servers to this directory” enter
- The
easy way: use .\Scripts\Set-VS2010SymbolServer.ps1
- Part
of code disk for this session
The
.NET Reference Source Code (cont.)
- Now
every time you debug, you’ll download the .NET Reference Source
- Can
be very slow the first time you run on a machine
- May
want to consider only loading symbols manually
- So
you pay the download tax only when you need to
- Options
dialog, Debugging, Symbols
- Uncheck
“Search the above locations only when symbols are loaded manually”
- When
you want symbols and source
- Right
click on method in Call Stack window and select Load Symbols
Problems
with .NET Reference Source Downloading
- The
debugger can only download a single file at a time
- Would
be nice to have the following
- A
batch download of all supported files into your cache
- A
way to work with proxy servers
- A
way to even have .NET source debugging with VS 2005 or CodeGear tools
- NetMassDownloader
to the rescue
- http://www.codeplex.com/NetMassDownloader
- By
Kerem Kusmezer and John Robbins
- To
download all the current sources from Microsoft:
netmassdownloader
-d "C:\Program Files\Reference Assemblies\Microsoft\Framework\v4.0"
-d C:\windows\Microsoft.NET\Framework\v4.0.30128
Debugging
Exceptions
- A
little used, but powerful feature of the debugger is the Exceptions
dialog
- Checking
thrown will stop on the throw statement
Exceptions
Handled by the Debugger
- C++
Exceptions
- Native
code language exceptions
- Common
Language Runtime Exceptions
- Managed
exceptions from .NET applications
- Every
FCL exception is listed by default
- Managed
Debugging Assistants
- Diagnostic
error notifications from the CLR
- Native
Run-Time Checks
- The
outstanding native /RTC switch exceptions
- Win32
Exceptions
- The
well known Win32 native exceptions
The
Debugging Tricks with Exceptions
- In
many cases, you want to stop when the exception is thrown so you can
start debugging right from the moment a problem happens
- The
steps
- Select
the exception in the Exception dialog
- Check
the throw box next to the particular exception
- Great
idea to set the entire CLR Exception tree to “Break into the Debugger”
- This
lets you see how many exceptions are being thrown
- Helps
you determine performance issues with exceptions
Adding
Your Own Exceptions
- If
you want your custom exceptions in the Exception dialog
- Click
the Add button
- Select
Common Language Runtime Exceptions in the Type combo box
- Type
in the completely qualified name of your custom exception in the New
Common Language Runtime Exceptions dialog
- Data
is saved to the .SUO file for the project
Mini
Dumps with VS
- Get
in the habit of saving dumps when debugging
- Debug,
Save Dump As command
- Open
dumps with File, Open menu
- Initiate
analysis by clicking on “Debug with Mixed”
- Saves
you tons of time!
- No
longer have to open all dumps with WinDBG+SOS
- Hints
- Make
sure Symbol Server is set up
- For
private build binaries and PDB files
- Put
them in same directory as .DMP file
- Only
works for .NET 4.0 applications
IntelliTrace:
Why VS 2010 ROCKS!
- Stopping
in the debugger is just a “moment in time”
- Like
looking at a photograph
- A
video of everything that happened up to the current point would be even
better
- That’s
exactly what IntelliTrace is all about
- The
most exciting advance in debugging in 20 years
- You’ll
easily debug problems 25% faster with IntelliTrace
- Caveats
- Only
in Visual Studio 2010 Ultimate
- Today
only works with x86 binaries in the debugger
- IntelliTrace
integrated into Microsoft Test Manager (MTM) and works with x64
Initially
Setting up IntelliTrace
- Key
to IntelliTrace
- IntelliTrace
General Page
- Enable
IntelliTrace events and call information
Initially
Setting up IntelliTrace (cont.)
- IntelliTrace,
IntelliTrace Events Page
- Enable
all events
- Seriously!
IntelliTrace
Usage Hints
- Turn
off VSHOST for WPF, Win Forms & console apps
- Makes
it easier to find your code
- Finding
an executed line or method is hidden in the UI
- Right
click on line
- Select
“Search for This Line/Method in IntelliTrace”
- Use
Information Bar at top of source window to find the exact execution
IntelliTrace
Usage Oddness
- So
you finish debugging and want to look at the last run log
- POOF!
The IntelliTrace log disappears as soon as you stop debugging
- Use
the Wintellect macro: IntelliTraceHelper/OpenLastIntelliTraceRecording
- Opens
the last recorded log
- Double
click one of the threads to load the log
Remote
Debugging
- Remote
debugging has gotten even easier with Visual Studio
- No
longer requires an installation process; now either
- XCOPY
the required bits
- Share
the directory with the bits and run
- Supports
cross CPU debugging
- Bits
are in <Install Path>Common7\IDE\Remote Debugger\<CPU>
- Where
CPU is x86, x64, or ia64
Remote
Machine Initial Setup
- On
the remote machines run MSVSMON.EXE to get the firewall configured
- Must
be an administrator on the machine to unblock ports
- Leave
the defaults in place
- Look
at the first line in the MSVSMON.EXE UI and record the default name
of the server
- Optionally,
set any permissions using the Options dialog
Local
Machine Initial Setup
- Select
the Tools, Attach to Process menu
- In
the Qualifier field, type in the server name of the remote machine
- Click
the Refresh button
- When
prompted with updating the firewall, select the appropriate level and
click OK
- You
still may not connect as the administrator account may not have permissions
on the other machine
- Start
Visual Studio with the same account you logged into the remote machine
with
- Go
through the attach process and you’ll connect
Using
MSVSMON.EXE as a Service
- The
default usage model requires you to be logged into the remote machine
for debugging to work
- Install
the Remote Debugging Components from Visual Studio CD/DVD
- <Drive>:\Remote
Debugger\<cpu>\RDBGSETUP.EXE
- If
Visual Studio is installed on the machine
- Run
<VS DIR>\Common7\IDE\RDBGWIZ.EXE
- For
domain-based systems, use LocalService as account
- For
workgroups, use an Administrator account for service
- Only
accounts in Administrator group can connect and debug
Setting
Up a Project
- In
the project Property Pages, Debug page
- Check
Use remote debugging
- Specify
the remote machine connection string
- If
the binary is in the same location on both machines
- You
do not need to do anything else
- If
the binary is in a different location on the remote machine
- Select
the Start external program radio button
- In
the edit box, type in the complete drive, path, and filename to the
EXE just like you were typing it on the remote machine
Where
Do the PDB Files Go?
- Ideally
in a symbol server
- For native debugging,
symbols are loaded on the local machine
- For managed debugging,
symbols are loaded on the remote machine
- Remote
debugging includes SYMSRV.DLL so set up the _NT_SYMBOL_PATH environment
variable on the remote machine
- If
not using a symbol server
- Put
the PDB files in the same directories as the binaries on both machines
- Source
files are found using paths on the local machine
Remote
Debugging Troubleshooting
- “Access
denied” errors in workgroups
- Check
the security options
- Start
Local Security Settings MMC
- Go
to Local Policies/Security Options
- Make
sure “Network Access: Sharing and security model for local accounts”
is set to Classic
Questions?
john@wintellect.com