summaryrefslogtreecommitdiff
path: root/application-devel
diff options
context:
space:
mode:
authorJan Altenberg <jan@linutronix.de>2010-04-29 13:59:29 +0200
committerJan Altenberg <jan@linutronix.de>2010-04-29 13:59:29 +0200
commit7b2abe24fccf70eb427c04729d7ecd9185e4862c (patch)
tree026d5769a561198d94f31965a36d8f0fca506e29 /application-devel
parent76d0a001d0acc3a414f3626c4364af048beac9a7 (diff)
- Added some stuff for cross development.
- Handout for the debugging chapter! - Added malloc() hooks
Diffstat (limited to 'application-devel')
-rw-r--r--application-devel/app-debugging/handout_app-debugging_de.tex456
-rw-r--r--application-devel/app-debugging/pres_app-debugging_de.tex30
-rw-r--r--application-devel/cross-devel/pres_cross-devel_de.tex8
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: