From e472102af365fe62bfff720b36d3b5f2b5128179 Mon Sep 17 00:00:00 2001
From: Manuel Traut <manut@linutronix.de>
Date: Mon, 22 Jun 2009 20:21:10 +0100
Subject: application-devel: _REALLY_ added debugging section

Signed-off-by: Manuel Traut <manut@linutronix.de>
---
 .../app-debugging/handout_app-debugging_de.tex     | 290 ++++++++++++++++++++-
 1 file changed, 284 insertions(+), 6 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 4c391b2..89c71c2 100644
--- a/application-devel/app-debugging/handout_app-debugging_de.tex
+++ b/application-devel/app-debugging/handout_app-debugging_de.tex
@@ -1,17 +1,295 @@
-\documentclass{article}
+\documentclass{lxarticle}
 \usepackage{german}
 \usepackage[utf8]{inputenc}
+\usepackage{lxheaders}
+\usepackage{lxextras}
 
 \begin{document}
 
-\section*{Titel}
+\section*{Debugging}
 
-\subsection*{Abschnitt1}
+Beim Debugging geht es darum, Fehler in einem System zu finden.
 
-Text
+Es gibt zwei grundlegend verschiedene Fehlerarten:
 
-\subsection*{Abschnitt2}
+\begin{enumerate}
+\item die Anwendung beendet sich unerwartet
+	\begin{description}
+	\item[auf Grund von Fehlern bei der Speicherveraltung] z.B. durch freigeben
+	eines Speicherbereichs, welcher zuvor nicht alloziert wurde:
+		\begin{lstlisting}
+mem = malloc(5);
+free(((char*)mem)+6000);
+		\end{lstlisting}
+		Die Programmausf\"uhrung wird abgebrochen, die glibc liefert alle
+		Informationen, welche n\"otig sind, um den Fehler zu decodieren:
+		\begin{lstlisting}
+bash-4.0$ ./test
+*** glibc detected *** ./test: free(): invalid pointer: 0x083c9778 ***
+======= Backtrace: =========
+/lib/libc.so.6[0x57c231]
+./test[0x804841e]
+/lib/libc.so.6(__libc_start_main+0xe6)[0x522a66]
+./test[0x8048361]
+======= Memory map: ========
+0048e000-0048f000 r-xp 0048e000 00:00 0          [vdso]
+004e8000-00508000 r-xp 00000000 fd:00 66065      /lib/ld-2.10.1.so
+00508000-00509000 r--p 0001f000 fd:00 66065      /lib/ld-2.10.1.so
+...
+		\end{lstlisting}
+		Mit folgendem Befehl kann festgestellt werden, von wo aus der Fehler
+		getriggered wurde:
+		
+		\cmd{addr2line -e test 0x804841e}
 
