Debuggers: Introduction to gdb, pdb

Common gdb/pdb commands

Both programs

  • print, p: print the value of a variable
  • list, l: list the code lines around the current line
  • up: move a frame up the stack trace
  • down: move a frame down the stack trace
  • backtrace, bt, where: list all the frames in the stack (e.g. from main all the way down through all the subroutine calls). In pdb you get an arrow pointing to the current frame
  • next, n: move to the next line of code, stepping over any subroutine calls
  • step, s: similar to next, but will step into subroutine calls (even ones you might not expect like vector::operator[], e.g. vector element access)
  • continue, c: continue program execution until hitting the next breakpoint or until program execution finishes (whichever comes first)
  • break, b: tell the debugger to halt execution at a given point. Can be at the beginning of a method call, e.g. break GroupDiffusion::computeQpResidual, or a particular line of code, e.g. break Kernel.C:50. For pdb, if specifying breakpoints by file or function, they must be in sys.path
  • disable <breakpoint #>: disable the supplied breakpoint
  • enable <breakpoint #>: enable the supplied breakpoint
  • run, r: run the program from the beginning

gdb

  • finish: continue execution until the current frame or subroutine returns to the calling frame and print the returned value
  • return: prematurely return from the current frame to the calling frame. Can optionally supply a value that you want the prematurely exiting frame to return
  • info <subcommand>: get info about a particular subcommand. Most common:
  • info break: get information about breakpoints

  • delete <breakpoint #>, d <breapoint #>: delete the supplied breakpoint

pdb

  • return: like the gdb finish command; continue execution until the current method returns
  • clear: like gdb delete
  • ignore <breakpoint #> <count>: ignore the specified breakpoint <count> number of times

Quick (contrived) gdb example

