diff options
| author | Jan Altenberg <jan@linutronix.de> | 2010-04-29 13:59:29 +0200 |
|---|---|---|
| committer | Jan Altenberg <jan@linutronix.de> | 2010-04-29 13:59:29 +0200 |
| commit | 7b2abe24fccf70eb427c04729d7ecd9185e4862c (patch) | |
| tree | 026d5769a561198d94f31965a36d8f0fca506e29 /application-devel | |
| parent | 76d0a001d0acc3a414f3626c4364af048beac9a7 (diff) | |
- Added some stuff for cross development.
- Handout for the debugging chapter!
- Added malloc() hooks
Diffstat (limited to 'application-devel')
3 files changed, 484 insertions, 10 deletions
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} diff --git a/application-devel/app-debugging/pres_app-debugging_de.tex b/application-devel/app-debugging/pres_app-debugging_de.tex index d9482d9..7940bf4 100644 --- a/application-devel/app-debugging/pres_app-debugging_de.tex +++ b/application-devel/app-debugging/pres_app-debugging_de.tex @@ -6,7 +6,6 @@ \usepackage{graphicx} \usepackage{lxextras} -\lstset{keywordstyle=\color{blue},commentstyle=\color{orange}} \title{Block \lq Debugging\rq} \institute{Linutronix GmbH} @@ -188,7 +187,7 @@ 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); + *arthur_dent); (gdb) bt #0 0x0000000000400538 in main () at hello_crash.c:6 \end{lstlisting} @@ -324,6 +323,17 @@ Address Size Caller \end{lstlisting} \end{frame} +\begin{frame}[containsverbatim] +\frametitle{GLIBC eigene Mechanismen: Hooks für malloc()} +\_\_malloc\_hook:\\ +void *function (size\_t size, const void *caller)\\ +\_\_realloc\_hook:\\ +void *function (void *ptr, size\_t size, const void *caller)\\ +\_\_free\_hook:\\ +void *function (void *ptr, const void *caller)\\ +\_\_memalign\_hook:\\ +void *function (size\_t size, size\_t alignment, const void *caller) +\end{frame} \subsection{libDUMA (aka electric fence)} \begin{frame}[containsverbatim] \frametitle{libDUMA / electric fence} @@ -370,7 +380,7 @@ DUMA: ptr=0x7f7280bddfff size=1 type='malloc()' \end{frame} \begin{frame}[containsverbatim] -\frametitle{libDUMA / electric fence: Überschriebender Speicher} +\frametitle{libDUMA / electric fence: Überschriebener Speicher} \begin{lstlisting}[language=C,basicstyle=\ttfamily\fontsize{8}{8}\selectfont] /* array_access.c */ #include <stdio.h> @@ -396,8 +406,8 @@ $ gcc -g -o array_access array_access.c \end{lstlisting} \end{frame} -\frametitle{libDUMA / electric fence: Überschriebener Speicher} \begin{frame}[containsverbatim] +\frametitle{libDUMA / electric fence: Überschriebener Speicher} \begin{lstlisting}[language=bash,basicstyle=\ttfamily\fontsize{9}{9}\selectfont] $ gcc -lduma -g -o array_access array_access.c $ ulimit -c unlimited @@ -414,6 +424,16 @@ $1 = 10 \end{lstlisting} \end{frame} +\begin{frame}[containsverbatim] +\frametitle{libDUMA / electric fence: Überschriebener Speicher} +\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} +\end{frame} + \subsection{valgrind} \begin{frame} \frametitle{Valgrind} @@ -452,7 +472,7 @@ $ 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] +\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 diff --git a/application-devel/cross-devel/pres_cross-devel_de.tex b/application-devel/cross-devel/pres_cross-devel_de.tex index 844642a..b4822c6 100644 --- a/application-devel/cross-devel/pres_cross-devel_de.tex +++ b/application-devel/cross-devel/pres_cross-devel_de.tex @@ -106,6 +106,14 @@ cd /tftpboot/nfsroot \end{lstlisting} \end{frame} +\begin{frame} +\frametitle{Device nodes} +\begin{figure}[h] +\centering +\includegraphics[width=8cm]{images/mknod.png} +\end{figure} +\end{frame} + \begin{frame}[containsverbatim] \frametitle{Erstellen eines Rootfilesystems für die Zielarchitektur} 2) Grundstruktur erstellen: |
