Friday, September 7, 2012

Book review: The Art of Debugging with GDB, DDD and Eclipse (Chapter 3).

Chapter 3: Inspecting and setting variables.

Our Main Example Code

The main example is an implementation of a binary tree.

Advanced Inspection and Setting of Variables

Instead of using three print commands as in

  p tmp->val
  p tmp->left
  p tmp->right
you can print a struct in its entirety using
  p *tmp
Even better is using GDB's display or disp command, which tells GDB to automatically print the specified item each time there is a pause in execution (due to a breakpoint, the next or step commands,...)

You can also use GDB's commands command to execute several commands (like print) when a breakpoint is hit. Next to the print command, the printf() command can be helpful for this. Its formatting is similar to that of its C-language namesake. The command set for a given breakpoint can be modified dynamically, or simply canceled by redefining an empty set:

  commands 1
  end

If your code contains functions to print certain data-structures, you can call these from GDB using the call command:

  call printtree(root)

In DDD, the Right-Click / Display option is very useful for displaying linked data-structures! To follow a link, right-click on the link and select the `Display *()' choice. To remove something, right-click and choose the Undisplay option. To avoid windows cluttered with data, you can run DDD with the --separate option, which will create three separate windows for Source Code, Console and Data.

Eclipse has its Variables view where you can inspect the value of variables. By default, this view does not show global variables. You can add those by right-clicking within the Variables view and selecting 'Add Global Variables'.

For printing values of dynamically created arrays (e.g. int *x;), you can use for example:

  p x
  p *x
  p x[5]
  p *x@25
  p (int [25]) *x
In DDD it's probably best to also use these commands in the Console. In Eclipse, you select the variabe in the Variables view by right-clicking and selecting `Display As Array'.

For C++ code, the same GDB commands work, but with somewhat different output. Also, GDB needs you to specify variables according to the same scope rules that C++ uses. For example, don't use

  p *root
but specify root via its full name as
  p *node::root

GDB's ptype command is handy to get a quick review of the structure of a class or struct. In DDD, you can right-click the class or variable name and choose `What Is' to get the same information. Eclipse has its Outline view for this.

With the info locals command in GDB, you can get a list of values of all the local variables in the current stack frame. In DDD, you can display these by clicking Data | Display Local Variables. Eclipse displays the local variables in the Variables view.

To examine memory at a given address directly, GDB provides the x (examine) command. In DDD one selects Data | Memory. Eclipse has a Memory view, in which you can create Memory Monitors. These things are mainly useful in assembly language contexts.

The print and display commands allow you to specify alternative formats for hex, character, string and floating point:

  p/x myvar
  p/c myvar
  p/s myvar
  p/f myvar
To temporarily disable, re-enable and delete a display item, do:
  info disp
  dis disp 1
  enable disp 1
  undisp 1

Setting Variables from Within GDB/DDD/Eclipse

In GDB, you can very easily set values with for example:

  set x = 12
There is no mouse-based way to do this in DDD, so do it from the Console. In Eclipse, right-click the variable in the Variables view and select Change Value. Note also that the changes you make to argv[1], argv[2] etc. with the set args command will not occur until the next time you issue the run command.

GDB has the info args command to check the arguments of the current function. DDD provides this when you click Data | Display Arguments.

GDB's Own Variables

Output values from GDB's print command are labeled $1, $2, and so on, and are collectively called the value history. They can be used to produce shortcuts in future print commands, for example:

  (gdb) p tmp->left
  $1 = (struct node *) 0x80496a8
  (gdb) p *$1
There is also a special value history variable $.

You can also store certain values in convenience variables. For example

  set $q = p
  p $*q
The variable $q here is called a convenience variables. These variables can change values according to C rules.

No comments:

Post a Comment