Take this example C++ code (I've saved as null_ptr.cpp (any idea what the error might be?)):

void foo()
{
  char *x = 0;
  *x = 3;
}

int main()
{
  foo();
  return 0;
}

Compile with debug symbols:

g++ -g -o null_ptr null_ptr.cpp

Execute

./null_ptr
Segmentation fault (core dumped)

Let's pretend we don't know what the error is. One thing you can do is actually load in the core file:

gdb <path to executable> <path to core file>

If you're running recent versions of Ubuntu, you're probably not going to see a core file in the same place that you executed your program. The reason is outlined here. But you can fix that by executing

ulimit -c unlimited

Sorry, I don't know about OS X or other flavors of Linux. If you open the core file, you're directed to the error right away, including subroutine and line number:

Core was generated by `./null_ptr'.
Program terminated with signal SIGSEGV, Segmentation fault.
#0  0x0000000000400566 in foo () at null_ptr.cpp:4
4     *x = 3;

You can reproduce the segmentation fault again within gdb simply by executing run. This will again terminate on the null pointer dereference.

How I use gdb

gdb --args <program to run>

Example: failed assert in C++ program

Some systems by default don't break on failed assertions (mine doesn't), meaning when the program fails, you can't inspect variables, etc. Solution is either

break abort

or

break exit

After failing assertion, examine backtrace with bt and then move up the stack trace with up into user land code. Note that after typing a command once, subsequent RET without any input will execute that previous command. After a single p xsec_names[j], I know exactly what the problem is.

Fun tip: You can print the contents of a vector with the command:

print *(myVector._M_impl._M_start)@myVector.size()

This stems from the more generic command to print N elements of an array starting at pointer P:

print *(P)@N

where here the starting address of our vector is given by myVector._M_impl._M_start

Example 2: inspect some routine

break CoupledFissionEigenKernel::computeQpResidual
break CoupledFissionEigenKernel::computeQpResidual if _qp == 1 && _group == 1
p _qp
p _group
l
n
n
p _chi[_qp][_group]
p computeConcentration((*_group_fluxes[i]), _qp)

Can try stepping many times to get into computeConcentration, but we'll discover all the std::vector::operator[] calls. Would be easier to just set a new breakpoint and then continue.

How I use pdb


In [2]:
cd ~/projects/moose/modules/navier_stokes/tests/ins/lid_driven/gold


/home/lindsayad/projects/moose/modules/navier_stokes/tests/ins/lid_driven/gold

In [3]:
import yt
ds = yt.load("lid_driven_out.e", step=-1)
slc = yt.SlicePlot(ds, 'z', ('all', 'vel_y'))


---------------------------------------------------------------------------
YTElementTypeNotRecognized                Traceback (most recent call last)
<ipython-input-3-fd5307248fe3> in <module>()
      1 import yt
      2 ds = yt.load("lid_driven_out.e", step=-1)
----> 3 slc = yt.SlicePlot(ds, 'z', ('all', 'vel_y'))

/home/lindsayad/yt-hg/yt/visualization/plot_window.py in SlicePlot(ds, normal, fields, axis, *args, **kwargs)
   2015             del kwargs['north_vector']
   2016 
-> 2017         return AxisAlignedSlicePlot(ds, normal, fields, *args, **kwargs)

/home/lindsayad/yt-hg/yt/visualization/plot_window.py in __init__(self, ds, axis, fields, center, width, axes_unit, origin, right_handed, fontsize, field_parameters, window_size, aspect, data_source)
   1332         PWViewerMPL.__init__(self, slc, bounds, origin=origin,
   1333                              fontsize=fontsize, fields=fields,
-> 1334                              window_size=window_size, aspect=aspect, right_handed=right_handed)
   1335         if axes_unit is None:
   1336             axes_unit = get_axes_unit(width, ds)

/home/lindsayad/yt-hg/yt/visualization/plot_window.py in __init__(self, *args, **kwargs)
    668             self._plot_type = kwargs.pop("plot_type")
    669         self._splat_color = kwargs.pop("splat_color", None)
--> 670         PlotWindow.__init__(self, *args, **kwargs)
    671 
    672     def _setup_origin(self):

/home/lindsayad/yt-hg/yt/visualization/plot_window.py in __init__(self, data_source, bounds, buff_size, antialias, periodic, origin, oblique, right_handed, window_size, fields, fontsize, aspect, setup)
    221                 self._field_transform[field] = linear_transform
    222         self.setup_callbacks()
--> 223         self._setup_plots()
    224 
    225     def _initialize_dataset(self, ts):

/home/lindsayad/yt-hg/yt/visualization/plot_window.py in _setup_plots(self)
    756             return
    757         if not self._data_valid:
--> 758             self._recreate_frb()
    759             self._data_valid = True
    760         self._colorbar_valid = True

/home/lindsayad/yt-hg/yt/visualization/plot_window.py in _recreate_frb(self)
    280         # At this point the frb has the valid bounds, size, aliasing, etc.
    281         if old_fields is None:
--> 282             self._frb._get_data_source_fields()
    283         else:
    284             # Restore the old fields

/home/lindsayad/yt-hg/yt/visualization/fixed_resolution.py in _get_data_source_fields(self)
    154         for f in fields:
    155             if f not in exclude and f[0] not in self.data_source.ds.particle_types:
--> 156                 self[f]
    157 
    158     def _is_ion( self, fname ):

/home/lindsayad/yt-hg/yt/visualization/fixed_resolution.py in __getitem__(self, item)
    133         buff = self.ds.coordinates.pixelize(self.data_source.axis,
    134             self.data_source, item, bounds, self.buff_size,
--> 135             int(self.antialias))
    136 
    137         for name, (args, kwargs) in self._filters:

/home/lindsayad/yt-hg/yt/geometry/coordinates/cartesian_coordinates.py in pixelize(self, dimension, data_source, field, bounds, size, antialias, periodic)
    113                                         indices,
    114                                         buff_size, field_data, extents,
--> 115                                         index_offset=offset)
    116 
    117             # re-order the array and squeeze out the dummy dim

/home/lindsayad/yt-hg/yt/utilities/lib/pixelization_routines.pyx in yt.utilities.lib.pixelization_routines.pixelize_element_mesh (yt/utilities/lib/pixelization_routines.c:8148)()

YTElementTypeNotRecognized: Element type not recognized - dim = 2, num_nodes = 9

In [4]:
%debug


> /home/lindsayad/projects/moose/modules/navier_stokes/tests/ins/lid_driven/gold/yt/utilities/lib/pixelization_routines.pyx(617)yt.utilities.lib.pixelization_routines.pixelize_element_mesh (yt/utilities/lib/pixelization_routines.c:8148)()

ipdb> p ndim
*** NameError: name 'ndim' is not defined
ipdb> p nvertices
*** NameError: name 'nvertices' is not defined
ipdb> where
  <ipython-input-3-fd5307248fe3>(3)<module>()
      1 import yt
      2 ds = yt.load("lid_driven_out.e", step=-1)
----> 3 slc = yt.SlicePlot(ds, 'z', ('all', 'vel_y'))

  /home/lindsayad/yt-hg/yt/visualization/plot_window.py(2017)SlicePlot()
   2013                   "an AxisAlignedSlicePlot object."
   2014             mylog.warn(msg)
   2015             del kwargs['north_vector']
   2016 
-> 2017         return AxisAlignedSlicePlot(ds, normal, fields, *args, **kwargs)

  /home/lindsayad/yt-hg/yt/visualization/plot_window.py(1334)__init__()
   1332         PWViewerMPL.__init__(self, slc, bounds, origin=origin,
   1333                              fontsize=fontsize, fields=fields,
-> 1334                              window_size=window_size, aspect=aspect, right_handed=right_handed)
   1335         if axes_unit is None:
   1336             axes_unit = get_axes_unit(width, ds)

  /home/lindsayad/yt-hg/yt/visualization/plot_window.py(670)__init__()
    668             self._plot_type = kwargs.pop("plot_type")
    669         self._splat_color = kwargs.pop("splat_color", None)
--> 670         PlotWindow.__init__(self, *args, **kwargs)
    671 
    672     def _setup_origin(self):

  /home/lindsayad/yt-hg/yt/visualization/plot_window.py(223)__init__()
    221                 self._field_transform[field] = linear_transform
    222         self.setup_callbacks()
--> 223         self._setup_plots()
    224 
    225     def _initialize_dataset(self, ts):

  /home/lindsayad/yt-hg/yt/visualization/plot_window.py(758)_setup_plots()
    756             return
    757         if not self._data_valid:
--> 758             self._recreate_frb()
    759             self._data_valid = True
    760         self._colorbar_valid = True

  /home/lindsayad/yt-hg/yt/visualization/plot_window.py(282)_recreate_frb()
    280         # At this point the frb has the valid bounds, size, aliasing, etc.
    281         if old_fields is None:
--> 282             self._frb._get_data_source_fields()
    283         else:
    284             # Restore the old fields

  /home/lindsayad/yt-hg/yt/visualization/fixed_resolution.py(156)_get_data_source_fields()
    154         for f in fields:
    155             if f not in exclude and f[0] not in self.data_source.ds.particle_types:
--> 156                 self[f]
    157 
    158     def _is_ion( self, fname ):

  /home/lindsayad/yt-hg/yt/visualization/fixed_resolution.py(135)__getitem__()
    133         buff = self.ds.coordinates.pixelize(self.data_source.axis,
    134             self.data_source, item, bounds, self.buff_size,
--> 135             int(self.antialias))
    136 
    137         for name, (args, kwargs) in self._filters:

  /home/lindsayad/yt-hg/yt/geometry/coordinates/cartesian_coordinates.py(115)pixelize()
    113                                         indices,
    114                                         buff_size, field_data, extents,
--> 115                                         index_offset=offset)
    116 
    117             # re-order the array and squeeze out the dummy dim

> /home/lindsayad/projects/moose/modules/navier_stokes/tests/ins/lid_driven/gold/yt/utilities/lib/pixelization_routines.pyx(617)yt.utilities.lib.pixelization_routines.pixelize_element_mesh (yt/utilities/lib/pixelization_routines.c:8148)()

ipdb> up
> /home/lindsayad/yt-hg/yt/geometry/coordinates/cartesian_coordinates.py(115)pixelize()
    113                                         indices,
    114                                         buff_size, field_data, extents,
--> 115                                         index_offset=offset)
    116 
    117             # re-order the array and squeeze out the dummy dim

ipdb> p coords
array([[ 0.     ,  0.     ],
       [ 0.0625 ,  0.     ],
       [ 0.0625 ,  0.0625 ],
       ..., 
       [ 1.     ,  0.96875],
       [ 0.96875,  1.     ],
       [ 0.96875,  0.96875]])
ipdb> p coords.shape
(1089, 2)
ipdb> p indices.shape
(256, 9)
ipdb> down
> /home/lindsayad/projects/moose/modules/navier_stokes/tests/ins/lid_driven/gold/yt/utilities/lib/pixelization_routines.pyx(617)yt.utilities.lib.pixelization_routines.pixelize_element_mesh (yt/utilities/lib/pixelization_routines.c:8148)()

ipdb> l

ipdb> list

ipdb> up
> /home/lindsayad/yt-hg/yt/geometry/coordinates/cartesian_coordinates.py(115)pixelize()
    113                                         indices,
    114                                         buff_size, field_data, extents,
--> 115                                         index_offset=offset)
    116 
    117             # re-order the array and squeeze out the dummy dim

ipdb> continue

If you know where you want to set breakpoints irrespective of abnormal execution...

import pdb; pdb.set_trace()

Example: halt nose test

Note that the breakpoints set in this way are hard-coded; they cannot be disabled, cleared, or ignored.

Example: invocation from command line

python -m pdb <script_name.py>

This drops you in on the first executable line of your script.