EmbLogic's Blog

How to use GDB with BT(Backtrace)

GDB is an essential tool for programmers to debug their code.
Breakpoints are the way to tell GDB to stop or pause the program execution at certain line, or function, or address. Once the program is stopped you can examine and change the variable values, continue the program execution from that breakpoint, etc.
Similar to breakpoints, backtrace is also helpful during debugging process to view and navigate the stack frame as explained in this tutorial

This tutorial requires some basic understanding of stack frame that we discussed in our memory layout of a process article.
C Code Example for GDB Backtrace
The following C program code example will be used in this tutorial to explain GDB backtrace.

#include
void func1();
void func2();
int main() {
int i=10;
func1();
printf(“In Main(): %d\n”,i);
}
void func1() {
int n=20;
printf(“In func1(): %d\n”,n);
func2();
}
void func2() {
int n = 30;
printf(“In func2() : %d\n”,n);
}
# cc -g stack.c

In a above code, main() will call func1() which inturn calls func2(). We will show how to examine the stack at each stage.
Getting a Backtrace in GDB
In this example, we had set a breakpoint at line number 20. So, the code stopped at func2() line 20 when we use gdb.
You can get the backtrace using ‘bt’ command as shown below.

# gdb
(gdb) file ./a.out
Reading symbols from /home/lakshmanan/a.out…done.
(gdb) b 20
Breakpoint 1 at 0×400579: file stack.c, line 20.
(gdb) run
Starting program: /home/lakshmanan/./a.out
In func1(): 20
Breakpoint 1, func2 () at stack.c:20
20 printf(“In func2() : %d\n”,n);
We already discussed how we can use GDB breakpoints to pause and continue a program execution from a particular point for debugging purpose.
From the output below, we know that currently we are in func2(), which is called by func1(), which was inturn called by main().

(gdb) bt
#0 func2 () at stack.c:20
#1 0×0000000000400568 in func1 () at stack.c:15
#2 0×0000000000400525 in main () at stack.c:9

Moving from one Frame to Another
You can move between the stack frames using ‘frame [number]’ as shown below.
In the below snippet, still the func2() is not returned, but we are able to move to frame 1 (which is func1) and examine the variable n’s value which is present inside func1().

(gdb) bt
#0 func2 () at stack.c:20
#1 0×0000000000400568 in func1 () at stack.c:15
#2 0×0000000000400525 in main () at stack.c:9
(gdb) p n
$1 = 30
(gdb) frame 1
#1 0×0000000000400568 in func1 () at stack.c:15
15 func2();
(gdb) p n
$2 = 20
In the snippet below, we have executed the next 2 instructions using ‘n 2’, and func2 is returned.
Now ‘bt’ tells you that you are currently in func1() which is called from main(), and the stack frame for func2 is gone.

(gdb) n 2
In func2() : 30
func1 () at stack.c:16
16 }
(gdb) bt
#0 func1 () at stack.c:16
#1 0×0000000000400525 in main () at stack.c:9
Get Information about a Stack Frame
You can get the information about a particular frame using ‘info frame [number]’ as shown below.

(gdb) info frame 0
Stack frame at 0x7fffffffe150:
rip = 0×400568 in func1 (stack.c:16); saved rip 0×400525
called by frame at 0x7fffffffe170
source language c.
Arglist at 0x7fffffffe140, args:
Locals at 0x7fffffffe140, Previous frame’s sp is 0x7fffffffe150
Saved registers:
rbp at 0x7fffffffe140, rip at 0x7fffffffe148

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>