5.6 C++ source code debuggers

5.6.1 Introduction to the GNU gdb debugger

This section provides a brief overview on using gdb for debugging OOMMF programs. For a more thorough background you can refer to the extensive documentation available from the GNU Project or the many online tutorials.

In the following examples, the (bash) shell prompt is indicated by $, and the gdb prompt with (gdb). You launch gdb from the command line with the name of the executable file. You can provide arguments to the executable when you run the program inside gdb. For example, to debug a problem with an Oxs extension, we would run Boxsi with a sample troublesome .mif file, say

$ cd oommf/app/oxs
$ gdb linux-x86_64/oxs
(gdb) run boxsi.tcl local/foo/foo.mif -threads 1
Subsequent run commands will reuse the same arguments unless you specify new ones. In this example the -threads 1 option to Boxsi is used to simplify the debugging process. If you need or want to debug with multiple threads, then read up on the “thread” command in the gdb documentation.

The program run will automatically terminate and return to the (gdb) prompt if the program exits or aborts. Alternately you can Ctrl-C at any time to manually halt. To exit gdb type quit at the (gdb) prompt.

gdb has a large collection of commands that you can use to control program flow and inspect program data. An example we saw before is backtrace, which can be abbreviated as bt. Fig. 5.3 lists a few of the more common commands, and Figs. 5.4 and 5.5 provide an example debugging session illustrating their use.

 

