| List of Sidebars | xix |
| Acknowledgments | xxi |
| Introduction | xxiii |
| PART I THE GESTALT OF DEBUGGING | |
| 1 Bugs: Where They Come From and How You Solve Them | 3 |
| Bugs and Debugging | 3 |
| What Are Bugs? | 4 |
| Process Bugs and Solutions | 8 |
| Planning for Debugging | 18 |
| Prerequisites to Debugging | 19 |
| The Skill Set | 19 |
| Learning the Skill Set | 21 |
| The Debugging Process | 22 |
| Step 1: Duplicate the Bug | 24 |
| Step 2: Describe the Bug | 25 |
| Step 3: Always Assume That the Bug Is Yours | 25 |
| Step 4: Divide and Conquer | 25 |
| Step 5: Think Creatively | 26 |
| Step 6: Leverage Tools | 27 |
| Step 7: Start Heavy Debugging | 27 |
| Step 8: Verify That the Bug Is Fixed | 28 |
| Step 9: Learn and Share | 30 |
| Final Debugging Process Secret | 30 |
| 2 Getting Started Debugging | 33 |
| Track Changes Until You Throw Away the Project | 33 |
| Version Control Systems | 34 |
| Bug Tracking Systems | 38 |
| Choosing the Right Systems for You | 40 |
| Schedule Time for Building Debugging Systems | 41 |
| Build All Builds with Debugging Symbols | 42 |
| For Managed Code, Treat Warnings as Errors | 46 |
| For Native Code, Treat Warnings as ErrorsMostly | 48 |
| For Native Code, Know Where Your DLLs Load | 52 |
| What About Managed Modules and Base Addresses? | 57 |
| Design a Lightweight Diagnostic System for Release Builds | 65 |
| Frequent Builds and Smoke Tests Are Mandatory | 67 |
| Frequent Builds | 67 |
| Smoke Tests | 68 |
| Build the Installation Program Immediately | 70 |
| QA Must Test with Debug Builds | 70 |
| Install the Operating System Symbols and Set Up a Symbol Store | 71 |
| Your Source and Symbol Servers | 81 |
| 3 Debugging During Coding | 83 |
| Assert, Assert, Assert, and Assert | 85 |
| How and What to Assert | 86 |
| Assertions in .NET Windows Forms or Console Applications | 95 |
| Assertions in ASP.NET Applications and XML Web Services | 103 |
| Assertions in Native C++ Applications | 113 |
| Different Types of Visual C++ Assertions | 118 |
| SUPERASSERT | 121 |
| Trace, Trace, Trace, and Trace | 142 |
| Tracing in Windows Forms and Console .NET Applications | 144 |
| Tracing in ASP.NET Applications and XML Web Services | 146 |
| Tracing in Native C++ Applications | 148 |
| Comment, Comment, Comment, and Comment | 149 |
| Trust Yourself, but Verify (Unit Testing) | 151 |
| PART II POWER DEBUGGING | |
| 4 Operating System Debugging Support and How Win32 Debuggers Work | 157 |
| Types of Windows Debuggers | 159 |
| User-Mode Debuggers | 159 |
| Kernel-Mode Debuggers | 161 |
| Windows Operating System Support for Debuggees | 164 |
| Just-In-Time (JIT) Debugging | 164 |
| Automatically Starting in a Debugger (Image File Execution Options) | 168 |
| MinDBG: A Simple Win32 Debugger | 171 |
| WDBG: A Real Debugger | 190 |
| Reading and Writing Memory | 192 |
| Breakpoints and Single Stepping | 195 |
| Symbol Tables, Symbol Engines, and Stack Walking | 200 |
| Step Into, Step Over, and Step Out | 209 |
| So You Want to Write Your Own Debugger | 210 |
| What's Next for WDBG? | 211 |
| 5 Advanced Debugger Usage with Visual Studio .NET | 213 |
| Advanced Breakpoints and How to Use Them | 214 |
| Breakpoint Tips | 215 |
| Quickly Breaking on Any Function | 217 |
| Location Breakpoint Modifiers | 224 |
| Multiple Breakpoints on a Single Line | 227 |
| The Watch Window | 228 |
| Calling Methods in the Watch Window | 230 |
| The Set Next Statement Command | 232 |
| 6 Advanced .NET Debugging with Visual Studio .NET | 235 |
| Advanced Breakpoints for .NET Programs | 236 |
| Conditional Expressions | 236 |
| The Watch Window | 241 |
| Expanding Your Own Types Automatically | 241 |
| Tips and Tricks | 245 |
| DebuggerStepThroughAttribute and DebuggerHiddenAttribute | 245 |
| Mixed Mode Debugging | 246 |
| Remote Debugging | 247 |
| ILDASM and Microsoft Intermediate Language | 249 |
| Getting Started with ILDASM | 251 |
| CLR Basics | 257 |
| MSIL, Locals, and Parameter | 258 |
| The Important Instructions | 259 |
| Other Reverse Engineering Tools | 266 |
| 7 Advanced Native Code Techniques with Visual Studio .NET | 269 |
| Advanced Breakpoints for Native Applications | 269 |
| Advanced Breakpoint Syntax | 270 |
| Breakpoints on System or Exported Functions | 271 |
| Conditional Expressions | 274 |
| Data Breakpoints | 277 |
| The Watch Window | 280 |
| Formatting Data and Expression Evaluation | 280 |
| Timing Code in the Watch Window | 283 |
| The Undocumented Pseudoregisters | 283 |
| Expanding Your Own Types Automatically | 283 |
| Remote Debugging | 291 |
| Tips and Tricks | 295 |
| Debugging Injected Code | 295 |
| The Memory Window and Auto Memory Evaluation | 295 |
| Exception Monitoring | 296 |
| More Symbol Handling Tips | 298 |
| Detaching from Windows 2000 Processes | 299 |
| Handling Dump Files | 299 |
| x86 Assembly Language | 302 |
| The Basics of the CPU | 303 |
| A Word About the Visual C++ .NET Inline Assembler | 309 |
| Instructions You Need to Know | 310 |
| Common Sequence: Function Entry and Exit | 313 |
| Calling Procedures and Returning | 315 |
| Calling Conventions | 316 |
| Variable Access: Global Variables, Parameters, and Local Variables | 322 |
| More Instructions You Need to Know | 327 |
| String Manipulation | 333 |
| Common Assembly-Language Constructs | 336 |
| Structure and Class References | 338 |
| A Complete Example | 339 |
| The Disassembly Window | 341 |
| Walking the Stack Manually | 346 |
| Tips and Tricks | 349 |
| 8 Advanced Native Code Techniques with WinDBG | 353 |
| Before You Begin | 354 |
| The Basics | 356 |
| Debugging Situations | 360 |
| Getting Help | 361 |
| Ensuring Correct Symbols Are Loaded | 362 |
| Processes and Threads | 366 |
| General Debugging with the Command Window | 372 |
| Looking at and Evaluating Variables | 372 |
| Executing, Stepping, and Tracing | 373 |
| Breakpoints | 379 |
| Exceptions and Events | 382 |
| Controlling WinDBG | 385 |
| The Magical Extensions | 386 |
| Loading and Controlling Extensions | 387 |
| The Important Extension Commands | 388 |
| Dealing with Dump Files | 393 |
| Creating Dump Files | 393 |
| Opening Dump Files | 395 |
| Debugging the Dump | 396 |
| Son of Strike (SOS) | 396 |
| Using SOS | 397 |
| PART III POWER TOOLS AND TECHNIQUES FOR .NET | |
| 9 Extending the Visual Studio .NET IDE | 407 |
| Extending with Macros | 409 |
| Macro Parameters | 410 |
| Problems with Projects | 412 |
| Code Elements | 413 |
| CommenTater: The Cure for the Common Potato? | 415 |
| Introduction to Add-Ins | 424 |
| Fixing the Add-In Wizard-Generated Code | 426 |
| Handling Toolbar Button Issues | 429 |
| Creating Tool Windows | 430 |
| Creating Options Property Pages with Managed Code | 433 |
| The SuperSaver Add-In | 438 |
| The SettingsMaster Add-In | 444 |
| SettingsMaster Implementation Highlights | 451 |
| SettingsMaster Future Enhancements | 452 |
| 10 Managed Exception Monitoring | 455 |
| Introduction to the Profiling API | 456 |
| Getting Your Profiler Started | 463 |
| ProfilerLib | 465 |
| ExceptionMon | 467 |
| In-Process Debugging and ExceptionMon | 469 |
| Exception Usage in .NET | 475 |
| 11 Flow Tracing | 479 |
| Hooking Functions in the Profiling API | 479 |
| Requesting Enter and Leave Notifications | 480 |
| Implementing the Hook Functions | 480 |
| Inlining | 482 |
| The Function ID Mapper | 483 |
| Using FlowTrace | 484 |
| FlowTrace Implementation Highlights | 485 |
| What's Next for FlowTrace | 487 |
| PART IV POWER TOOLS AND TECHNIQUES FOR NATIVE CODE | |
| 12 Finding Source and Line Information with Just a Crash Address | 491 |
| Creating and Reading a MAP File | 493 |
| MAP File Contents | 495 |
| Finding the Source File, Function Name, and Line Number | 498 |
| PDB2MAPMap Files After the Fact | 499 |
| Using CrashFinder | 502 |
| Implementation Highlights | 505 |
| What's Next for CrashFinder? | 511 |
| 13 Crash Handlers | 513 |
| Structured Exception Handling vs. C++ Exception Handling | 514 |
| Structured Exception Handling | 514 |
| C++ Exception Handling | 518 |
| Avoid Using C++ Exception Handling | 519 |
| The SetUnhandledExceptionFilter API Function | 525 |
| Using the CrashHandler API | 527 |
| Translating EXCEPTION_POINTERS Structures | 551 |
| Minidumps | 553 |
| The MiniDumpWriteDump API | 554 |
| Pacifying MiniDumpWriteDump | 555 |
| 14 Debugging Windows Services and DLLs That Load into Services | 565 |
| Service Basics | 566 |
| The API Dance | 566 |
| The Security Dance | 568 |
| Debugging Services | 568 |
| Debugging the Core Code | 569 |
| Debugging the Basic Service | 570 |
| 15 Multithreaded Deadlocks | 581 |
| Multithreading Tips and Tricks | 581 |
| Don't Do It | 582 |
| Don't Overdo It | 582 |
| Multithread Only Small, Discrete Pieces | 583 |
| Synchronize at the Lowest Level | 583 |
| Spin Your Critical Sections | 587 |
| Don't Use CreateThread/ExitThread | 588 |
| The Default Memory Manager Might Kill You | 589 |
| Get the Dump in the Field | 590 |
| Review the CodeAnd Review the Code Again | 591 |
| Test on Multiprocessor Machines | 592 |
| DeadlockDetection Requirements | 595 |
| High-Level Design Issues with DeadlockDetection | 596 |
| Using DeadlockDetection | 598 |
| Implementing DeadlockDetection | 601 |
| Hooking Imported Functions | 601 |
| Implementation Highlights | 610 |
| What's Next for DeadlockDetection? | 624 |
| 16 Automated Testing | 627 |
| The Bane of Unit Testing: User Interfaces | 627 |
| Tester Requirements | 629 |
| Using Tester | 630 |
| Tester Scripts | 630 |
| Recording Scripts | 635 |
| Implementing Tester | 638 |
| The TESTER.DLL Notification and Playback Implementation | 638 |
| Implementing TESTREC.EXE | 653 |
| What's Next for Tester? | 665 |
| 17 The Debug C Run-Time Library and Memory Management | 667 |
| Features of the Debug C Run-Time Library | 668 |
| Using the Debug C Run-Time Library | 670 |
| The Bug in the DCRT | 671 |
| Useful DCRT Functions | 675 |
| Choosing the Right C Run-Time Library for Your Application | 677 |
| Using MemDumperValidator | 678 |
| Using MemDumperValidator with C++ | 685 |
| Using MemDumperValidator with C | 686 |
| Deep Validations | 687 |
| Implementing MemDumperValidator | 691 |
| Initialization and Termination in C++ | 692 |
| Where Have All the Leak Reports Gone? | 693 |
| Using MemStress | 694 |
| Interesting Stress Problems | 696 |
| Operating System Heaps | 697 |
| Tricks for Hunting Down Memory Problems | 699 |
| Finding Uninitialized Memory Writes | 700 |
| Finding Memory Overruns | 701 |
| Killer Switches | 707 |
| The Run-Time Check Switches | 707 |
| The Buffer Security Check Switch | 714 |
| 18 FastTrace: A High-Performance Tracing Tool for Server Applications | 717 |
| The Fundamental Problem and Its Solution | 718 |
| Using FastTrace | 719 |
| Merging Trace Logs | 720 |
| FastTrace Implementation | 721 |
| 19 Smoothing the Working Set | 723 |
| Working Set Tuning | 724 |
| Using SWS | 728 |
| Setting Up the SWS Compiles | 729 |
| Running Applications Using SWS | 731 |
| Producing and Using the Order File | 732 |
| Implementing SWS | 734 |
| The _penter Function | 734 |
| The .SWS File Format and Symbol Enumeration | 738 |
| The Run Time and Tuning | 744 |
| What's Next for SWS? | 747 |
| PART V APPENDIXES | |
| A Reading Dr. Watson Logs | 751 |
| Dr. Watson Logs | 753 |
| B Resources for .NET and Windows Developers | 761 |
| Books | 762 |
| Software Development | 762 |
| Debugging and Testing | 763 |
| .NET Technologies | 764 |
| C/C++ Language | 765 |
| Windows and Windows Technologies | 766 |
| The Intel CPU and Hardware | 767 |
| Software Tools | 768 |
| Web Sites | 769 |
| INDEX | 771 |