-Text
+		/home/linutronix/test.c:16
+
+	\item[Speicherzugriffsfehler] z.B. durch Zugriff auf nicht allozierten
+	Speicher. Die Programmausf\"uhrung wird abgebrochen:
+	\begin{lstlisting}
+bash-4.0$ ./test
+Speicherzugriffsfehler
+	\end{lstlisting}
+	Solche Fehler lassen sich am Besten mit einer gdb Backtrace Ausgabe (siehe
+	unten) finden.
+	\end{description}
+\item die Anwendung verh\"alt sich anders als erwartet.
+
+	In einem solchen Fall sollte man sich zu erst Gedanken dar\"uber machen,
+	durch was das Fehlverhalten getriggered werden k\"onnte. Sofort mit einem
+	Debugger durch den Code zu steppen ist kein guter Ansatz, da so evt. ein
+	Fehler gefunden und behoben wird der aber nicht zwangsl\"aufig die Ursache
+	f\"ur das Problem war. Dies kann dazu f\"uhren, dass die Fehlersuche eines
+	sp\"ater entdeckten Bugs um so komplexer und schwieriger wird.
+
+	Hat man sich Gedanken \"uber die Ursachen gemacht, kann man gezielt mit den
+	nachfolgend beschriebenen Techniken dem Fehler auf den Grund gehen.
+\end{enumerate}
+
+\subsection*{Einfach aber wirkungsvoll: \cmd{printf}, \cmd{fprintf}}
+
+Da Ausgaben auf die \cmd{stdout} gecached werden, ist es zuverl\"assiger f\"ur
+Debugging \cmd{stderr} zu verwenden und nach jeder Ausgabe noch den cash flush
+zu triggern. Ein Debug konstrukt k\"onnte z.B. folgenderma\ss en aussehen:
+
+\begin{lstlisting}
+fprintf(stderr, "debug test\n");
+fflush(stderr);
+\end{lstlisting}
+
+F\"ur gew\"ohnlich wird \cmd{(f)printf} beim Debuggen f\"ur drei Zwecke
+verwendet:
+
+\begin{enumerate}
+\item Tracing:
+\begin{lstlisting}
+fprintf(stderr, "%s, called\n", __FUNCTION__);
+fflush(stderr);
+\end{lstlisting}
+\item Ausgabe von Variablenwerten:
+\begin{lstlisting}
+fprintf(stderr, "Wert: %d, Wert (hex): %x\n", wert, wert);
+fflush(stderr);
+\end{lstlisting}
+\item Ausgabe von Adressen:
+\begin{lstlisting}
+fprintf(stderr, "Adresse: %p, Wert: %x\n", wert, wert);
+fflush(stderr);
+\end{lstlisting}
+\end{enumerate}
+
+Nat\"urlich k\"onnen die Methoden kombiniert werden.
+
+Soll das Debugging zur Compilezeit zu- und abschaltbar sein, kann z.B. folgendes
+Pr\"aprozessor konstrukt hilfreich sein:
+
+\begin{lstlisting}
+#ifdef DEBUG
+#define debug(...)  fprintf(stderr, "%s:%d - ", __FILE__, __LINE__); \
+                    fprintf(stderr, __VA_ARGS__); fflush(stderr)
+#else
+#define debug(...)  ((void)0)
+#endif
+
+int main(int argc, char **argv)
+{
+	int val = 3;
+	debug("addr: %p - val: %d\n", &val, val);
+	return 0;
+}
+\end{lstlisting}
+
+Resultat:
+\begin{lstlisting}
+bash-4.0$ gcc -o test test.c
+bash-4.0$ ./test
+bash-4.0$
+bash-4.0$ gcc -o test -DDEBUG test.c
+bash-4.0$ ./test
+test.c:22 - test: 0xbfef8694 - val: 3
+bash-4.0$
+\end{lstlisting}
+
+\subsubsection*{deutlich flexibler: Logging Frameworks}
+
+Wird f\"ur Debugging oder Logging mehr Flexibilit\"at ben\"otigt, sollte ein
+Logging Framework verwendet werden. Prominente Vertretter f\"ur verschiedene
+Programmiersprachen sind zum Beispiel:
+
+\begin{itemize}
+\item Log for C++ (http://log4cpp.sourceforge.net)
+\item log4c (http://log4c.sourceforge.net)
+\item log4j (http://logging.apache.org/log4j) - f\"ur JAVA
+\end{itemize}
+
+Diese Frameworks bieten die M\"oglichkeit das Loggingverhalten zum Startpunkt
+der Anwendung, oder teilweise sogar, w\"ahrend der Laufzeit zu ver\"andern.
+
+Es wird beim Loggen mindestens zwischen den Kategorien Debug, Error und Info
+unteschieden, welche jeweils an verschiedene Ziele geleitet werden k\"onnen:
+Datei, syslog, \dots
+
+\subsubsection*{Backtraces ausgeben}
+
+Die glibc bietet auch die M\"oglichkeit an einer beliebigen Stelle in der
+Applikation die Ausgabe eines Function Call Traces (Backtrace) aus zu geben.
+
+Dies ist hilfreich, wenn man herausfinden will, \"uber welche Funktionsaufrufe
+die aktuelle Codezeile aufgerufen wurde.
+
+Beispiel:
+\begin{lstlisting}
+#include <stdio.h>
+#include <stdlib.h>
+#define DEFAULT_BT_DEPTH 16
+
+void btrace(int depth) {
+  const void *trace[depth];
+  char **messages = (char **) NULL;
+  unsigned int i = 0;
+  int trace_size = backtrace(trace, depth);
+  messages = backtrace_symbols(trace, trace_size);
+  fprintf(stderr, "***BACKTRACE***\n");
+  for(; i < trace_size; i++)
+      fprintf(stderr, "%s\n", messages[i]);
+  fprintf(stderr, "***************\n");
+  fflush(stderr);
+}
+void pong() {
+#ifdef DEBUG
+  btrace(DEFAULT_BT_DEPTH);
+#endif
+}
+void ping() {
+  pong();
+}
+int main(int argc, char **argv) {
+  ping();
+  return 0;
+}
+\end{lstlisting}
+
+Anwendung:
+\begin{lstlisting}
+bash-4.0$ gcc -g -o test -DDEBUG test.c
+bash-4.0$ ./test
+***BACKTRACE***
+./test [0x804859b]
+./test [0x8048663]
+./test [0x8048670]
+./test [0x804867d]
+/lib/libc.so.6(__libc_start_main+0xe6) [0x522a66]
+./test [0x8048441]
+***************
+bash-4.0$ addr2line -e test 0x804867d
+/home/linutronix/test.c:27
+bash-4.0$ addr2line -e test 0x8048670
+/home/linutronix/test.c:24
+\end{lstlisting}
+
+\subsection*{Tracing mit strace}
+
+Mit \cmd{strace} k\"onnen Systemaufrufe getraced werden. Es kann ermittelt
+werden welche Systemaufrufe von der Applikation zu welchem Zeitpunkt aufgerufen
+wurden und wieviel Zeit der Kernel ben\"otigt um den Aufruf ab zu arbeiten.
+
+Ein \cmd{strace} ist folgenderma\ss en zu interpretieren:
+
+\begin{lstlisting}
+bash-4.0$ strace -ftttT ./test
+1245687387.873813 execve("./test", ["./test"], [/* 18 vars */]) = 0 <0.000233>
+^                 ^          ^                                  ^    ^
+|                 |          |                                  |    |
+|                 |          +- Argumente                       |    +- Dauer
++- Zeitstempel    +- syscall                                    +- Rueckgabewert
+\end{lstlisting}
+
+Die Option
+\begin{itemize}
+\item \cmd{-f} sorgt daf\"ur, dass auch Kindprozesse mit getraced werden,
+\item \cmd{-ttt} blendet den pr\"azisen Zeitstempel ein,
+\item \cmd{-T} gibt die Dauer des Systemaufrufs mit an.
+\end{itemize}
+
+\subsection*{Debugging mit gdb}
+
+gdb ist ein textbasierter Debugger. Eine Applikation kann z.B mit dem Befehl
+\cmd{gdb ./test} in gdb geladen werden und anschliessend mit dem Befehl
+\cmd{run} ausgef\"uhrt werden.
+
+Die 'gdb Reference Card' listet viele n\"utzliche Befehle, z.B. zum Setzen von
+Breakpoints und zum Steppen durch die Applikation.
+
+Es gibt auch grafische Frontends f\"ur gdb, wie z.B. \cmd{ddd}
+(http://www.gnu.org/software/ddd).
+
+\subsubsection*{Core Dumps analysieren}
+
+\cmd{gdb} eignet sich au\ss erdem hervorragend zur Analyse von so genannten
+'core dumps'. Ein 'core dump' entsteht, wenn eine Applikation unerwartet beendet
+wird. Gegebenenfalls mu\ss  mit \cmd{ulimit -c unlimited} vor dem
+Applikationsstart das Limit f\"ur maximal zul\"assige core dumps erh\"oht
+werden.
+
+Beispiel:
+\begin{lstlisting}
+bash-4.0$ ulimit -c unlimited
+bash-4.0$ ./test
+Speicherzugriffsfehler (Speicherabzug geschrieben)
+bash-4.0$ gdb ./test core.12371
+GNU gdb 6.8-debian
+Copyright (C) 2008 Free Software Foundation, Inc.
+License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
+This is free software: you are free to change and redistribute it.
+There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
+and "show warranty" for details.
+This GDB was configured as "x86_64-linux-gnu"...
+Reading symbols from /lib/libc.so.6...done.
+Loaded symbols for /lib/libc.so.6
+Reading symbols from /lib/ld-linux.so.2...done.
+Loaded symbols for /lib/ld-linux.so.2
+Core was generated by `./test'.
+Program terminated with signal 11, Segmentation fault.
+[New process 12371]
+#0  0x08048661 in pong () at test.c:22
+22              *null_ptr = 3;
+(gdb)
+(gdb) bt
+#0  0x08048661 in pong () at test.c:22
+#1  0x08048671 in ping () at test.c:26
+#2  0x0804867b in main (argc=1, argv=0xbf9921f4) at test.c:29
+(gdb)
+\end{lstlisting}
+
+Der Befehl \cmd{bt} steht f\"ur Backtrace. Die zuletzt aufgerufene Funktion
+steht an Position \#0. Zeigt \#0 nicht auf die eigene Applikationen sondern z.B.
+in die glibc ist es eher warscheinlich, dass der Fehler durch eine nicht
+spezifiezierte Verwendung einer glibc Funktion getriggered wurde. Man sollte in
+diesem Fall zuerst untersuchen, ob die erste Funktion in der eigenen Software,
+einen korrekten glibc call absetzt, bevor die glibc gedebugged wird.
+
+%\subsubsection*{Remote-Debuggging mit gdbserver}
+
+%Text
 
 \end{document}
-- 
cgit v1.2.3

