gdb-best-friend/gdb-best-friend.tex

473 lines
13 KiB
TeX

\documentclass[slidestop,compress,blue]{beamer}
%\usetheme{default}
%\usetheme{Malmoe}
%\usetheme{Boadilla}
%\usetheme{umbc2}
%\usetheme{Antibes}
%\usetheme{Berlin}
%\usetheme{Madrid}
% Pacotes úteis
\usepackage[utf8]{inputenc}
% Fonte bonita!
\usepackage{ae,aecompl}
\usepackage[english]{babel}
\usepackage[T1]{fontenc}
\usepackage{listings}
\title{GDB, Your New Best Friend}
\author{Sergio Durigan Junior \\
\texttt{sergiodj@\{redhat.com,sergiodj.net\}}}
\date{\today}
\usetheme[secheader]{Madrid}
\setbeamertemplate{navigation symbols}{}
\defbeamertemplate*{footline}{infolines theme without institution}
{
\leavevmode%
\hbox{%
\begin{beamercolorbox}[wd=.333333\paperwidth,ht=2.25ex,dp=1ex,center]{author in head/foot}%
\usebeamerfont{author in head/foot}\insertshortauthor
\end{beamercolorbox}%
\begin{beamercolorbox}[wd=.333333\paperwidth,ht=2.25ex,dp=1ex,center]{title in head/foot}%
\usebeamerfont{title in head/foot}\insertshorttitle
\end{beamercolorbox}%
\begin{beamercolorbox}[wd=.333333\paperwidth,ht=2.25ex,dp=1ex,right]{date in head/foot}%
\usebeamerfont{date in head/foot}\insertshortdate{}\hspace*{2em}
\insertframenumber{} / \inserttotalframenumber\hspace*{2ex}
\end{beamercolorbox}}%
\vskip0pt%
}
\newcommand{\aspas}[1]{``#1''}
\newcommand{\gnu}{\texttt{GNU}}
\newcommand{\gdb}{\texttt{GDB}}
\newcommand{\gcc}{\texttt{GCC}}
\newcommand{\stap}{\texttt{SystemTap}}
\newcommand{\python}{\texttt{Python}}
\newcommand{\glibc}{\texttt{GLIBC}}
\newcommand{\kernel}{\textit{kernel}}
\newcommand{\probe}{\textit{probe}}
\newtheorem{sourcecode}{Source Code}
\begin{document}
\lstset{escapeinside={(*}{*)}}
\begin{frame}
\titlepage
\end{frame}
\begin{frame}
\frametitle{License}
\begin{itemize}
\item{License: \textbf{Attribution-ShareAlike 3.0 Unported (CC BY-SA 3.0)}}
\item{\url{http://creativecommons.org/licenses/by-sa/3.0/}}
\end{itemize}
\end{frame}
\section{Agenda}
\begin{frame}
\frametitle{Agenda}
\begin{itemize}
\item{Introduction}
% corefile
\item{The core of the file}
% Falar de multiprocess
\item{Multiprocess}
% Falar de probes, stap
\item{\stap{} \texttt{SDT} probes}
% Falar de catchpoints? catch syscall
% \item{Análise de uma \probe{}}
% Falar de depuração reversa
\item{gniggubeD esreveR}
% Falar de Python
\item{\python{}}
\item{Conclusion}
\end{itemize}
\end{frame}
\section{Introduction}
\begin{frame}[fragile]
\frametitle{Introduction}
\begin{itemize}
\item{\gdb{}: \gnu{} project's Debugger \pause{} (it is \textbf{not} a \textit{database}...). Supports several programming languages.}
\begin{itemize}
\item{\verb|#> gcc -g program.c -o program|}
\item{\verb|#> gdb ./program|}
\end{itemize}
\pause
\item{Before anything else! \verb|C-x a|}
\end{itemize}
\end{frame}
\section{The core of the file}
\begin{frame}[fragile]
\frametitle{The core of the file}
\begin{itemize}
\item{\texttt{corefile}s are ``frozen images'' of a certain point of execution inside a program.}
\pause
\item{To generate one on \gdb{}, at any time:}
\begin{itemize}
\item{\verb|(gdb) generate-core-file|}
\end{itemize}
\pause
\item{If you are seeing a segmentation fault, enable the \texttt{corefile} generation in your \texttt{shell}:}
\begin{itemize}
\item{\verb|#> ulimit -c unlimited|}
\end{itemize}
\pause
\item{And then open the \texttt{corefile} on \gdb{}:}
\begin{itemize}
\item{\verb|#> gdb program core.12345|}
\end{itemize}
\pause
\item{Inside \gdb{}, almost everything works. You can print variables, request a \texttt{backtrace}, change the current \texttt{frame}. You just cannot ``resurrect'' the program (i.e., execute it from that point) \verb|:-)|.}
\end{itemize}
\end{frame}
\section{Multiprocess}
\begin{frame}[fragile]
\frametitle{Multiprocess}
\begin{itemize}
\item{Given:}
\begin{block}{Makefile}
\tiny
\begin{lstlisting}[language=sh,showstringspaces=false]
all: run
run: segv
./segv
segv: segv.c
gcc -g -o segv segv.c
\end{lstlisting}
\end{block}
\begin{block}{segv.c}
\tiny
\begin{lstlisting}[language=c,showstringspaces=false]
int
main (int argc, char *argv[])
{
int *x = 0;
*x = 52;
return 0;
}
\end{lstlisting}
\end{block}
\end{itemize}
\end{frame}
\begin{frame}[fragile]
\frametitle{Multiprocess$^2$}
\begin{itemize}
\item{How do you debug the program from the example, which has a segmentation fault?}
\pause
\item{Multiprocess!}
\pause
\item{On \gdb{}:}
\begin{itemize}
\item{\verb|(gdb) set detach-on-fork off|}
\item{\verb|(gdb) set target-async on|}
\item{\verb|(gdb) set non-stop on|}
\item{\verb|(gdb) run|}
\item{(...)}
\item{\verb|(gdb) info inferiors|}
\end{itemize}
\item{(Yes, it is boring to type. Yes, we will improve it.)}
\pause
\item{Time for a hands-on!}
\end{itemize}
\end{frame}
\section{SystemTap SDT probes}
\begin{frame}[fragile]
\frametitle{\stap{} \texttt{SDT} probes}
\begin{itemize}
\item{Pre-req: \probe{} v3, \verb|systemtap-sdt-devel >= 1.4|.}
\begin{block}{Example code -- \texttt{example-stap.c}}
\tiny
\begin{lstlisting}[language=c,showstringspaces=false]
(*\textcolor{red}{\#\textbf{include}} \textcolor{red}{\textless{}sys/sdt.h\textgreater{}}*)
void foo (int a)
{
(*\textcolor{red}{STAP\_PROBE1 (}\textcolor{red}{example-stap, my\_probe, a}\textcolor{red}{);}*)
}
int main (int argc, char *argv[])
{
foo (10);
return 0;
}
\end{lstlisting}
\end{block}
\pause
\begin{block}{Compiling and verifying the \probe{}}
\tiny
\begin{lstlisting}[language=sh,showstringspaces=false]
$> gcc exemplo-stap.c -o exemplo-stap
$> stap -L '(*\textcolor{red}{process("./example-stap").mark("*")}*)'
process("./example-stap").mark("my_probe") $arg1:long
\end{lstlisting}
\end{block}
\end{itemize}
\end{frame}
\begin{frame}[fragile]
\frametitle{\stap{} \texttt{SDT} probes$^2$}
\begin{itemize}
\item{Available since \gdb{} 7.5, release in August, 2012.}
\pause
\item{Integrated with the \textit{breakpoint} system. Support for printing a \probe{}'s argument value.}
\pause
\item{\textcolor{red}{Not necessary to include debug information in your binary (\texttt{-g} flag); arguments are encoded directly in the asm.}}
\pause
\item{Also possible to use optmization flags (\texttt{-O}).}
\end{itemize}
\end{frame}
\begin{frame}[fragile]
\frametitle{\stap{} \texttt{SDT} probes$^3$}
\begin{itemize}
\item{Command \texttt{info probes}, list information about available \textit{probes}.}
\pause
\item{Command \texttt{break -probe-stap <probe\_name>}.}
\pause
\begin{itemize}
\item{Also possible to use \texttt{-probe} or \texttt{-p}.}
\end{itemize}
\pause
\item{Printing arguments for each \probe{}: internal \gdb{} variables.}
\begin{itemize}
\item{\texttt{\$\_probe\_argc}: number of arguments of the \probe{} (max: 12).}
\item{\texttt{\$\_probe\_arg$\{$0..11$\}$}: print argument \{0..11\}.}
\end{itemize}
\end{itemize}
\end{frame}
\begin{frame}[fragile]
\frametitle{\stap{} \texttt{SDT} probes$^4$}
\begin{itemize}
\item{After compiling your program (as shown previously):}
\begin{block}{Debugging \stap{} \texttt{SDT} probes}
\tiny
\begin{lstlisting}[language=sh,showstringspaces=false]
\$> gdb /tmp/example-stap
...
(gdb) info probes
Provider Name Where Semaphore Object
example-stap my_probe 0x000000000040047b /tmp/example-stap
(gdb) break -probe-stap my_probe
Breakpoint 1 at 0x40047b
(gdb) run
Starting program: /tmp/example-stap
Breakpoint 1, 0x000000000040047b in foo ()
(gdb) print $_probe_argc
$1 = 1
(gdb) print $_probe_arg0
$2 = 10
\end{lstlisting}
\end{block}
\end{itemize}
\end{frame}
\section{gniggubeD esreveR}
\begin{frame}[fragile]
\frametitle{gniggubeD esreveR}
\begin{itemize}
\item{Available since \gdb{} 7.0, released on September, 2009!}
\pause
\item{Implementation is kind of messy, but works in most cases...}
\pause
\item{Just works on x86/x86\_64 (patch for PowerPC is being made).}
\pause
\item{The hacker who did almost everything passed away. \verb|:-(|}
\begin{itemize}
\item{Old story: ``... if I die, who is going to maintain this code?''}
\end{itemize}
\end{itemize}
\end{frame}
\begin{frame}[fragile]
\frametitle{gniggubeD esreveR$^2$}
\begin{itemize}
\item{\verb|(gdb) start|}
\item{\verb|(gdb) target record-full|}
\item{Or, with a recent \gdb{}: \verb|(gdb) record|}
\item{(...)}
\item{Use the commands with the prefix \texttt{reverse}. \verb|reverse-next, reverse-step, reverse-nexti, reverse-stepi, set exec-direction reverse|...}
\end{itemize}
\end{frame}
\section{Python}
\begin{frame}[fragile]
\frametitle{\python{}}
\begin{itemize}
\item{Available since \gdb{} 7.0, too.}
\pause
\item{Motivation: make it easy to extend \gdb{} without having to mess with its internals.}
\pause
\item{Very well maintained, several extensions implemented.}
\pause
\item{Several projects already make use of it. Yours can be the next! \verb|:-)|}
\end{itemize}
\end{frame}
\begin{frame}[fragile]
\frametitle{\python{}$^2$}
\begin{itemize}
\item{Problem: \gdb{} knows about the \texttt{call stack}. \gdb{} also has conditional \texttt{breakpoints}.}
\pause
\item{\emph{However, you cannot use information from the \texttt{stack} in the condition of a \texttt{breakpoint}.}}
\pause
\item{Solution? Python!}
\end{itemize}
\end{frame}
\begin{frame}[fragile]
\frametitle{\python{}$^3$}
\begin{block}{caller\_is.py}
\tiny
\begin{lstlisting}[language=python,showstringspaces=false]
import gdb
class CallerIs (gdb.Function):
"""Return True if the calling function's name is equal to a string.
This function takes one or two arguments.
The first argument is the name of a function; if the calling function's
name is equal to this argument, this function returns True.
The optional second argument tells this function how many stack frames
to traverse to find the calling function. The default is 1."""
def __init__ (self):
super (CallerIs, self).__init__ ("caller_is")
def invoke (self, name, nframes = 1):
frame = gdb.selected_frame ()
while nframes > 0:
frame = frame.older ()
nframes = nframes - 1
return frame.name () == name.string ()
CallerIs()
\end{lstlisting}
\end{block}
\end{frame}
\begin{frame}[fragile]
\frametitle{\python{}$^4$}
\begin{itemize}
\item{To use it:}
\begin{block}{Using caller\_is.py}
\tiny
\begin{lstlisting}[language=sh,showstringspaces=false]
(gdb) source caller_is.py
(gdb) break foo if $caller_is ("bar")
\end{lstlisting}
\end{block}
\item{Internal variables and functions on \gdb{} start with \verb|$|.}
\item{\texttt{caller\_is.py} is part of upstream \gdb{}.}
\end{itemize}
\end{frame}
\begin{frame}[fragile]
\frametitle{\python{}$^5$}
\begin{itemize}
\item{Problem: \texttt{std::string s = "Hello, World";}}
\begin{block}{Printing ``s'' inside \gdb{}}
\tiny
\begin{lstlisting}[language=sh,showstringspaces=false]
(gdb) print s
$1 = {static npos = <optimized out>,
_M_dataplus = {<std::allocator<char>> =
{<__gnu_cxx::new_allocator<char>> = {<No data fields>},
<No data fields>}, _M_p = 0x602028 ``Hello, World''}}
\end{lstlisting}
\end{block}
\pause
\item{\gdb{} knows about \verb|_M_dataplus -> _M_p|. How to tell that this is the only field you are interested in?}
\pause
\item{Python!}
\end{itemize}
\end{frame}
\begin{frame}[fragile]
\frametitle{\python{}$^6$}
\begin{block}{print-std-string.py}
\tiny
\begin{lstlisting}[language=python,showstringspaces=false]
class StdStringPrinter:
"Print a std::basic_string of some kind"
def __init__(self, typename, val):
self.val = val
def to_string(self):
# ... snip ...
# Calculate the length of the string so that to_string returns
# the string according to length, not according to first null
# encountered.
(*\textcolor{red}{ptr = self.val ['\_M\_dataplus']['\_M\_p']}*)
realtype = type.unqualified ().strip_typedefs ()
reptype = gdb.lookup_type (str (realtype) + '::_Rep').pointer ()
header = ptr.cast(reptype) - 1
len = header.dereference ()['_M_length']
if hasattr(ptr, "lazy_string"):
return ptr.lazy_string (length = len)
return ptr.string (length = len)
\end{lstlisting}
\end{block}
\begin{itemize}
\pause
\item{Present on \verb|libstdcxx| upstream}
\end{itemize}
\end{frame}
\section{Conclusion}
\begin{frame}[fragile]
\frametitle{Conclusion}
\begin{itemize}
\item{The debugger you knew has changed for the better.}
\pause
\item{Things that are coming:}
\begin{itemize}
\item{Improvements in the multiprocess feature.}
\item{Scalability}
\item{Improvements for \texttt{C++}.}
\end{itemize}
\end{itemize}
\end{frame}
\section{Thank you's}
\begin{frame}[fragile]
\frametitle{Thank you's}
\begin{itemize}
\item{Red Hat}
\item{FSOSS}
\item{You guys and girls \verb|:-)|}
\end{itemize}
\end{frame}
\section{Questions}
\begin{frame}
\frametitle{Questions?}
\begin{center}
Shoot! Or send e-mail!
\end{center}
\end{frame}
\end{document}