Overview: GDB or GNU debugger is a tool to debug and inspect C/C++ programs. Programs can be in the form of simple application, static or dynamic link library or kernel module or other types. Here we mainly discuss about debugging an application.

Role of a Debugger: Now before we jump to GDB we must understand why do we need a debugger? Debuggers are used in many situations during entire development span of software. These situations start from the early program implementation till root causing crashes and panics. At early stage developer can use debugger to check the execution flow or to execute unit tests. This is like verifying developer’s own implementation during coding time. Now developers submit code for a release and quality assurance verifies this software. QA people simulate many use cases and error conditions and software may fail for one or more of these execution paths. These failures are like not proper error handing, memory corruptions, unexpected behaviors, undesired output etc. These are software bugs. Developer uses debuggers to root cause these issues. Developers run the same program in a debugger and execute the same use case or error scenarios as done by QA. This is called error reproduction. During this time debugger gives many facilities like pausing or breaking at a point, watching values of variables, modifying variables etc. These help developers to know the cause of this bug. That is why the name becomes de-bugger. Debugger also helps to take a memory dump of a program or running operating system during fatal error situations. These are called core-dump or crash for programs and blue screen/panic for operating system. Sometimes program or operating system can go through an execution path which can cause faults or violation to CPU or memory. These faults or error situations are handled by sending stop/abort signals to the process via operating system. As a result operating system triggers debugger to take a dump of memory and ends the execution. Same way operating system can suffer faults or panics. Panic handlers are written in such a way that it takes memory dump and halts the execution. These memory dumps are very useful for debugging the error path. It gives the full trace of the call stack when it hits the panic or fault. This is called offline debugging. Here no program/OS is running thus users cannot run the program. The only facility is to watch call stack, and inspect all parameters like jumping to call frames and watching local variables and also watching global variables and other necessary details. This offline debugging or core-dump analysis good to root cause or understand the failure situations.

GDB Details: Now we will discuss GDB and its usages. Debugging code with GDB needs some preparations. It requires a debug mode binary. This binary is compiled with no optimization and line by line debug information and symbol info. are present inside it in a separate section. Some compiler generates line by line debug info and symbol table in a separate file. To obtain this debug build we need to compile source code with gcc –g. This –g option tells compiler to generate debug info and symbol table for debugging. Generally it increases binary size and execution time may increase due to non-present of optimization flag. This build is generally used in development side for program inspection and bug finding. Released binary never have these options and it always includes optimization flag and thus size is reduced and thus execution speed also increased.

Loading binary using GDB
$gdb <binary name>
$gdb a.out
Putting a breakpoint with break/b:
(gdb) break <function name/filename [+ line offset]>
examples-
(gdb) break main
(gdb) break main+2
(gdb) break hello_world.c:20
or
(gdb) b main
(gdb) b main+2
(gdb) b hello_world.c:20
Running the program with run/r-
(gdb) run
or
(gdb) r
Continue to run when hitting a break-
(gdb) continue
or
(gdb) c
Stepping line by line-
(gdb) step
or
(gdb) s

GDB can display values of any global or local variable. GDB can do this when it is in break mode inside a function. Printing or displaying can be done with print/p command. GDB can print the values of global variables any time during execution. It is not same for the local variables. Local variables come to the context with it is inside that function. Thus it is obvious that we need to break inside the function to print its local variables.

(gdb) print <variable name/local/global>
or
(gdb) p <variable name/local/global>
examples-
(gdb) print local
(gdb) print i
(gdb) print global
Display many parameters with info command:
(gdb) info <parameters>

examples-
(gdb) info local
(gdb) info reg 
Setting global or local variable :
(gdb) set var <variable name>=<value>

examples-
(gdb) set var i=10
Display call stack or back trace:
(gdb) bracktrace
or
(gdb) bt
Switching to inner or outer call stack or frame with frame/f:
(gdb) frame <frame number>
or
(gdb) f <frame number>
examples-
(gdb) frame 2
(gdb) f 2
Quit from GDB:
(gdb) quit
or
(gdb) q

Example program [source code, and GDB run]:
$ cat hello.c
#include

void function (int i)
{
  printf ("Hello World %d\n", i);
}
int main (int argc, char *argv[])
{
  int count = 10;
  function (count);
  return 0;
}


$ gcc -g hello.c
$ ./a.out
Hello World 10
$ gdb a.out
GNU gdb (GDB) 7.2
(gdb) run
Starting program: /a.out
Hello World 10

Program exited normally.
(gdb) b main
Breakpoint 1 at 0x4004a6: file hello.c, line 9.
(gdb) run
Starting program: /a.out

Breakpoint 1, main (argc=1, argv=0x7fffffffe858) at hello.c:9
9         int count = 10;
(gdb) step
10        function (count);
(gdb) print count
$2 = 10
(gdb) break function
Breakpoint 2 at 0x400483: file hello.c, line 5.

Breakpoint 1, main (argc=1, argv=0x7fffffffe858) at hello.c:9
9         int count = 10;
(gdb) info reg
rax            0x3810753a60     240794286688
rbx            0x380f61bbc0     240776231872
rcx            0x4004d0 4195536
rdx            0x7fffffffe858   140737488349272
rsi            0x7fffffffe848   140737488349256
rdi            0x1      1
rbp            0x7fffffffe760   0x7fffffffe760
rsp            0x7fffffffe740   0x7fffffffe740
r8             0x38107522d0     240794280656
r9             0x380f40d620     240774075936
r10            0x0      0
r11            0x381041d8a0     240790919328
r12            0x0      0
r13            0x7fffffffe840   140737488349248
r14            0x0      0
r15            0x0      0
rip            0x4004a6 0x4004a6 
eflags         0x202    [ IF ]
cs             0x33     51
ss             0x2b     43
ds             0x0      0
es             0x0      0
fs             0x0      0
gs             0x0      0
(gdb) info local
count = 10
(gdb) continue
Continuing.

Breakpoint 2, function (i=10) at hello.c:5
5         printf ("Hello World %d\n", i);
(gdb) set var i=20
(gdb) c
Continuing.
Hello World 20

Program exited normally.
(gdb)

About our authors: Team EQA

You have viewed 1 page out of 252. Your C learning is 0.00% complete. Login to check your learning progress.

#