From 7b2abe24fccf70eb427c04729d7ecd9185e4862c Mon Sep 17 00:00:00 2001
From: Jan Altenberg <jan@linutronix.de>
Date: Thu, 29 Apr 2010 13:59:29 +0200
Subject: - Added some stuff for cross development. - Handout for the debugging
 chapter! - Added malloc() hooks

---
 .../app-debugging/handout_app-debugging_de.tex     | 456 ++++++++++++++++++++-
 1 file changed, 451 insertions(+), 5 deletions(-)

(limited to 'application-devel/app-debugging/handout_app-debugging_de.tex')

diff --git a/application-devel/app-debugging/handout_app-debugging_de.tex b/application-devel/app-debugging/handout_app-debugging_de.tex
index b6e7158..537f62d 100644
--- a/application-devel/app-debugging/handout_app-debugging_de.tex
+++ b/application-devel/app-debugging/handout_app-debugging_de.tex
@@ -3,17 +3,463 @@
 \usepackage[utf8]{inputenc}
 \usepackage{lxheaders}
 \usepackage{lxextras}
+\lstset{keywordstyle=\color{blue}}
 
 \begin{document}
 
-\section*{Titel}
+\section*{STRACE}
+Eine sehr einfache und mächtige Möglichkeit, Systemaufrufe und Signale
+zu tracen ist das Tool ''strace''. Die Anwendung ist denkbar einfach. Dem Aufruf
+des zu tracenden Programms wird einfach strace vorangestellt:
+\begin{lstlisting}[language=bash]
+strace /bin/ls
+$ strace /bin/ls
+execve("/bin/ls", ["/bin/ls"], [/* 50 vars */]) = 0
+brk(0)                                  = 0x2246000
+access("/etc/ld.so.nohwcap", F_OK)      = 
+               -1 ENOENT (No such file or directory)
+mmap(NULL, 8192, PROT_READ|PROT_WRITE,
+         MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f32457fe000
+access("/etc/ld.so.preload", R_OK)      = 
+                -1 ENOENT (No such file or directory)
+open("/etc/ld.so.cache", O_RDONLY)      = 3
+fstat(3, {st_mode=S_IFREG|0644, st_size=110532, ...}) = 0
+mmap(NULL, 110532, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f32457e3000
+close(3)                                = 0
+\end{lstlisting}
+Strace besitzt eine Vielzahl von Commandlineparametern. Die wichtigsten
+davon sind:\\
+\begin{center}
+\begin{tabular}{|c|p{5cm}|}
+\hline
+\textbf{Parameter} & \textbf{Zweck} \\
+\hline
+-f & follow forks \\
+\hline
+-v & Verbose mode \\
+\hline
+-T & Zeit ausgeben, die in jedem Syscall verbracht wird \\
+\hline
+-p PID & Auf PID attachen \\
+\hline
+\end{tabular}
+\end{center}
+\section*{GDB}
+\subsection*{Interaktives Debugging mit GDB}
+Der GNU Debugger: GDB stellt einen vollwertigen interaktiven Debugger dar,
+der für alle gängigen Prozessortarchitekturen verfügbar ist. GDB bietet ein
+sehr mächtiges Commandlineinterface. Es existieren diverse grafische Frontends
+für GDB (z.B. DDD). Eine einfache Debuggingsession stellt sich wie folgt dar:
+\begin{lstlisting}[language=c]
+	/* hello.c */
+	#include <stdio.h>
+	
+	int main (void)
+	{
+		printf("Hello world\n");
+		return 0;
+	}
+\end{lstlisting}
+Übersetzen des Programms mit Debuginformationen:
+\begin{lstlisting}
+$ gcc -g -o hello hello.c
+\end{lstlisting}
+Starten der Debugsession:
+\begin{lstlisting}
+$ gdb ./hello
+(gdb) run
+Starting program: /home/jan/work/examples/hello 
+Hello world
 
-\subsection*{Abschnitt1}
+Program exited normally.
+\end{lstlisting}
+Mit dem Kommando ''list'' kann der zugehörige Quellcode angezeigt werden.
+Breakpoints werden mit ''break'' gesetzt:
+\begin{lstlisting}
+(gdb) list
+1	#include <stdio.h>
+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{lstlisting}
+Mit ''next'' und ''step'' werden einzelne Codezeilen ausgeführt,
+während ''next'' einem step-OVER und ''step'' einem step-IN entspricht:
+\begin{lstlisting}
+(gdb) run
+Starting program: /home/jan/work/examples/hello 
 
-Text
+Breakpoint 1, main () at hello.c:5
+5		printf("Hello world\n");
+(gdb) next
+Hello world
+6		return 0;
+(gdb) continue 
+Continuing.
+\end{lstlisting}
+Folgende Tabelle zeigt eine Übersicht der wichtigsten GDB Kommandos:\\
+\begin{center}
+\begin{tabular}{|l|c|p{8cm}|}
+\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
+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{center}
 
-\subsection*{Abschnitt2}
+\subsection*{Analyse von core-Files}
+Neben der Möglichkeit des interaktiven Debuggings findet GDB auch häufig
+eine weitere Anwendung: Die ''Post-Mortem-Analyse'' von Problemen. Wird
+eine Applikation beispielsweise durch seinen Segmentation Fault beendet
+wird ein sogenanntes core-File erzeugt, welches u.A. den aktuellen Stack der
+Applikation beinhaltet. Das Erzeugen von core-Files ist per Default deaktiviert
+und kann mit dem Kommanto ''ulimit'' aktiviert werden:
+\begin{lstlisting}
+ulimit -c unlimited
+\end{lstlisting}
+Die maximale Größe des zu erzeugenden core-Files wird ulimit als Parameter
+übergeben. Gibt es keine Größenbeschränkung kann einfach ''unlimited'' als
+Parameter übergeben werden. Der Name des zu erzeugenden Files kann unter
+/proc/sys/kernel/core\_pattern festgelegt werden. Folgende Formatoptionen
+können hier verwendet werden:
+\begin{center}
+\begin{tabular}{|c|l|}
+\hline
+\textbf{Format} & \textbf{Bedeutung} \\
+\hline
+\%p & PID \\
+\hline
+\%u & User ID \\
+\hline
+\%g & Group ID \\
+\hline
+\%h & Hostname \\
+\hline
+\%e & Executable filename \\
+\hline
+\%s & Signal number: Signal, welches dem Prozess gesendet wurde \\
+\hline
+\%t & UNIX Time \\
+\hline
+\end{tabular}
+\end{center}
+Folgendes Beispiel verdeutlich die Analyse eines core-Files:
+\begin{lstlisting}[language=c]
+	/* segfault.c */
+	#include <stdio.h>
+	
+	int main (void)
+	{
+		char *arthur_dent = NULL;
+		printf("%c\n", *arthur_dent);
+		return 0;
+        }
+\end{lstlisting}
+Programm übersetzen:
+\begin{lstlisting}
+$ gcc -g -o segfault segfault.c
+\end{lstlisting}
+Ggf. core\_pattern setzen
+\begin{lstlisting}
+$ echo core-%p > /proc/sys/kernel/core_pattern
+\end{lstlisting}
+Coredumps aktivieren:
+\begin{lstlisting}
+$ ulimit -c unlimited
+\end{lstlisting}
+Programm starten:
+\begin{lstlisting}
+$ ./segfault
+Segmentation fault (core dumped)
+\end{lstlisting}
+core-File analysieren:
+\begin{lstlisting}
+gdb ./segfault core-2567
+[...]
+Loaded symbols for /lib64/ld-linux-x86-64.so.2
+Core was generated by `./segfault'.
+Program terminated with signal 11, Segmentation fault.
+#0  0x0000000000400538 in main () at segfault.c:6
+6		printf("%c\n", *arthur_dent);
+(gdb) bt
+#0  0x0000000000400538 in main () at segfault.c:6
+\end{lstlisting}
 
-Text
+\section*{Memory debugging}
+Eine sehr häufige Problemstellung bei der Fehlersuche in Applikationen
+ist das Aufspüren von Problemen in der dynamischen Speicherverwaltung.
+Die häufigsten Probleme, die es hier zu untersuchen gilt, sind:
+\begin{itemize}
+\item Schreiben / Lesen über die Grenze von Speicherbereichen
+\item Memory leaks
+\item ''Use after free()''
+\end{itemize}
+\subsection*{GLIBC: MTrace}
+Die GNU C Library, GLIBC, liefert bereits ein Integriertes Werkzeug zum
+Debuggen von Speicherproblemen. Die Anwendung von MTrace ist denkbar einfach.
+Im ersten Schritt ist der Code um folgende Zeilen zu ergänzen:
+\begin{lstlisting}
+[...]
+#include <mcheck.h>
+[...]
+mtrace();
+\end{lstlisting}
+MTrace wertet die Umbebungsvariable MALLOC\_TRACE aus. Diese Variable gibt
+an, in welches Logfile MTrace seinen Output schreiben soll. Folgendes Beispiel
+verdeutlicht die Anwendung von MTrace:
+\begin{lstlisting}[language=C]
+/* mem_leak.c */
+#include <mcheck.h>
+#include <malloc.h>
+#include <stdio.h>
+
+int main(void)
+{
+        int i = 0;
+        char *blurb = NULL;
+
+        mtrace();
+
+        for(i = 0; i < 50; i++)
+                blurb = malloc(sizeof(char));
+
+        free(blurb);
+}
+\end{lstlisting}
+Übersetzen und Ausführen der Applikation:
+\begin{lstlisting}[language=bash]
+$ gcc -g -o mem_leak mem_leak.c
+$ MALLOC_TRACE=mytrace.log ./mem_leak
+\end{lstlisting}
+Auswerten des Logfiles mit dem mtrace Tool:
+\begin{lstlisting}[language=bash]
+$ 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}
+\subsection*{GLIBC: Hooks für malloc()}
+Neben mtrace() sieht die GLIBC noch Hooks for, um Callbacks einzuhängen,
+die bei jedem Aufrunf von malloc(), realloc(), free() oder memalign()
+aufgerufen werden. Hiermit steht eine sehr einfach Möglichkeit zur Verfügung,
+dynamische Speicherverwaltung individuell zu überwachen.\\
+Folgende Variablen stehen hierzu zur Verfügung:\\
+\_\_malloc\_hook:
+\begin{lstlisting}[language=C]
+/* function prototype */
+void *function (size_t size, const void *caller)
+\end{lstlisting}
+\_\_realloc\_hook:
+\begin{lstlisting}[language=C]
+/* function prototype */
+void *function (void *ptr, size_t size, const void *caller)
+\end{lstlisting}
+\_\_free\_hook:
+\begin{lstlisting}[language=C]
+/* function prototype */
+void *function (void *ptr, const void *caller)
+\end{lstlisting}
+\_\_memalign\_hook:
+\begin{lstlisting}[language=C]
+/* function prototype */
+void *function (size_t size, size_t alignment, const void *caller)
+\end{lstlisting}
+\subsection*{libDUMA}
+Ein weiteres bekanntes Werkzeug zum Speicherdebugging ist eine Bibliothek
+mit dem Namen DUMA. Hierbei handelt sich um einen Fork der bekannten
+Electric Fence Libraries von Bruce Perence. DUMA ermöglicht es durch einfaches
+Linken gegen die Bibliothek, Speicherprobleme wie Leaks oder das Schreiben über
+Array Grenzen hinaus zu detektieren. Hierzu bringt DUMA eigene Implementierungen
+von malloc() und free(). Zum detektieren von Überschriebenen Array Grenzen
+reicht das dynamische Linken oder das einfache ''pre-loading'' gegen / von libDUMA.
+Erkennt DUMA eine Fehler wird ein Segmentation Fault erzeugt. Die Fehlersituation
+kann dann mittels core-File oder interaktivem Debuggen analysiert werden. Zum
+Aufspüren von Memory Leaks muß statisch gegen libDUMA gelinkt und weiterhin
+duma.h inkludiert werden. Bezogen auf unser Beispiel bedeutet dies:
+\begin{lstlisting}
+/* mem_leak.c */
+#include <duma.h>
+#include <malloc.h>
+#include <stdio.h>
+
+int main(void)
+{
+        int i = 0;
+        char *blurb = NULL;
+
+        for(i = 0; i < 50; i++)
+                blurb = malloc(sizeof(char));
+
+        free(blurb);
+}
+\end{lstlisting}
+Übersetzen der Applikation (Achtung: Linkreihenfolge beachten!!!):
+\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}
+Ausführen der Applikation:
+\begin{lstlisting}
+$ ./mem_leak
+DUMA 2.5.15 (static library)
+Copyright (C) 2006 Michael Eddington
+<meddington@gmail.com>
+Copyright (C) 2002-2008 Hayati Ayguen
+<h_ayguen@web.de>, Procitec GmbH
+Copyright (C) 1987-1999 Bruce Perens
+<bruce@perens.com>
+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}
+Das detektieren von überschriebenem Speicher erfordert, wie bereits beschrieben,
+kein statisches Linken gegen libDUMA:
+\begin{lstlisting}[language=C]
+/* array_access.c */
+#include <stdio.h>
+#include <malloc.h>
+#include <string.h>
+
+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}
+Ohne libDUMA:
+\begin{lstlisting}
+$ gcc -g -o array_access array_access.c
+./array_access 0 0 0 0 0 0 0 0 0 0 135121
+\end{lstlisting}
+Mit libDUMA:
+\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}
+Mit libDUMA und LD\_PRELOAD:
+\begin{lstlisting}[language=bash,basicstyle=\ttfamily\fontsize{9}{9}\selectfont]
+$ gcc -g -o array_access array_access.c
+$ LD_PRELOAD=/usr/lib/libduma.so ./array_access
+Segmentation fault (core dumped)
+[...]
+\end{lstlisting}
+Das Verhalten von libDUMA durch folgende Umgebungsvariablen beeinflußt werden:
+\begin{center}
+\begin{tabular}{|l|p{8cm}|}
+\hline
+\textbf{Variable} & \textbf{Bedeutung} \\
+\hline
+DUMA\_ALIGNMENT & Alignment des allozierten Speichers \\
+\hline
+DUMA\_PROTECT\_BELOW & DUMA platziert normalerweise ''Marker'' hinter dem Allozierten Speicherbereich.
+Das Setzen dieser Variable veranlaßt DUMA die Marker VOR den allozierten Bereich zu setzen\\
+\hline
+DUMA\_REPORT\_ALL\_LEAKS & Alle Memory leaks anzeigen (auch wenn Sourcefile und Zeilennummer
+nicht verfügbar ist)\\
+\hline
+DUMA\_ALLOW\_MALLOC\_0 & malloc() mit der Größe 0 als Fehler ausgeben\\
+\hline
+\end{tabular}
+\end{center}
+Es gibt noch viele andere Environment Variablen. Deren Bedeutung ist der
+Manpage von libduma zu entnehmen: ''man duma''
+\subsection*{Valgrind}
+Valgrind ist das wohl Mächtigste Werkzeug, das zur Analyse von Speicherproblemen
+zur Verfügung steht. Es handelt sich um mehrere Werkzeuge, die unter anderem auch
+Profiling Funkionaliät bieten. Valgrind erreicht eine sehr hohe Trefferquote. Leider
+gibt es derzeit nur beschränkten Support für ARM CPUs (derzeit gibt es noch
+harte Abhängigkeiten nach ARMv7). Die Analyse des Memory Leak Beispiel mit valgrind gestaltet
+sich wie folgt:
+\begin{lstlisting}[language=C]
+/* mem_leak.c */
+/* Keine Anpassung der Sourcen notwendig!!! */
+#include <malloc.h>
+#include <stdio.h>
+
+int main(void)
+{
+        int i = 0;
+        char *blurb = NULL;
+
+        for(i = 0; i < 50; i++)
+                blurb = malloc(sizeof(char));
+
+        free(blurb);
+}
+\end{lstlisting}
+Übersetzen der Applikation:
+\begin{lstlisting}[language=bash]
+$ gcc -g -o mem_leak mem_leak.c
+\end{lstlisting}
+Analyse mit valgrind:
+\begin{lstlisting}[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{document}
-- 
cgit v1.2.3

