\documentclass{beamer} \usetheme{linutronix} \usepackage{german} \usepackage[utf8]{inputenc} \usepackage{pgf} \usepackage{graphicx} \usepackage{lxextras} \lstset{keywordstyle=\color{blue},commentstyle=\color{orange}} \title{Block \lq Debugging\rq} \institute{Linutronix GmbH} \lstset{keywordstyle=\color{blue},commentstyle=\color{orange}} \begin{document} \maketitle \begin{frame} \frametitle{Übersicht} \tableofcontents \end{frame} \section{Einfache Debugging Werkzeuge} \subsection{Systemcalls tracen mit STRACE} \begin{frame} \frametitle{STRACE} \begin{alertblock}{Was ist STRACE?} STRACE ist ein mächtiges Diagnosewerkzeug, mit dem sich System Calls und Signale tracen lassen. \end{alertblock} \end{frame} \begin{frame}[containsverbatim] \frametitle{Anwendungsbeispiel} \begin{lstlisting}[language=bash,basicstyle=\ttfamily\fontsize{9}{9}\selectfont] $ strace /bin/ls execve("/bin/ls", ["/bin/ls"], [/* 38 vars */]) = 0 brk(0) = 0x8061000 access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT mmap2(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MA 0xb7f03000 access("/etc/ld.so.preload", R_OK) = -1 ENOENT open("/etc/ld.so.cache", O_RDONLY) = 3 fstat64(3, {st_mode=S_IFREG|0644, st_size=113431, ...} [...] \end{lstlisting} \end{frame} \begin{frame}[containsverbatim] \frametitle{Wichtige STRACE Optionen} \begin{itemize} \item \textbf{-f}: Follow Forks \item \textbf{-v}: Verbose mode \item \textbf{-T}: Print out time which is spent in each syscall \item \textbf{-p PID}: Attach to PID \end{itemize} \end{frame} \section{Der GNU Debugger: GDB} \subsection{Interaktives Debugging mit GDB} \begin{frame}[containsverbatim] \frametitle{Hello world debuggen} \begin{enumerate} \item Übersetzen mit Debug Informationen \item Starten im Debugger: \begin{lstlisting}[language=bash] gdb ./hello \end{lstlisting} \end{enumerate} \end{frame} \begin{frame}[containsverbatim] \frametitle{Wichtige GDB Kommandos} \begin{verbatim} (gdb) run Starting program: /home/jan/work/examples/hello Hello world Program exited normally. (gdb) \end{verbatim} \end{frame} \begin{frame}[containsverbatim] \frametitle{Wichtige GDB Kommandos} \begin{verbatim} (gdb) list 1 #include 2 3 int main (void) 4 { 5 printf("Hello world\n"); 6 return 0; 7 } (gdb) break 5 Breakpoint 1 at 0x400528: file hello.c, line 5. \end{verbatim} \end{frame} \begin{frame}[containsverbatim] \frametitle{Wichtige GDB Kommandos} \begin{verbatim} (gdb) run Starting program: /home/jan/work/examples/hello Breakpoint 1, main () at hello.c:5 5 printf("Hello world\n"); (gdb) next Hello world 6 return 0; (gdb) continue Continuing. \end{verbatim} \end{frame} \begin{frame}[containsverbatim] \frametitle{GDB Kommandos: Übersicht} \begin{tabular}{|c|c|p{5cm}|} \hline \textbf{Kommando} & \textbf{Abkürzung} & \textbf{Zweck} \\ \hline run & r & Programm starten \\ \hline continue & c & Programm fortsetzen \\ \hline break X & b & Breakpoint in Zeile X setzen \\ \hline step & s & step IN \\ \hline next & n & step OVER \\ \hline print var & -- & Inhalt von Variable var anzeigen \\ \hline display var & -- & Inhalt von Variable var jedes mal anzeigen, wenn das Programm stoppt \\ \hline \end{tabular} \end{frame} \begin{frame}[containsverbatim] \frametitle{GDB Kommandos: Übersicht} \begin{tabular}{|c|c|p{5cm}|} \hline \textbf{Kommando} & \textbf{Abkürzung} & \textbf{Zweck} \\ \hline backtrace & bt & Backtrace anzeigen \\ \hline frame X & f & Im aktuellen Stack zu Frame Nr. X wechseln \\ \hline quit & q & GDB beenden \\ \hline \end{tabular} \end{frame} \subsection{Post mortem Analyse mit GDB} \begin{frame}[containsverbatim] \frametitle{Post Mortem Debugging mit GDB} \begin{lstlisting}[language=C] #include int main (void) { char *arthur_dent = NULL; printf("Hello segfault world\n", *arthur_dent); return 0; } \end{lstlisting} \end{frame} \begin{frame}[containsverbatim] \frametitle{Post Mortem Debugging mit GDB} \begin{lstlisting}[language=bash] ulimit -c unlimited $ ./hello_segfault Segmentation fault (core dumped) $ ls -l core* \end{lstlisting} \end{frame} \begin{frame}[containsverbatim] \frametitle{Post Mortem Debugging mit GDB} \begin{lstlisting}[language=bash,basicstyle=\ttfamily\fontsize{9}{9}\selectfont] $ gdb hello_segfault core [...] Loaded symbols for /lib64/ld-linux-x86-64.so.2 Core was generated by `./hello_segfault'. Program terminated with signal 11, Segmentation fault. #0 0x0000000000400538 in main () at hello_crash.c:6 6 printf("Hello segfaulting world\n", *arthur_dent); (gdb) bt #0 0x0000000000400538 in main () at hello_crash.c:6 \end{lstlisting} \end{frame} \begin{frame}[containsverbatim] \frametitle{Wichtig Kommandos für Post Mortem Debugging} \begin{tabular}{|p{5.5cm}|p{5cm}|} \hline \textbf{Kommando} & \textbf{Zweck} \\ \hline ulimit & core dumpt aktivieren und größe festlegen \\ \hline cat /proc/sys/kernel/core\_pattern & Aktuelles Namenspattern für core files anzeigen \\ \hline echo core-\%p \textgreater /proc/sys/kernel/core\_pattern & Aktuelles Namenspattern für core files anzeigen \\ \hline gdb ./exe corefile & Coredump mit GDB anzeigen \\ \hline \end{tabular} \end{frame} \subsection{Remote Debugging mit GDB} \begin{frame} \frametitle{Remote Debugging} \begin{figure}[h] \centering \includegraphics[width=8cm]{images/remote_debug.png} \end{figure} \end{frame} \begin{frame}[containsverbatim] \frametitle{Remote Debugging session} \begin{lstlisting}[language=bash] $ powerpc-linux-gnu-gdb cross_hello (gdb) set solib-absolute-prefix /XXX/libc/ (gdb) target remote 10.0.0.3:54321 Remote debugging using localhost:54321 0x30016180 in _start() from /XXX/libc/lib/ld.so.1 (gdb) c \end{lstlisting} Auf dem Target: \begin{lstlisting}[language=bash] $ gdbserver 10.0.0.2:54321 ./cross_hello Process ./cross_hello created; pid = 310 Listening on port 54321 Remote debugging from host 10.0.2.2 Hello world \end{lstlisting} \end{frame} \begin{frame}[containsverbatim] \frametitle{gdbinit} GDB Kommandos automatisch ausführen: \begin{lstlisting}[language=bash] vim gdbinit.txt \end{lstlisting} \begin{verbatim} set solib-absolute-prefix /XXX/libc/ target remote 10.0.0.3:54321 \end{verbatim} \begin{lstlisting}[language=bash] powerpc-linux-gnu-gdb -x gdbinit.txt cross_hello \end{lstlisting} \end{frame} \section{Memory debugging} \begin{frame} \frametitle{Memory debugging} Gängige Probleme: \begin{itemize} \item Schreiben / Lesen über die Grenze von Speicherbereichen \item Memory leaks \item ''Use after free()'' \end{itemize} \end{frame} \subsection{MTrace} \begin{frame}[containsverbatim] \frametitle{GLIBC eigene Mechanismen: MTrace} \begin{lstlisting}[language=C] /* mem_test.c */ [...] #include [...] int main(void) { mtrace(); [...] } \end{lstlisting} \begin{lstlisting}[language=bash] $ gcc -o mem_test mem_test.c $ MALLOC_TRACE=mytrace.log ./mem_test $ mtrace mem_test mytrace.log \end{lstlisting} \end{frame} \begin{frame}[containsverbatim] \frametitle{GLIBC eigene Mechanismen: MTrace} \begin{lstlisting}[language=C,basicstyle=\ttfamily\fontsize{9}{9}\selectfont] /* mem_leak.c */ #include #include #include int main(void) { int i = 0; char *blurb = NULL; mtrace(); for(i = 0; i < 50; i++) blurb = malloc(sizeof(char)); free(blurb); } \end{lstlisting} \end{frame} \begin{frame}[containsverbatim] \frametitle{GLIBC eigene Mechanismen: MTrace} \begin{lstlisting}[language=bash,basicstyle=\ttfamily\fontsize{9}{9}\selectfont] $ gcc -g -o mem_leak mem_leak.c $ MALLOC_TRACE=mytrace.log ./mem_leak $ mtrace ./mem_leak mytrace.log Memory not freed: ----------------- Address Size Caller 0x1536460 0x1 at /home/jan/work/examples/mem_leak.c:13 0x1536480 0x1 at /home/jan/work/examples/mem_leak.c:13 0x15364a0 0x1 at /home/jan/work/examples/mem_leak.c:13 [...] \end{lstlisting} \end{frame} \subsection{libDUMA (aka electric fence)} \begin{frame}[containsverbatim] \frametitle{libDUMA / electric fence} \begin{lstlisting}[language=C,basicstyle=\ttfamily\fontsize{9}{9}\selectfont] /* mem_leak.c */ #include #include #include int main(void) { int i = 0; char *blurb = NULL; for(i = 0; i < 50; i++) blurb = malloc(sizeof(char)); free(blurb); } \end{lstlisting} \begin{lstlisting}[language=bash,basicstyle=\ttfamily\fontsize{9}{9}\selectfont] $ gcc -g -o mem_leak mem_leak.c /usr/lib/libduma.a \ -lpthread \end{lstlisting} \end{frame} \begin{frame}[containsverbatim] \frametitle{libDUMA / electric fence} \begin{lstlisting}[language=bash,basicstyle=\ttfamily\fontsize{9}{9}\selectfont] $ ./mem_leak DUMA 2.5.15 (static library) Copyright (C) 2006 Michael Eddington Copyright (C) 2002-2008 Hayati Ayguen , Procitec GmbH Copyright (C) 1987-1999 Bruce Perens DUMA: ptr=0x7f7280bdbfff size=1 type='malloc()' alloced from mem_leak.c(11) not freed DUMA: ptr=0x7f7280bddfff size=1 type='malloc()' alloced from mem_leak.c(11) not freed [...] \end{lstlisting} \end{frame} \begin{frame}[containsverbatim] \frametitle{libDUMA / electric fence: Überschriebender Speicher} \begin{lstlisting}[language=C,basicstyle=\ttfamily\fontsize{8}{8}\selectfont] /* array_access.c */ #include #include #include int main(void) { int *my_array = (int*) malloc(10 * sizeof(int)); int i = 0; memset(my_array, 0, 10); for(i = 0; i < 11; i++) printf("%d ", my_array[i]); printf("\n"); return 0; } \end{lstlisting} \begin{lstlisting}[language=bash,basicstyle=\ttfamily\fontsize{9}{9}\selectfont] $ gcc -g -o array_access array_access.c ./array_access 0 0 0 0 0 0 0 0 0 0 135121 \end{lstlisting} \end{frame} \frametitle{libDUMA / electric fence: Überschriebener Speicher} \begin{frame}[containsverbatim] \begin{lstlisting}[language=bash,basicstyle=\ttfamily\fontsize{9}{9}\selectfont] $ gcc -lduma -g -o array_access array_access.c $ ulimit -c unlimited $ ./array_access Segmentation fault (core dumped) $ gdb array_access core Loaded symbols for /lib64/ld-linux-x86-64.so.2 Core was generated by `./array_access'. Program terminated with signal 11, Segmentation fault. #0 0x00000000004006b7 in main () at array_access.c:10 10 printf("%d\n", my_array[i]); (gdb) print i $1 = 10 \end{lstlisting} \end{frame} \subsection{valgrind} \begin{frame} \frametitle{Valgrind} \begin{alertblock}{Vorteile} \begin{itemize} \item Sehr hohe Trefferquote \item Sehr viel Funktionalität \end{itemize} \end{alertblock} \begin{alertblock}{Nachteile} \begin{itemize} \item Nur bedingter ARM support (harte Abhängigkeit zu ARMv7)!!! \end{itemize} \end{alertblock} \end{frame} \begin{frame}[containsverbatim] \begin{lstlisting}[language=C,basicstyle=\ttfamily\fontsize{9}{9}\selectfont] /* mem_leak.c */ #include #include int main(void) { int i = 0; char *blurb = NULL; for(i = 0; i < 50; i++) blurb = malloc(sizeof(char)); free(blurb); } \end{lstlisting} \begin{lstlisting}[language=bash,basicstyle=\ttfamily\fontsize{9}{9}\selectfont] $ gcc -g -o mem_leak mem_leak.c \end{lstlisting} \end{frame} \begin{frame}[containsverbatim] \begin{lstlisting}[language=bash,basicstyle=\ttfamily\fontsize{9}{9}\selectfont] $ valgrind --leak-check=full ./mem_leak =5764= Memcheck, a memory error detector =5764= Copyright (C) 2002-2009, and GNU GPL'd, by Julian Seward et al. =5764= Using Valgrind-3.6.0.SVN-Debian and LibVEX; rerun with -h for copyright info =5764= Command: ./mem_leak =5764= =5764= HEAP SUMMARY: =5764= in use at exit: 49 bytes in 49 blocks =5764= total heap usage: 50 allocs, 1 frees, =5764= 50 bytes allocated =5764= 49 bytes in 49 blocks are definitely lost in =5764= loss record 1 of 1 =5764= at 0x4C274A8: malloc (vg_replace_malloc.c:236) =5764= by 0x40058D: main (mem_leak.c:10) =5764= =5764= LEAK SUMMARY: =5764= definitely lost: 49 bytes in 49 blocks [...] \end{lstlisting} \end{frame} \end{document}