Topics covered:

  • Introduction to Debugging
  • Visual Studio Debugger
  • Breakpoints
  • Data Inspection
  • Threads and Stacks
  • Finding a Defect

Video (in Bulgarian)

Presentation Content

What is Debugging?

  • The process of locating and fixing or bypassing bugs (errors) in computer program code
  • To debug a program:
    • Start with a problem and stable source state
    • Isolate the source of the problem
    • Fix it and send the fix to the source control
      • One change at a time
    • Create regression test
  • Debugging tools (called debuggers) help identify coding errors

Debugging vs. Testing

  • Testing
    • A means of initial detection of errors
  • Debugging
    • A means of diagnosing and correcting the root causes of errors that have already been detected

Importance of Debugging

  • Perfect code is an illusion
  • Debugging can viewed as one big decision tree
    • Individual nodes represent theories
    • Leaf nodes represent possible root causes
  • You should be able to debug code that is written years ago
  • $60 Billion per year in economic losses due to software defects (in USA only)

How to Avoid Bugs

  • Reduce number of code lines
    • Write less and write smarter. Keep it simple.
  • Reduce complexity / Good code separation
    • Reduce number of possible code paths
  • Understand the size of the input & output spaces (be aware of the corner cases)
  • Unit test (TDD) with almost 100% test coverage
  • Always assume your code is not working
    • Prove it otherwise!
    • Always check the code you write
  • Experience matters / Read, learn, code

Visual Studio Debugger

  • Visual Studio IDE gives us a lot of tools to debug your application
    • Adding breakpoints
    • Visualize the program flow
    • Control the flow of execution
    • Data tips
    • Watch variables
    • Debugging multithreaded programs
    • and many more…

How To Debug a Process

  • Starting a process under the Visual Studio debugger
  • Attaching to an already running process
    • Without a solution loaded you can still debug
    • Useful when solution isn’t readily available
    • Debug menu -> Attach to Process

Debugging a Solution

  • Debug menu, Start Debugging item
    • F5 is a shortcut
  • Easier access to the source code and symbols since its loaded in the solution
  • Certain differences exist in comparison to debugging an already running process
    • Hosting for ASP.NET application
      • VS uses a replacement of the real IIS

Debug Windows

  • Debug Windows are the means to introspect on the state of a process
  • Opens a new window with the selected information in it
  • Window categories
    • Data inspection
    • Threading
  • Accessible from menu
    • Debug -> Windows

Debugging Toolbar

  • Convenient shortcut to common debugging tasks
    • Step into
    • Step over
    • Continue
    • Break
    • Breakpoints
  • Customizable to fit your needs
    • Add and/or remove buttons

Controlling Execution

  • By default, an app will run uninterrupted (and stop on exception or breakpoint)
  • Debugging is all about looking at the state of the process
  • Controlling execution allows:
    • Pausing execution
    • Resuming execution
    • Stepping through the application in smaller chunks
    • In the case of IntelliTrace (recording steps), allows backward and forward stepping

IntelliTrace

  • IntelliTrace operates in the background, records what you are doing during debugging
  • You can easily get a past state of your application from the IntelliTrace
  • You can navigate your code with any part and see what’s happened
    • To navigate, just click any of the events that you want to explore

Options and Settings

  • Visual Studio offers quite a few knobs and tweaks in the debugging experience
  • Options and settings is available via Debug -> Options and Settings
  • Examples of Options and Settings
    • Enable just my code (ignore other code)
    • Enable .NET framework source stepping
    • Source server support
    • Symbols (line numbers, variable names)
    • Much more…

Breakpoints

  • Ability to stop execution based on certain criteria is key when debugging
    • When a function is hit
    • When data changes
    • When a specific thread hits a function
    • much more
  • Visual Studio debugger has a huge feature set when it comes to breakpoints

Visual Studio Breakpoints

  • Stops execution at a specific instruction (line of code)
    • Can be set using Debug->Toggle breakpoint
      • F9 shortcut
      • Clicking on the left most side of the source code window
  • By default, the breakpoint will hit every time execution reaches the line of the code
  • Additional capabilities: condition, hit count, value changed, when hit, filters

