\documentclass[11pt]{article}
\usepackage{fontspec}
\usepackage[margin=25mm]{geometry}
\usepackage{tcolorbox}
\newtcolorbox{infobox}[1]%
{colback=blue!5!white,colframe=blue!75!black,fonttitle=\large\sffamily\bfseries,title=#1}
\newtcolorbox[auto counter]{listingbox}[2][]%
{colback=green!5!white,colframe=green!75!black,fonttitle=\large\sffamily\bfseries,title=Listing
\thetcbcounter: #2,#1}
\newtcolorbox{termbox}%
{colback=black!95!white,coltext=green!75!yellow,colframe=black}
\usepackage{sectsty}
\allsectionsfont{\bfseries\sffamily}
\usepackage{minted}
\setminted{autogobble}
\setlength\parindent{0pt}
\setlength\parskip{6pt plus 1pt minus 1pt}
\title{\bfseries\sffamily Notes and Tutorial on GDB}
\author{Jack Rosenthal}
\date{CSM Linux Users Group}
\begin{document}
\maketitle
\begin{infobox}{Note}
    This isn't a complete reference, but an unprofessional handy source. You
    might find out a lot more by reading the manual.
\end{infobox}
\tableofcontents
\section{Introduction}
\textbf{The GNU Debugger} (GDB) is an awesome tool for debugging your programs written
in C, C++, FORTRAN (please don't), and plenty of other compiled languages. You
can use it by running \texttt{gdb} from the command line.

\subsection{Compiling your programs for GDB}
GDB can make use of special symbols in your program to help you debug. Add the
\texttt{-ggdb3} flag to include these symbols. Example below:
\begin{termbox}
\begin{verbatim}
$ gcc -ggdb3 -std=c11 -o program.debug program.c
\end{verbatim}
\end{termbox}
This compiler flag works with \texttt{gcc}, \texttt{clang}, or any of their
related compilers (\texttt{g++}, etc.). Generally, you will only want to use
this flag for debugging, as it not only embeds the source of your program in
the binary, but also increases the size of the binary significantly. The rest
of this document assumes you have compiled with this flag when debugging.

Many people add a \texttt{debug} target to their \texttt{Makefile}, this allows
them to compile their program for debugging and start the debugger simply
typing \texttt{make debug}. The following listing contains a complete
\texttt{Makefile} example, it may be overkill for small projects.
\begin{listingbox}{A complete \texttt{Makefile} example}
    \inputminted{Makefile}{MakefileExample}
\end{listingbox}
This \texttt{Makefile} compliles a multifile project with all of the source
located at \texttt{src/*.c}.

\clearpage
\subsection{A basic example}
A coworker has handed you a simple C program they wrote, but is segfaulting.
They are fairly new to C programming\footnote{Your coworker also used the
$1^{\mathrm{st}}$ edition K\&R C book to learn} and would like your help
debugging. The program they wrote follows:
\begin{listingbox}[left=1cm]{Your coworker's program (\texttt{prog1.c})}
    \inputminted[linenos]{c}{prog1.c}
\end{listingbox}
Can you spot the bug? Not easy without a debugger. Let's throw it in
\texttt{gdb}! Start off by compiling with debugging symbols and starting
\texttt{gdb} on the program.
\begin{termbox}
\begin{verbatim}
$ gcc -ggdb3 -o prog1.debug prog1.c
$ gdb prog1.debug
\end{verbatim}
\end{termbox}
\clearpage
When \texttt{gdb} first starts, you will see this:
\begin{termbox}
\begin{verbatim}
GNU gdb (GDB) 7.10.1
Copyright (C) 2015 Free Software Foundation, Inc.
...
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from prog1.debug...done.
(gdb)
\end{verbatim}
\end{termbox}
\texttt{gdb} has near a gazillion commands, but we are going to want to use
either \texttt{start} or \texttt{run} here. \texttt{start} will create a
breakpoint at the start of \texttt{main} before running, whereas \texttt{run}
will run right away. If we wanted the program to read a file on standard input,
we could use the syntax \texttt{run < myfile} to read it. Go ahead and type
\texttt{run}, and give it the input ``\texttt{Hello, World!}'':
\begin{termbox}
\begin{verbatim}
(gdb) run
Starting program: prog1.debug
What would you like me to print? Hello, World!

Program received signal SIGSEGV, Segmentation fault.
0x00007ffff7aa0eb0 in __GI__IO_getline_info () from /usr/lib/libc.so.6
\end{verbatim}
\end{termbox}
Yikes! What caused that? We can generate a backtrace to see where this
happened. To do this, type \texttt{backtrace} (or, if you are lazy, \texttt{bt}
works too).
\begin{termbox}
\begin{verbatim}
(gdb) bt
#0 0x00007ffff7aa0eb0 in __GI__IO_getline_info () from /usr/lib/libc.so.6
#1 0x00007ffff7a9fe1d in fgets () from /usr/lib/libc.so.6
#2 0x0000000000400650 in read_str_buf (buf_sz=...) at prog1.c:12
#3 0x0000000000400680 in main (argc=1, argv=0x7fffffffe7e8) at prog1.c:24
\end{verbatim}
\end{termbox}
Well, obviously it was at that \texttt{fgets} on line 12. Let's \texttt{kill}
the program and restart it. We'll \texttt{break} at the start of
\texttt{read\_str\_buf} to inspect what may be happening there.
\begin{termbox}
\begin{verbatim}
(gdb) break read_str_buf
Breakpoint 1 at 0x400622: file prog1.c, line 11.
(gdb) run
Starting program: prog1.debug

Breakpoint 1, read_str_buf (buf_sz=...) at prog1.c:11
11          buf = malloc(buf_sz);
\end{verbatim}
\end{termbox}
Next, let's print some variables and step through some lines. We are going to
use a few commands:
\begin{tabular}{l l}
    \texttt{print \emph{varname}} & Print the value of \texttt{\emph{varname}},
    can be abbreviated to \texttt{p} \\
    \texttt{next} & Go to the next line, can be abbreviated to \texttt{n} \\
\end{tabular}
\begin{termbox}
\begin{verbatim}
(gdb) print buf_sz
$1 = 18446744071562067968
(gdb) next
12          fgets(buf, buf_sz, stdin);
(gdb) print buf
$2 = 0x0
(gdb) next
What would you like me to print? Hello, World?

Program received signal SIGSEGV, Segmentation fault.
0x00007ffff7aa0eb0 in __GI__IO_getline_info () from /usr/lib/libc.so.6
\end{verbatim}
\end{termbox}
Hopefully you said ``Hey that's it, \texttt{malloc} returned \texttt{NULL}''
when you printed \texttt{buf}. You can go ahead and type \texttt{quit} now, we
will come back to this example later.

Brownie points are available if you can name why:
\begin{enumerate}
    \item Even if the program worked, and allocated a reasonable amount of
        memory (say 1024), it would still leak memory.
    \item The prompt line did not print until we reached the \texttt{fgets}
    \item \texttt{buf\_sz} was 18446744071562067968, not 2147483648
    \item If line 12 was changed to read:
        \begin{minted}{c}
            buf = fgets(buf, buf_sz, stdin);
        \end{minted}
        the program would not segfault until line 25.
\end{enumerate}
\subsection{The Terminal User Interface}
Yes. \texttt{gdb} has a nice terminal user interface that you can access by
starting \texttt{gdb} with the \texttt{-tui} flag. This allows you to view each
line in the source code you are stepping through in a nice box above the
debugger. Sometimes the interface will get messed up and you will need to
redraw, simply type Ctrl+L to redraw it.

\section{Basic Features}
\subsection{Stepping through your code}
For stepping through your code, you will want to use the \texttt{step},
\texttt{next}, and \texttt{continue} (abbreviated to \texttt{s}, \texttt{n},
and \texttt{c}) commands.

\begin{itemize}
    \item The \texttt{step} command will execute whatever is on the current line
        \emph{stepping into function calls} if there are any.
    \item The \texttt{next} command will execute whatever is on the current
        line \emph{continuing through function calls} if there are any.
    \item The \texttt{continue} command will keep running your code until it
        reaches a breakpoint.
\end{itemize}

Using the program from earlier, here is an example. You may find it
helpful to use the TUI, so you can see which line you are at visually.
\begin{termbox}
\begin{verbatim}
(gdb) start
Temporary breakpoint 1 at 0x400669: file prog1.c, line 23.
Starting program: prog1.debug

Temporary breakpoint 1, main (argc=1, argv=0x7fffffffe7e8) at prog1.c:23
23              printf("What would you like me to print? ");
(gdb) next
24              str = read_str_buf(1<<31);
(gdb) step
read_str_buf (buf_sz=18446744071562067968) at prog1.c:11
11          buf = malloc(buf_sz);
(gdb) next
12          buf = fgets(buf, buf_sz - 1, stdin);
(gdb) next
What would you like me to print? Hello, World?

Program received signal SIGSEGV, Segmentation fault.
0x00007ffff7aa0eb0 in __GI__IO_getline_info () from /usr/lib/libc.so.6
\end{verbatim}
\end{termbox}
Notice how we used \texttt{step} to step into the \texttt{read\_str\_buf}
function call. If we used \texttt{next}, it would silently run that function without
taking us through it.

\subsection{Working with Variables}
\texttt{gdb} gives you full control of your variables at any time.

\begin{tabular}{l l}
    \texttt{print \emph{varname}} & Print the value of \texttt{\emph{varname}},
    can be abbreviated to \texttt{p} \\
    \texttt{set \emph{varname}=\emph{value}} & Set \texttt{\emph{varname}} to
    \texttt{\emph{value}} \\
    \texttt{print \emph{varname}=\emph{value}} & Set \texttt{\emph{varname}} to
    \texttt{\emph{value}} and print it \\
\end{tabular}

\texttt{\emph{value}} can be another variable.

To change frames, type \texttt{backtrace} to find the frame number to change
to, then type \texttt{frame \emph{n}} to change to frame \texttt{\emph{n}}.

To list all variables in this frame, type \texttt{info locals}. To list the
arguments to this frame, type \texttt{info args}. To get way too much
information about this frame, type \texttt{info frame}.

\begin{listingbox}[left=1cm]{\texttt{prog2.c}}
    \inputminted[linenos]{c}{prog2.c}
\end{listingbox}
\clearpage

\subsection{Breakpoints}
To set a breakpoint, use the incredibly powerful \texttt{break} command. The
general syntax is:
\begin{center}
    \texttt{break [$\langle \mathrm{location} \rangle$] [if $\langle
    \mathrm{condition} \rangle$]}
\end{center}
where $\langle \mathrm{location} \rangle$ can be:

\begin{tabular}{ l  l }
    A line number (current file assumed) & \texttt{lineno} \\
    A file name and line number & \texttt{file.c:lineno} \\
    A function name & \texttt{my\_function} \\
    A function name with namespace (for C++) & \texttt{std::my\_function} \\
    A function with types (for overloading in C++) & \texttt{my\_function(int)} \\
    The address of the program counter & \texttt{*0xfedcba76} \\
\end{tabular}

and $\langle \mathrm{condition} \rangle$ can be any valid conditional syntax in
your language (eg. \texttt{i == 32}). If the location is not specified, the
current program counter is assumed.

For our example, we are going to use the \texttt{prog2.c} program, which
reimplements \texttt{strdup}, but with a bug. The \texttt{main} function prints
all of the user's environment variables after they've been through
\texttt{my\_strdup} so you can see the bug (compare to the output of
\texttt{env}).

Load up this program in \texttt{gdb} and issue the following commands. Keep
pressing \texttt{c} whenever you reach a breakpoint, and notice how breakpoint
2 will only trigger when the first letter of the environment variable is H.
Neato!

\begin{termbox}
\begin{verbatim}
(gdb) break my_strlen
(gdb) break my_strdup if *in == 'H'
(gdb) run
\end{verbatim}
\end{termbox}

\subsection{Watchpoints}
You may want to break the program whenever a variable is changed or read. This
is called setting a watchpoint. The syntax is:

\begin{tabular}{l l}
    \texttt{watch \emph{x}} & break whenever \texttt{\emph{x}} is changed. \\
    \texttt{rwatch \emph{x}} & break whenever \texttt{\emph{x}} is read. \\
    \texttt{awatch \emph{x}} & break upon read or write \\
\end{tabular}

\subsection{Disabling and Enabling \{Break,Watch\}points}

If you are tired of breaking, you may want to disable a specific breakpoint. To
list breakpoints and their associated number \texttt{\emph{n}}, type
\texttt{info breakpoints}. Then, type \texttt{disable \emph{n}} or
\texttt{enable \emph{n}}.

\section{Advanced Magical Wizardry}

\subsection{Calling Functions}
\texttt{gdb} allows you to call one of your functions, or any function linked
to your program. Use the \texttt{call} command. Here is an example:

\begin{termbox}
\begin{verbatim}
(gdb) start
Temporary breakpoint 1 at 0x4006b7: file prog2.c, line 28.
Starting program: prog2.debug

Temporary breakpoint 1, main (argc=1, argv=0x7fffffffe7c8) at prog2.c:28
28          char **p = environ;
(gdb) call my_strlen("Hello, World!")
$1 = 13
\end{verbatim}
\end{termbox}

\subsection{Examining Memory}
\texttt{gdb} has an amazing command, \texttt{x}, but few people actually remember how
to use it without typing \texttt{help x}. Here is its syntax:

\begin{center}
    \texttt{x/$\langle\mathrm{amount}\rangle\langle\mathrm{format}\rangle\langle\mathrm{size}\rangle$
    $\langle\mathrm{variable\ or\ address}\rangle$}
\end{center}

$\langle\mathrm{amount}\rangle$ is the amount of objects of the specified size
to print. It will default to 1 if you don't specify it.

$\langle\mathrm{format}\rangle$ is a single character that specifies how it
should look when printed. Here are the different options:

\begin{tabular}{l l}
    \texttt{o} & octal \\
    \texttt{x} & hexadecimal \\
    \texttt{d} & decimal \\
    \texttt{u} & unsigned decimal \\
    \texttt{t} & binary \\
    \texttt{f} & float \\
    \texttt{a} & address \\
    \texttt{i} & instruction \\
    \texttt{c} & char \\
    \texttt{s} & string \\
    \texttt{z} & zero padded hexadecimal \\
\end{tabular}

$\langle\mathrm{size}\rangle$ specifies the size of the data to be printed. It
is also a single character. Here are the different options:

\begin{tabular}{l l}
    \texttt{b} & byte (8 bits) \\
    \texttt{h} & half word (16 bits) \\
    \texttt{w} & word (32 bits) \\
    \texttt{g} & giant word (64 bits) \\
\end{tabular}

That was awfully complex. For an example, let's examine \texttt{prog3.c}.

\begin{listingbox}[left=1cm]{\texttt{prog3.c}}
    \inputminted[linenos]{c}{prog3.c}
\end{listingbox}

Here are some examples:
\begin{termbox}
\begin{verbatim}
(gdb) start
Temporary breakpoint 1 at 0x400555: file prog3.c, line 6.
Starting program: prog3.debug

Temporary breakpoint 1, main (argc=1, argv=0x7fffffffe7c8) at prog3.c:6
6           char *str = strdup("Hello, World!\n");
(gdb) n
7           int x = 42;
(gdb) x/s str
0x601010:       "Hello, World!\n"
(gdb) x/c str
0x601010:       72 'H'
(gdb) x/6c str
0x601010:       72 'H'  101 'e' 108 'l' 108 'l' 111 'o' 44 ','
(gdb) n
8           int *y = &x;
(gdb) n
9           double pi = 3.1415926535897932384;
(gdb) x/tw y
0x7fffffffe6c4: 00000000000000000000000000101010
(gdb) n
10          double *pi_ptr = &pi;
(gdb) n
11          if (*str && x && *y && *(int *)pi_ptr)
(gdb) x/tg pi_ptr
0x7fffffffe6b8: 0100000000001001001000011111101101010100010001000010110100011000
\end{verbatim}
\end{termbox}

\subsection{When things get so bad to the point where you are dealing with assembly code}

You may want to \texttt{disassemble} part of the program:
\begin{termbox}
\begin{verbatim}
(gdb) disassemble main
Dump of assembler code for function main:
   0x0000000000400546 <+0>:     push   %rbp
   0x0000000000400547 <+1>:     mov    %rsp,%rbp
   0x000000000040054a <+4>:     sub    $0x40,%rsp
   0x000000000040054e <+8>:     mov    %edi,-0x34(%rbp)
...
\end{verbatim}
\end{termbox}

Maybe examine the registers:
\begin{termbox}
\begin{verbatim}
(gdb) info registers
rax            0x601010         6295568
rbx            0x0              0
rcx            0xa21646c726f57  2851464966991703
rdx            0x0              0
rsi            0x400657         4195927
...
\end{verbatim}
\end{termbox}

You can also use \texttt{nexti} and \texttt{stepi} to step instructions (rather
than lines).

You my friend, have achieved GDB wizard status.

\end{document}
