Thursday, April 07, 2011

DBX vs. Visual Studio and WinDbg: Part 1, Calling Functions

I’ve recently had an enlightening experience teaching a C++ Debugging course to a group of developers who are transitioning from a Solaris environment to Windows and Visual Studio. This hasn’t been an easy transition for them, and the course wasn’t easy to teach—specifically, because one of the most discussed topics was feature parity between DBX (the debugger of choice for C++ applications on Solaris) and Visual Studio. Fortunately, the course focuses on WinDbg, which has alternatives to several debugging features that are inaccessible from Visual Studio; and enabled me to address at least partially the pain points and missing features after leaving DBX.

Following the course, I decided to write a series of posts outlining the unique features of DBX and how they can be emulated using Visual Studio and WinDbg. The purpose is not to convert us all to loyal DBX users, but rather to see how some features we may never have considered are taken for granted on other platforms.

Some ideas I have for this blog series:
  • Calling a function [this post]
  • Configuring breakpoints
  • Setting multiple breakpoints at once
  • Memory access breakpoints
  • Conditional breakpoints
  • Tracing execution
  • Execution control
  • Displaying data, including STL collections
  • Runtime application checking
  • Miscellaneous commands
In this post we’ll discuss a fairly useful feature—calling a function in the middle of the debugging session. The function may belong to the current execution path, or any other library that is currently loaded into the process.

DBX 
DBX makes calling a function from the middle of the debugging session rather easy with the “call” command, and supports virtual methods, static functions, and arbitrary parameters. You can even set a breakpoint in a function you call that way, and stop to examine the program’s state. For example:
(dbx) list 
   11     std::map<int,std::vector<float> > m; 
   12     std::vector<float> v; 
   13     v.push_back(4.0f); 
   14     v.push_back(5.0f); 
   15     m[5] = v; 
   16     global = 2; 
   17     getchar(); 
   18   } 
... 
(dbx) next 
stopped in main at line 16 in file "stl.cc" 
   16     global = 2; 
(dbx) stop inmember size 
(3) stop inmember size 
(dbx) print m[5].size() 
stopped in std::vector<float, std::allocator, <float>void>::size at line 375 in file "stl_vector.h" 
  375   size() const { return size_type(end() - begin()); } 
dbx: Stopped within call to 'size'. Starting new command interpreter 
(dbx) where 
=>[1] std::vector<float, std::allocator, <float>void>::size(this = 0x8067a54), line 375 in "stl_vector.h" 
  ---------- called from debugger ---------- 
  [2] main(), line 16 in "stl.cc" 
(dbx) pop -c 
dbx: Call to 'size' aborted. Going back to previous command interpreter