Figure 5.3: gdb Debugger Cheatsheet  (description)
Shellcommand: gdb linux-x86_64/oxs [corefile (opt)]
Command Abbr. Description
Process control
run [args] run executable with args
run run executable with last args
show args display current args
set env FOO bar set envr. variable FOO to “bar”
unset env FOO unset environment variable FOO
Ctrl-C stop and return to (gdb) prompt
kill terminate current run
quit exit gdb
Introspection
backtrace bt stack trace
frame 7 f 7 change to stack frame 7
list 123 l 123 list source about line 123
list foo.cc:50 list source about line 50 of foo.cc
list - l - list preceding ten lines
list foo::bar list first ten lines of function foo::bar()
set listsize 20 change list output length to 20 lines
info locals i lo print local variables
info args print function arguments
print foo p foo write info on variable foo
printf "%g", foo print foo with format %g (note comma)
Flow control
break bar.cc:13 b bar.cc:13 set breakpoint at line 13 of bar.cc
break foo::bar b foo::bar break on entry to C++ routine foo::bar()
info breakpoints i b list breakpoints
delete 4 d 4 delete breakpoint 4
delete d delete all breakpoints
ignore 3 100 skip breakpoint 3 100 times
watch -location foo break when foo changes value
condition 2 foo>10 break if foo>10 at breakpoint 2
continue c continue running
step [#] s [#] take # steps, follow into subroutines
next [#] n [#] take # steps, step over subroutines
finish run to end of current subroutine (step out)
Threads
info threads i th list threads
thread 4 t 4 switch context to thread 4

 

 

Figure 5.4: Sample gdb session, part 1: Locating the error (description)
$ cd app/oxs
$ gdb linux-x86_64/oxs
(gdb) run boxsi.tcl examples/stdprob1.mif -threads 1
Starting program: oommf/app/oxs/linux-x86_64/oxs boxsi.tcl examples/stdp...
oxs: oommf/app/oxs/base/meshvalue.h:319: const T& Oxs_MeshValue<T>::oper...
  Assertion ‘0<=index && index<size’ failed.

Thread 1 "oxs" received signal SIGABRT, Aborted.
0x00007ffff65d837f in raise () from /lib64/libc.so.6
(gdb) bt
#0  0x00007ffff65d837f in raise () from /lib64/libc.so.6
[...]
#4  0x000000000041012a in Oxs_MeshValue<double>::operator[]
  (this=0xcbeb58, index=40000) at oommf/app/oxs/base/meshvalue.h:319
#5  0x000000000061e88a in Oxs_UniaxialAnisotropy::RectIntegEnergy
  (this=0x1307d60, state=..., ocedt=..., ocedtaux=..., node_start=36864,
  node_stop=40000) at oommf/app/oxs/ext/uniaxialanisotropy.cc:241
[...]
(gdb) frame 5
#5  0x000000000061e88a in Oxs_UniaxialAnisotropy::RectIntegEnergy...
241           field_mult = (2.0/MU0)*k*Ms_inverse[i];
(gdb) set listsize 5
(gdb) list
239         if(aniscoeftype == K1_TYPE) {
240           if(!K1_is_uniform) k = K1[i];
241           field_mult = (2.0/MU0)*k*Ms_inverse[i];
242         } else {
243           if(!Ha_is_uniform) field_mult = Ha[i];
(gdb) print i
$1 = 40000
(gdb) print Ms_inverse
$2 = (const Oxs_MeshValue<double> &) @0xcbeb58: {arr = 0x7ffff7ebf000,
  size = 40000, arrblock = {datablock = 0x7ffff7ebe010 "",
  arr = 0x7ffff7ebf000, arr_size = 40000, strip_count = 1,
  strip_size = 320000, strip_pos = std::vector of length 2,
  capacity 2 = {0, 320000}}, static MIN_THREADING_SIZE = 10000}
(gdb) kill
Kill the program being debugged? (y or n) y
[Inferior 1 (process 1309854) killed]

 

 

Figure 5.5: Sample gdb session, part 2: Bug details (description)
(gdb) break uniaxialanisotropy.cc:239
Breakpoint 1 at 0x61e811: file ext/uniaxialanisotropy.cc, line 239.
(gdb) run
Starting program: oommf/app/oxs/linux-x86_64/oxs boxsi.tcl examples/s...
[...]
Thread 1 "oxs" hit Breakpoint 1, Oxs_UniaxialAnisotropy::RectIntegEne...
239         if(aniscoeftype == K1_TYPE) {
(gdb) info breakpoints
Num     Type           Disp Enb Address            What
1       breakpoint     keep y   0x000000000061e811 in Oxs_UniaxialAni...
        breakpoint already hit 1 time
(gdb) ignore 1 39999
Will ignore next 39999 crossings of breakpoint 1.
(gdb) continue

Thread 1 "oxs" hit Breakpoint 1, Oxs_UniaxialAnisotropy::RectIntegEne...
239         if(aniscoeftype == K1_TYPE) {
(gdb) print i
$3 = 39991
(gdb) condition 1 i>=40000
(gdb) c

Thread 1 "oxs" hit Breakpoint 1, Oxs_UniaxialAnisotropy::RectIntegEne...
239         if(aniscoeftype == K1_TYPE) {
(gdb) l
237
238       for(OC_INDEX i=node_start;i<=node_stop;++i) {
239         if(aniscoeftype == K1_TYPE) {
240           if(!K1_is_uniform) k = K1[i];
241           field_mult = (2.0/MU0)*k*Ms_inverse[i];
(gdb) next
240           if(!K1_is_uniform) k = K1[i];
(gdb) n
241           field_mult = (2.0/MU0)*k*Ms_inverse[i];
(gdb) step
Oxs_MeshValue<double>::operator[] (this=0xcbeb58, index=40000)
  at oommf/app/oxs/base/meshvalue.h:319
319       assert(0<=index && index<size);
(gdb) printf "%d,%d\n", index, size
40000,40000
(gdb) quit

 

Two notes concerning gdb on macOS: First, as mentioned earlier, if you install gdb through MacPorts, the executable name is ggdb. Second, debuggers operate outside the normal end-user program envelope and may run afoul of the OS security system. In particular to use gdb you may need to set up a certificate in the macOS System Keychain for it; details on this process can be found online. This issue might be resolved for lldb (next section) as part of the installation process if it and clang++ were installed as part of the Xcode package.

This introduction only scratches the surface of gdb commands and capabilities. You can find tutorials and additional information online, or else refer to the gdb documentation from GNU for full details.