From 4b3bbbe2c49a4e5c06099d3597e6aa5a076e4d3f Mon Sep 17 00:00:00 2001 From: Sergio Durigan Junior Date: Mon, 3 Jun 2019 10:36:07 -0400 Subject: [PATCH] First version of the slides, with examples. --- examples/corefile/1.c | 28 ++ examples/points/Makefile | 10 + examples/points/breakwatch.c | 40 +++ examples/points/catch.c | 31 +++ examples/points/hello.c | 28 ++ examples/python/pretty-print/1.cpp | 9 + examples/python/pretty-print/str.py | 29 ++ examples/reverse/1.c | 23 ++ examples/reverse/1.h | 1 + examples/reverse/2.c | 17 ++ examples/reverse/2.h | 3 + examples/stap-probe/1.c | 41 +++ examples/stap-probe/README | 2 + examples/stap-probe/baz.c | 12 + gdb-intro-kwlug.org | 270 ++++++++++++++++++ gdb-intro-kwlug.tex | 411 ++++++++++++++++++++++++++++ 16 files changed, 955 insertions(+) create mode 100644 examples/corefile/1.c create mode 100644 examples/points/Makefile create mode 100644 examples/points/breakwatch.c create mode 100644 examples/points/catch.c create mode 100644 examples/points/hello.c create mode 100644 examples/python/pretty-print/1.cpp create mode 100644 examples/python/pretty-print/str.py create mode 100644 examples/reverse/1.c create mode 100644 examples/reverse/1.h create mode 100644 examples/reverse/2.c create mode 100644 examples/reverse/2.h create mode 100644 examples/stap-probe/1.c create mode 100644 examples/stap-probe/README create mode 100644 examples/stap-probe/baz.c create mode 100644 gdb-intro-kwlug.org create mode 100644 gdb-intro-kwlug.tex diff --git a/examples/corefile/1.c b/examples/corefile/1.c new file mode 100644 index 0000000..1a7c340 --- /dev/null +++ b/examples/corefile/1.c @@ -0,0 +1,28 @@ +static void foo_segv (void); + +static void +bar (void) +{ + foo_segv (); +} + +static void +foo_segv (void) +{ + int *x = 0; + + *x = 5; +} + +static void +baz (void) +{ + bar (); +} + +int +main (int argc, char *argv[]) +{ + baz (); + return 0; +} diff --git a/examples/points/Makefile b/examples/points/Makefile new file mode 100644 index 0000000..17ebd6d --- /dev/null +++ b/examples/points/Makefile @@ -0,0 +1,10 @@ +CC = gcc +CFLAGS = -g3 -O0 + +all: breakwatch catch hello + +%.o: %.c + $(CC) -o $@ -c $< $(CFLAGS) + +clean: + rm -f breakwatch catch hello diff --git a/examples/points/breakwatch.c b/examples/points/breakwatch.c new file mode 100644 index 0000000..5af758d --- /dev/null +++ b/examples/points/breakwatch.c @@ -0,0 +1,40 @@ +/* points.c -- Break and watch examples. */ + +#include + +struct sttest +{ + int index; + char name[15]; + int value; +}; + +int +test_func (int n) +{ + int r; + + r = n + 10; + r += 20; + + return r; +} + +int +main (int argc, char **argv) +{ + int a, b, i; + struct sttest example_struct[10]; + + a = 5; + b = test_func (a) / 10; + + for (i = 0; i < 10; i++) + { + example_struct[i].index = i; + sprintf (example_struct[i].name, "element %d", i); + example_struct[i].value = test_func (i); + } + + return 0; +} diff --git a/examples/points/catch.c b/examples/points/catch.c new file mode 100644 index 0000000..3c890ea --- /dev/null +++ b/examples/points/catch.c @@ -0,0 +1,31 @@ +/* catch.c -- Example for 'catch fork' and 'catch syscall'. */ + +#include +#include + +void +test (void) +{ + if (fork () == 0) + printf ("Child\n"); + + fork (); +} + +void +another_test (const char *p) +{ + chdir (p); +} + +int +main (int argc, char **argv) +{ + int a; + + test (); + + another_test ("."); + + return 0; +} diff --git a/examples/points/hello.c b/examples/points/hello.c new file mode 100644 index 0000000..deb1df2 --- /dev/null +++ b/examples/points/hello.c @@ -0,0 +1,28 @@ +/* hello.c -- Segfault example. */ + +#include +#include + +int +print (char *msg) +{ + printf ("%s\n", msg); + return 0; +} + +int +hello (char *param) +{ + strcpy (param, "Hello World!"); + print (param); +} + +int +main (int argc, char **argv) +{ + char *str = "Hi!"; + + hello (str); + + return 0; +} diff --git a/examples/python/pretty-print/1.cpp b/examples/python/pretty-print/1.cpp new file mode 100644 index 0000000..dd3f378 --- /dev/null +++ b/examples/python/pretty-print/1.cpp @@ -0,0 +1,9 @@ +#include + +int +main () +{ + std::string x = "Hello Upstream"; + + return 0; +} diff --git a/examples/python/pretty-print/str.py b/examples/python/pretty-print/str.py new file mode 100644 index 0000000..6d80b6b --- /dev/null +++ b/examples/python/pretty-print/str.py @@ -0,0 +1,29 @@ +import gdb.printing +import re + +class StdStringPrinter: + + def __init__ (self, val): + self.val = val + + def to_string (self): + return self.val['_M_dataplus']['_M_p'] + + def display_hint (self): + return 'string' + +def str_lookup_function(val): + bbb = {} + try: + bbb = val.type.fields () + except: + pass + found = 0 + for x in bbb: + if x.name == '_M_dataplus': + found = 1 + if found == 1: + return StdStringPrinter(val) + return None + +gdb.printing.register_pretty_printer (gdb, str_lookup_function) diff --git a/examples/reverse/1.c b/examples/reverse/1.c new file mode 100644 index 0000000..32de183 --- /dev/null +++ b/examples/reverse/1.c @@ -0,0 +1,23 @@ +#include "2.h" + +void +foo (int v) +{ + int a = 0; + + a = 10 + 20; + a += v; + + bar (&a); + bar (0); + + a = 0; +} + +int +main (int argc, char *argv[]) +{ + initialize (); + + return 0; +} diff --git a/examples/reverse/1.h b/examples/reverse/1.h new file mode 100644 index 0000000..bd26dfc --- /dev/null +++ b/examples/reverse/1.h @@ -0,0 +1 @@ +void foo (int v); diff --git a/examples/reverse/2.c b/examples/reverse/2.c new file mode 100644 index 0000000..6f22119 --- /dev/null +++ b/examples/reverse/2.c @@ -0,0 +1,17 @@ +#include "1.h" + +void +initialize (void) +{ + int n = 0; + + n = 12314314 % 453; + foo (n); +} + +void +bar (int *v) +{ + if (v != 0) + *v += 12314314 % 453; +} diff --git a/examples/reverse/2.h b/examples/reverse/2.h new file mode 100644 index 0000000..90955dd --- /dev/null +++ b/examples/reverse/2.h @@ -0,0 +1,3 @@ +void initialize (void); + +void bar (int *v); diff --git a/examples/stap-probe/1.c b/examples/stap-probe/1.c new file mode 100644 index 0000000..c61a92f --- /dev/null +++ b/examples/stap-probe/1.c @@ -0,0 +1,41 @@ +#include + +struct baz + { + int a; + char b; + union + { + int c; + char d; + } u; + }; + +static void +foo (int a, const char *b) +{ + STAP_PROBE2 (test, probefoo, a, b); +} + +static void +bar (const struct baz *a) +{ + STAP_PROBE1 (test, probebar, a); +} + +int +main (int argc, char *argv[]) +{ + int i1 = 1; + const char *s = "String test"; + struct baz b; + + b.a = 49; + b.b = 'y'; + b.u.d = 'a'; + + foo (i1, s); + bar (&b); + + return 0; +} diff --git a/examples/stap-probe/README b/examples/stap-probe/README new file mode 100644 index 0000000..4646f00 --- /dev/null +++ b/examples/stap-probe/README @@ -0,0 +1,2 @@ +Compiling with -Ox (x > 0) changes the layout of the symbols in the memory. +If you want to access a structure field, refer to it explicitly in the probe argument. diff --git a/examples/stap-probe/baz.c b/examples/stap-probe/baz.c new file mode 100644 index 0000000..c95af1b --- /dev/null +++ b/examples/stap-probe/baz.c @@ -0,0 +1,12 @@ +struct baz + { + int a; + char b; + union + { + int c; + char d; + } u; + }; + +struct baz blabla; diff --git a/gdb-intro-kwlug.org b/gdb-intro-kwlug.org new file mode 100644 index 0000000..4f6ec20 --- /dev/null +++ b/gdb-intro-kwlug.org @@ -0,0 +1,270 @@ +#+OPTIONS: toc:nil date:nil +#+SELECT_TAGS: export +#+EXCLUDE_TAGS: noexport +#+CREATOR: Emacs 26.1 (Org mode 9.1.9) +#+TITLE: GDB Intro +#+AUTHOR: Sergio Durigan Junior @@latex:\\@@ sergiodj@{sergiodj.net,redhat.com,debian.org} +#+LANGUAGE: en +#+LATEX_HEADER: \usepackage{listings} +#+LATEX_HEADER: \lstdefinestyle{customc}{belowcaptionskip=1\baselineskip,breaklines=true,frame=L,xleftmargin=\parindent,language=C,showstringspaces=false,basicstyle=\footnotesize\ttfamily,keywordstyle=\bfseries\color{green!40!black},commentstyle=\itshape\color{purple!40!black},identifierstyle=\color{blue},stringstyle=\color{orange},} + +* License + +- License: *Creative Commons Attribution 4.0 International License (CC-BY-4.0)* + +- https://creativecommons.org/licenses/by/4.0/ + +* Agenda + +- Blabla + +* Introduction + +- =GDB=: =GNU= project's Debugger @@latex:\pause@@ (it is *not* a + /database/...). Supports several programming languages. + +- Started around 1986 by Richard Stallman (after *GNU Emacs*, but + likely before *GCC*). + +* Compiling your program for GDB + +- Your program needs to contain *debug information* (also called + =DWARF=) for GDB to consume. + +#+BEAMER: \pause + +- The GCC flag to include debug information is =-g=. We also use + =-g3=, which includes information about macros (=#define=). + +#+BEAMER: \pause + +- It's common to *disable optimizations* when building the binary, by + using the flag =-O0= (it's /dash-oh-zero/). + + #+BEAMER: \pause + + - =# gcc -O0 -g program.c -o program=, /or/ + + - ~# CFLAGS='-O0 -g' ./configure && make~ + +* Running your program using GDB + +- In GDB's parlance, the program being debugged is called the + *inferior*. + +#+BEAMER: \pause + +- Some ways to start the debugger: + + #+BEAMER: \pause + + - =# gdb ./program= + + #+BEAMER: \pause + + - =# gdb --args ./program arg1 arg2= + + #+BEAMER: \pause + + - =# gdb= @@latex: \\@@ + =(gdb) file ./program= @@latex: \\@@ + =(gdb) run arg1 arg2= + +* {Break,Catch,Watch}points + +- A *breakpoint* is related to /source code/ (location, function). A + *watchpoint* is related to /data/ (read/write of a variable). A + *catchpoint* is related to an /event/ (enter/exit a syscall, fork, + receive a signal). + +#+BEAMER: \pause + +- Breakpoints (/code/) + + - =break= + + - =tbreak= (temporary) + +#+BEAMER: \pause + +- Watchpoints (/data/) + + - =watch= (write), =rwatch= (read), =awatch= (access) + + - Conditional watchpoints are supported. + +#+BEAMER: \pause + +- Catchpoints (/events/) + + - =catch fork= + + - =catch syscall= + +* Resuming the execution + +- After GDB has stopped the inferior (because a =*point= has been hit, + for example), you will probably want to resume its execution. + +#+BEAMER: \pause + +- You may just want to continue the program: + + - =continue= + +#+BEAMER: \pause + +- Or maybe go to the next statement/instruction: + + - =next= (/statement/), or =nexti= (/instruction/) + +#+BEAMER: \pause + +- Or step into a function: + + - =step= (/statement/), or =stepi= (/instruction/) + +#+BEAMER: \pause + +- Or finish executing the current function, but stop at the end: + + - =finish= + + + +* Examining data + +- The inferior has stopped... Now what? + +#+BEAMER: \pause + +- You may want to print the value of some variable: + + - =print VAR= + +#+BEAMER: \pause + +- Or examine a memory location: + + - =x ADDRESS= + +#+BEAMER: \pause + +- The type of a variable? Easy: + + - =whatis VARIABLE= + +#+BEAMER: \pause + +- Hint: you may want to enable pretty-printing: + + - =set print pretty on= + +* Examining the code + +- Yes, we have =ncurses=! The @@latex:\textbf{T}@@ext + @@latex:\textbf{U}@@user @@latex:\textbf{I}@@nterface! + + - =C-x a= (that's =CTRL x a=). + +#+BEAMER: \pause + +- If you want to list the current region, or if you don't want/can't + to use TUI: + + - =list= + +#+BEAMER: \pause + +- You can also disassemble code: + + - =disassemble= + +#+BEAMER: \pause + +- If GDB can't find the source code, you can specify its location + using the =dir= command. + +* Examining the call stack + +- If you want to see the call stack (A.K.A. stack trace) that lead to + the current function: + + - =bt= + +#+BEAMER: \pause + +- And you can move through it: + + - =up= and =down= + + - You can also go to a specific frame: =frame NUMBER= + +* Corefiles + +- *Corefiles* are frozen images of the inferior. You can inspect + everything that was happening when the process was running (but you + can't resurrect it). + +#+BEAMER: \pause + +- You can generate them /outside/ GDB, when a program crashes. Make + sure you: + + - =ulimit -c unlimited= + + - Check if =systemd= is handling them + (=/proc/sys/kernel/core_pattern=). + +#+BEAMER: \pause + +- You can also generate them /inside/ GDB, at any moment: + + - =generate-core-file= + +#+BEAMER: \pause + +- You can open a corefile using GDB: + + - =# gdb program -c corefile.PID= + +* Other interesting information + +- =info breakpoints= + +- =info locals= + +- =info registers= + +- Many others! + +* Who you gonna call? + +- Our online documentation (=info=) is very good! + +- Every command has a =help=. + +- You can also use =apropos= when searching for a term. + +- =TAB=-completion is also useful. + +* Other advanced features + +- Python support. + +- Reverse debugging. + +- Support for /SystemTap SDT probes/. + +* End + + +#+ATTR_LATEX: :options style=customc +#+begin_src c -n +int main () +{ + const char *c = NULL; + + return 0; +} +#+end_src diff --git a/gdb-intro-kwlug.tex b/gdb-intro-kwlug.tex new file mode 100644 index 0000000..855b0cd --- /dev/null +++ b/gdb-intro-kwlug.tex @@ -0,0 +1,411 @@ +% Created 2019-06-02 Sun 21:20 +% Intended LaTeX compiler: pdflatex +\documentclass[presentation]{beamer} +\usepackage[utf8]{inputenc} +\usepackage[T1]{fontenc} +\usepackage{graphicx} +\usepackage{grffile} +\usepackage{longtable} +\usepackage{wrapfig} +\usepackage{rotating} +\usepackage[normalem]{ulem} +\usepackage{amsmath} +\usepackage{textcomp} +\usepackage{amssymb} +\usepackage{capt-of} +\usepackage{hyperref} +\usepackage{color} +\usepackage{listings} +\usepackage{listings} +\lstdefinestyle{customc}{belowcaptionskip=1\baselineskip,breaklines=true,frame=L,xleftmargin=\parindent,language=C,showstringspaces=false,basicstyle=\footnotesize\ttfamily,keywordstyle=\bfseries\color{green!40!black},commentstyle=\itshape\color{purple!40!black},identifierstyle=\color{blue},stringstyle=\color{orange},} +\usetheme{default} +\author{Sergio Durigan Junior \\ sergiodj@\{sergiodj.net,redhat.com,debian.org\}} +\date{} +\title{GDB Intro} +\hypersetup{ + pdfauthor={Sergio Durigan Junior \\ sergiodj@\{sergiodj.net,redhat.com,debian.org\}}, + pdftitle={GDB Intro}, + pdfkeywords={}, + pdfsubject={}, + pdfcreator={Emacs 26.1 (Org mode 9.1.9)}, + pdflang={English}} +\begin{document} + +\maketitle + +\begin{frame}[label={sec:orga1f4768}]{License} +\begin{itemize} +\item License: \alert{Creative Commons Attribution 4.0 International License (CC-BY-4.0)} + +\item \url{https://creativecommons.org/licenses/by/4.0/} +\end{itemize} +\end{frame} + +\begin{frame}[label={sec:org13db7cc}]{Agenda} +\begin{itemize} +\item Blabla +\end{itemize} +\end{frame} + +\begin{frame}[fragile,label={sec:orgcb90a6c}]{Introduction} + \begin{itemize} +\item \texttt{GDB}: \texttt{GNU} project's Debugger \pause (it is \alert{not} a +\emph{database}\ldots{}). Supports several programming languages. + +\item Started around 1986 by Richard Stallman (after \alert{GNU Emacs}, but +likely before \alert{GCC}). +\end{itemize} +\end{frame} + +\begin{frame}[fragile,label={sec:orgb03390f}]{Compiling your program for GDB} + \begin{itemize} +\item Your program needs to contain \alert{debug information} (also called +\texttt{DWARF}) for GDB to consume. +\end{itemize} + +\pause + +\begin{itemize} +\item The GCC flag to include debug information is \texttt{-g}. We also use +\texttt{-g3}, which includes information about macros (\texttt{\#define}). +\end{itemize} + +\pause + +\begin{itemize} +\item It's common to \alert{disable optimizations} when building the binary, by +using the flag \texttt{-O0} (it's \emph{dash-oh-zero}). + +\pause + +\begin{itemize} +\item \texttt{\# gcc -O0 -g program.c -o program}, \emph{or} + +\item \texttt{\# CFLAGS='-O0 -g' ./configure \&\& make} +\end{itemize} +\end{itemize} +\end{frame} + +\begin{frame}[fragile,label={sec:org71ced54}]{Running your program using GDB} + \begin{itemize} +\item In GDB's parlance, the program being debugged is called the +\alert{inferior}. +\end{itemize} + +\pause + +\begin{itemize} +\item Some ways to start the debugger: + +\pause + +\begin{itemize} +\item \texttt{\# gdb ./program} +\end{itemize} + +\pause + +\begin{itemize} +\item \texttt{\# gdb -{}-args ./program arg1 arg2} +\end{itemize} + +\pause + +\begin{itemize} +\item \texttt{\# gdb} \\ +\texttt{(gdb) file ./program} \\ +\texttt{(gdb) run arg1 arg2} +\end{itemize} +\end{itemize} +\end{frame} + +\begin{frame}[fragile,label={sec:org361654c}]{\{Break,Catch,Watch\}points} + \begin{itemize} +\item A \alert{breakpoint} is related to \emph{source code} (location, function). A +\alert{watchpoint} is related to \emph{data} (read/write of a variable). A +\alert{catchpoint} is related to an \emph{event} (enter/exit a syscall, fork, +receive a signal). +\end{itemize} + +\pause + +\begin{itemize} +\item Breakpoints (\emph{code}) + +\begin{itemize} +\item \texttt{break} + +\item \texttt{tbreak} (temporary) +\end{itemize} +\end{itemize} + +\pause + +\begin{itemize} +\item Watchpoints (\emph{data}) + +\begin{itemize} +\item \texttt{watch} (write), \texttt{rwatch} (read), \texttt{awatch} (access) + +\item Conditional watchpoints are supported. +\end{itemize} +\end{itemize} + +\pause + +\begin{itemize} +\item Catchpoints (\emph{events}) + +\begin{itemize} +\item \texttt{catch fork} + +\item \texttt{catch syscall} +\end{itemize} +\end{itemize} +\end{frame} + +\begin{frame}[fragile,label={sec:org62a7e28}]{Resuming the execution} + \begin{itemize} +\item After GDB has stopped the inferior (because a \texttt{*point} has been hit, +for example), you will probably want to resume its execution. +\end{itemize} + +\pause + +\begin{itemize} +\item You may just want to continue the program: + +\begin{itemize} +\item \texttt{continue} +\end{itemize} +\end{itemize} + +\pause + +\begin{itemize} +\item Or maybe go to the next statement/instruction: + +\begin{itemize} +\item \texttt{next} (\emph{statement}), or \texttt{nexti} (\emph{instruction}) +\end{itemize} +\end{itemize} + +\pause + +\begin{itemize} +\item Or step into a function: + +\begin{itemize} +\item \texttt{step} (\emph{statement}), or \texttt{stepi} (\emph{instruction}) +\end{itemize} +\end{itemize} + +\pause + +\begin{itemize} +\item Or finish executing the current function, but stop at the end: + +\begin{itemize} +\item \texttt{finish} +\end{itemize} +\end{itemize} +\end{frame} + + + +\begin{frame}[fragile,label={sec:org717537c}]{Examining data} + \begin{itemize} +\item The inferior has stopped\ldots{} Now what? +\end{itemize} + +\pause + +\begin{itemize} +\item You may want to print the value of some variable: + +\begin{itemize} +\item \texttt{print VAR} +\end{itemize} +\end{itemize} + +\pause + +\begin{itemize} +\item Or examine a memory location: + +\begin{itemize} +\item \texttt{x ADDRESS} +\end{itemize} +\end{itemize} + +\pause + +\begin{itemize} +\item The type of a variable? Easy: + +\begin{itemize} +\item \texttt{whatis VARIABLE} +\end{itemize} +\end{itemize} + +\pause + +\begin{itemize} +\item Hint: you may want to enable pretty-printing: + +\begin{itemize} +\item \texttt{set print pretty on} +\end{itemize} +\end{itemize} +\end{frame} + +\begin{frame}[fragile,label={sec:org71b8f2a}]{Examining the code} + \begin{itemize} +\item Yes, we have \texttt{ncurses}! The \textbf{T}ext +\textbf{U}user \textbf{I}nterface! + +\begin{itemize} +\item \texttt{C-x a} (that's \texttt{CTRL x a}). +\end{itemize} +\end{itemize} + +\pause + +\begin{itemize} +\item If you want to list the current region, or if you don't want/can't +to use TUI: + +\begin{itemize} +\item \texttt{list} +\end{itemize} +\end{itemize} + +\pause + +\begin{itemize} +\item You can also disassemble code: + +\begin{itemize} +\item \texttt{disassemble} +\end{itemize} +\end{itemize} + +\pause + +\begin{itemize} +\item If GDB can't find the source code, you can specify its location +using the \texttt{dir} command. +\end{itemize} +\end{frame} + +\begin{frame}[fragile,label={sec:org1b45b5a}]{Examining the call stack} + \begin{itemize} +\item If you want to see the call stack (A.K.A. stack trace) that lead to +the current function: + +\begin{itemize} +\item \texttt{bt} +\end{itemize} +\end{itemize} + +\pause + +\begin{itemize} +\item And you can move through it: + +\begin{itemize} +\item \texttt{up} and \texttt{down} + +\item You can also go to a specific frame: \texttt{frame NUMBER} +\end{itemize} +\end{itemize} +\end{frame} + +\begin{frame}[fragile,label={sec:org22c386a}]{Corefiles} + \begin{itemize} +\item \alert{Corefiles} are frozen images of the inferior. You can inspect +everything that was happening when the process was running (but you +can't resurrect it). +\end{itemize} + +\pause + +\begin{itemize} +\item You can generate them \emph{outside} GDB, when a program crashes. Make +sure you: + +\begin{itemize} +\item \texttt{ulimit -c unlimited} + +\item Check if \texttt{systemd} is handling them +(\texttt{/proc/sys/kernel/core\_pattern}). +\end{itemize} +\end{itemize} + +\pause + +\begin{itemize} +\item You can also generate them \emph{inside} GDB, at any moment: + +\begin{itemize} +\item \texttt{generate-core-file} +\end{itemize} +\end{itemize} + +\pause + +\begin{itemize} +\item You can open a corefile using GDB: + +\begin{itemize} +\item \texttt{\# gdb program -c corefile.PID} +\end{itemize} +\end{itemize} +\end{frame} + +\begin{frame}[fragile,label={sec:org7b2681d}]{Other interesting information} + \begin{itemize} +\item \texttt{info breakpoints} + +\item \texttt{info locals} + +\item \texttt{info registers} + +\item Many others! +\end{itemize} +\end{frame} + +\begin{frame}[fragile,label={sec:org73ead26}]{Who you gonna call?} + \begin{itemize} +\item Our online documentation (\texttt{info}) is very good! + +\item Every command has a \texttt{help}. + +\item You can also use \texttt{apropos} when searching for a term. + +\item \texttt{TAB}-completion is also useful. +\end{itemize} +\end{frame} + +\begin{frame}[label={sec:orgf6ce0ab}]{Other advanced features} +\begin{itemize} +\item Python support. + +\item Reverse debugging. + +\item Support for \emph{SystemTap SDT probes}. +\end{itemize} +\end{frame} + +\begin{frame}[fragile,label={sec:org0d39b0e}]{End} + \lstset{language=C,label= ,caption= ,captionpos=b,firstnumber=1,numbers=left,style=customc} +\begin{lstlisting} +int main () +{ + const char *c = NULL; + + return 0; +} +\end{lstlisting} +\end{frame} +\end{document}