Managing Breakpoints

  • Managed in the breakpoint window
  • Adding breakpoints
  • Removing or disabling breakpoints
  • Labeling or grouping breakpoints
  • Export/import breakpoints

Breakpoint Filters

  • Allows you to excerpt even more control of when a breakpoint hits
  • Examples of customization
    • Machine name
    • Process ID
    • Process name
    • Thread ID
    • Thread name
  • Multiple can be combined using &, ||, !

Data Inspection

  • Debugging is all about data inspection
    • What are the local variables?
    • What is in memory?
    • What is the code flow?
    • In general - What is the state of the process right now and how did it get there?
  • As such, the ease of data inspection is key to quick resolution of problems

Visual Studio Data Inspection

  • Visual Studio offers great data inspection features
    • Watch windows
    • Autos and Locals
    • Memory and Registers
    • Data Tips
    • Immediate window

Watch Window

  • Allows you to inspect various states of your application
  • Several different kinds of “predefined” watch windows
    • Autos
    • Locals
  • “Custom” watch windows also possible
    • Contains only variables that you choose to add
    • Right click on the variable and select “Add to Watch”

Autos and Locals

  • Locals watch window contains the local variables for the specific stack frame
    • Debug -> Windows -> Locals
    • Displays: name of the variable, value and type
    • Allows drill down into objects by clicking on the + sign in the tree control
  • Autos lets the debugger decide which variables to show in the window
    • Loosely based on the current and previous statement

Memory and Registers

  • Memory window can be used to inspect process wide memory
    • Address field can be a raw pointer or an expression
    • Drag and drop a variable from the source window
    • Number of columns displayed can be configured
    • Data format can be configured
  • Registers window can be used to inspect processor registers

Data Tips

  • Provides information about variables
    • Variables must be within scope of current execution
  • Place mouse pointer over any variable
    • Variables can be expanded by using the + sign
  • Pinning the data tip causes it to always stay open
  • Comments can be added to data tips
  • Data tips support drag and drop
  • Importing and exporting data tips

Immediate Window

  • Useful when debugging due to the expansive expressions that can be executed
    • To output the value of a variable <name of variable>
    • To set values, use <name of variable>=<value>
    • To call a method, use <name of variable>.<method>(arguments)
    • Similar to regular code
    • Supports Intellisense

Threads

  • Fundamental unit of code execution
  • Commonly, more than one thread
    • .NET, always more than one thread
  • Each thread has a memory area associated with it known as a stack used to
    • Store local variables
    • Store frame specific information
  • Memory area employs last in first out semantics

Threads Window

  • Contains an overview of thread activity in the process
  • Includes basic information in a per thread basis
    • Thread ID’s
    • Category
    • Name
    • Location
    • Priority

Callstacks

  • A threads stack is commonly referred to as a callstack
  • Visual Studio shows the elements of a callstack
    • Local variables
    • Method frames

Finding a Defect

  • Stabilize the error
  • Locate the source of the error
    • Gather the data
    • Analyze the data and form hypothesis
    • Determine how to prove or disprove the hypothesis
    • Prove or disprove the hypothesis by 2c
  • Fix the defect
  • Test the fix
  • Look for similar errors

Tips for Finding Defects

  • Use all available data
  • Refine the test cases
  • Check unit tests
  • Use available tools
  • Reproduce the error several different ways
  • Generate more data to generate more hypotheses
  • Use the results of negative tests
  • Brainstorm for possible hypotheses
  • Narrow the suspicious region of the code
  • Be suspicious of classes and routines that have had defects before
  • Check code that’s changed recently
  • Expand the suspicious region of the code
  • Integrate incrementally
  • Check for common defects
  • Talk to someone else about the problem
  • Take a break from the problem

Fixing a Defect

  • Understand the problem before you fix it
  • Understand the program, not just the problem
  • Confirm the defect diagnosis
  • Relax
  • Save the original source code
  • Fix the problem not the symptom
  • Make one change at a time
  • Add a unit test that expose the defect
  • Look for similar defects

Psychological Considerations

  • Your ego tells you that your code is good and doesn’t have a defect even when you’ve seen that it has one.
  • How “Psychological Set” Contributes to Debugging Blindness