summaryrefslogtreecommitdiff
path: root/application-devel
diff options
context:
space:
mode:
authorJohn Ogness <john.ogness@linutronix.de>2017-12-19 10:31:06 +0100
committerJohn Ogness <john.ogness@linutronix.de>2017-12-19 10:31:06 +0100
commit67fd50dca5856654f5eb89a7646c4f1184e7d1aa (patch)
tree250fdcdd59d8e8f703a6fa4b0a70d50a6cfac4c4 /application-devel
parent4ecb904c6b94fdbc03c1bb2d16d93a5eadb2d054 (diff)
devel/debugging tools: add english version
Signed-off-by: John Ogness <john.ogness@linutronix.de>
Diffstat (limited to 'application-devel')
-rw-r--r--application-devel/debugging-tools/Makefile1
-rw-r--r--application-devel/debugging-tools/pres_debugging-tools_en.tex576
2 files changed, 577 insertions, 0 deletions
diff --git a/application-devel/debugging-tools/Makefile b/application-devel/debugging-tools/Makefile
index 0a3184a..43ee821 100644
--- a/application-devel/debugging-tools/Makefile
+++ b/application-devel/debugging-tools/Makefile
@@ -1 +1,2 @@
obj-$(CONFIG_DEBUGGING_TOOLS) += pres_debugging-tools_de.pdf
+obj-$(CONFIG_DEBUGGING_TOOLS) += pres_debugging-tools_en.pdf
diff --git a/application-devel/debugging-tools/pres_debugging-tools_en.tex b/application-devel/debugging-tools/pres_debugging-tools_en.tex
new file mode 100644
index 0000000..9a6d414
--- /dev/null
+++ b/application-devel/debugging-tools/pres_debugging-tools_en.tex
@@ -0,0 +1,576 @@
+\input{configpres}
+
+\title{\lq Debugging Tools\rq}
+\maketitle
+
+\subsection{Simple Debugging Tools}
+
+\begin{frame}
+\frametitle{strace}
+\begin{alertblock}{What is strace?}
+strace is a powerful diagnosing tool. It traces system calls and signals for a specified program.
+\end{alertblock}
+\end{frame}
+
+\begin{frame}[containsverbatim]
+\frametitle{strace Example}
+\begin{verbatim}
+$ strace /bin/ls
+execve("/bin/ls", ["/bin/ls"], [/* 32 vars */]) = 0
+brk(0) = 0xa6a000
+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) = 0x7f6
+access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
+open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
+fstat(3, {st_mode=S_IFREG|0644, st_size=73614, ...}) = 0
+mmap(NULL, 73614, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f68e06d6000
+[...]
+\end{verbatim}
+\end{frame}
+
+\begin{frame}[containsverbatim]
+\frametitle{Important strace Options}
+\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}
+
+\subsection{The GNU Debugger: gdb}
+
+\begin{frame}[containsverbatim]
+\frametitle{Debug Test Program}
+build the program with debug symbols
+\begin{verbatim}
+gcc -g -ohello hello.c
+\end{verbatim}
+start the debugger
+\begin{verbatim}
+gdb ./hello
+\end{verbatim}
+\end{frame}
+
+\begin{frame}[containsverbatim]
+\frametitle{Important gdb Commands}
+run the program
+\begin{verbatim}
+(gdb) run
+Starting program: /home/devel/work/hello
+Hello, world!
+
+[Inferior 1 (process 935) exited normally]
+(gdb)
+\end{verbatim}
+\end{frame}
+
+\begin{frame}[containsverbatim]
+\frametitle{Important gdb Commands}
+set a breakpoint
+\begin{verbatim}
+(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{verbatim}
+\end{frame}
+
+\begin{frame}[containsverbatim]
+\frametitle{Important gdb Commands}
+run the program again (now with breakpoint set)
+\begin{verbatim}
+(gdb) run
+Starting program: /home/jan/work/examples/hello
+
+Breakpoint 1, main () at hello.c:5
+5 printf("Hello, world!\n");
+\end{verbatim}
+\begin{verbatim}
+step over printf
+(gdb) next
+Hello, world!
+6 return 0;
+\end{verbatim}
+let the program run to end
+\begin{verbatim}
+(gdb) continue
+Continuing.
+[...]
+\end{verbatim}
+\end{frame}
+
+\begin{frame}[containsverbatim]
+\frametitle{gdb Commands: Overview}
+\begin{tabular}{|c|c|p{5cm}|}
+\hline
+\textbf{Command} & \textbf{Short-Form} & \textbf{Description} \\
+\hline
+run & r & start running program \\
+\hline
+continue & c & continue running program \\
+\hline
+break X & b & set a breakpoint at line X \\
+\hline
+step & s & step \textbf{in} the current function \\
+\hline
+next & n & step \textbf{over} the current function \\
+\hline
+print V & -- & show the value of variable V \\
+\hline
+display V & -- & show the value of variable V every time the program stops \\
+\hline
+\end{tabular}
+\end{frame}
+
+\begin{frame}[containsverbatim]
+\frametitle{gdb Commands: Overview}
+\begin{tabular}{|c|c|p{5cm}|}
+\hline
+\textbf{Command} & \textbf{Short-Form} & \textbf{Description} \\
+\hline
+backtrace & bt & display the current backtrace (stack) \\
+\hline
+frame X & f & change display to frame X of the current stack \\
+\hline
+quit & q & end gdb \\
+\hline
+\end{tabular}
+\end{frame}
+
+\subsection{Post-Mortem Debugging (Core Files)}
+
+\begin{frame}[containsverbatim]
+\frametitle{Create a Crashing Program}
+\begin{verbatim}
+/* hello_crash.c */
+#include <stdio.h>
+
+int main(void)
+{
+ char *p = NULL;
+ printf("Hello, crash! %c\n", *p);
+ return 0;
+}
+\end{verbatim}
+build the program with debug symbols
+\begin{verbatim}
+gcc -g -ohello_crash hello_crash.c
+\end{verbatim}
+\end{frame}
+
+\begin{frame}[containsverbatim]
+\frametitle{Run Program}
+enable core files
+\begin{verbatim}
+$ ulimit -c unlimited
+\end{verbatim}
+run program
+\begin{verbatim}
+$ ./hello_segfault
+Segmentation fault (core dumped)
+\end{verbatim}
+core file created
+\begin{verbatim}
+$ ls -l core
+-rw------- 1 devel devel 249856 Jan 1 00:00 core
+\end{verbatim}
+\end{frame}
+
+\begin{frame}[containsverbatim]
+\frametitle{Analyzing Core Files with gdb}
+start the debugger
+\begin{verbatim}
+$ gdb hello_crash ./core
+[...]
+Reading symbols from hello_crash...done.
+[New LWP 1239]
+Core was generated by `./hello_crash'.
+Program terminated with signal SIGSEGV, Segmentation fault.
+#0 0x000000000040051a in main () at hello_crash.c:7
+7 printf("Hello, crash! %c\n", *p);
+\end{verbatim}
+look at the full backtrace
+\begin{verbatim}
+(gdb) bt
+#0 0x000000000040051a in main () at hello_crash.c:7
+\end{verbatim}
+\end{frame}
+
+\begin{frame}[containsverbatim]
+\frametitle{Important Commands for Post-Mortem Debugging}
+activate core dumps and set a maximum size
+\begin{verbatim}
+ulimit -c N
+\end{verbatim}
+view the current filename pattern for core files
+\begin{verbatim}
+cat /proc/sys/kernel/core_pattern
+\end{verbatim}
+set the filename pattern for core files
+\begin{verbatim}
+echo core-%p > /proc/sys/kernel/core_pattern
+\end{verbatim}
+view the core dump with gdb
+\begin{verbatim}
+gdb ./exe ./corefile
+\end{verbatim}
+\end{frame}
+
+\begin{frame}[containsverbatim]
+\frametitle{Symbol Tables}
+\begin{alertblock}{What if release software may not contain debug information?}
+\end{alertblock}
+build the program with debug symbols
+\begin{verbatim}
+gcc -g -ohello_crash hello_crash.c
+\end{verbatim}
+copy out debug information
+\begin{verbatim}
+objcopy --only-keep-debug hello_crash hello_crash.dbg
+\end{verbatim}
+remove the debug symbols from the binary for release
+\begin{verbatim}
+strip --strip-all hello_crash
+\end{verbatim}
+\end{frame}
+
+\begin{frame}[containsverbatim]
+\frametitle{Symbol Tables}
+cannot debug using only the release binary
+\begin{verbatim}
+$ gdb ./hello_crash core
+[...]
+Reading symbols from ./hello_crash...(no debugging symbols found)...done.
+[New LWP 1555]
+Core was generated by `./hello_crash'.
+Program terminated with signal SIGSEGV, Segmentation fault.
+#0 0x000000000040051a in ?? ()
+\end{verbatim}
+load the symbol file
+\begin{verbatim}
+(gdb) symbol-file ./hello_crash.dbg
+Load new symbol table from "./hello_crash.dbg"? (y or n) y
+Reading symbols from ./hello_crash.dbg...done.
+(gdb) bt
+$ bt
+#0 0x000000000040051a in main () at hello_crash.c:7
+\end{verbatim}
+\end{frame}
+
+\begin{frame}[containsverbatim]
+\frametitle{Symbol Tables}
+\begin{alertblock}{Always keep the debug symbols for release binaries!}
+\end{alertblock}
+verify that the debug symbols match the executable
+\begin{verbatim}
+$ file hello_crash hello_crash.dbg
+hello_crash: ... BuildID[sha1]=9bc82e1d6627ba58492ea24462fd6658726c4fc0
+hello_crash.dbg: ... BuildID[sha1]=9bc82e1d6627ba58492ea24462fd6658726c4fc0
+\end{verbatim}
+\end{frame}
+
+\subsection{Cross Debugging}
+
+\begin{frame}[containsverbatim]
+\frametitle{Building for the Target System}
+build the program for armhf with debug symbols
+\begin{verbatim}
+$ arm-linux-gnueabihf-gcc -g -ohello hello.c
+\end{verbatim}
+check executable
+\begin{verbatim}
+$ file hello
+hello: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV),...
+\end{verbatim}
+\end{frame}
+
+\begin{frame}
+\frametitle{QEMU as a Tool for Cross Development}
+\begin{alertblock}{What is QEMU?}
+QEMU is a high performance emulation and virtualization environment for all common CPU architectures.
+gängigen CPU Architekturen.
+\end{alertblock}
+\end{frame}
+
+\begin{frame}[containsverbatim]
+\frametitle{Testing Executables using QEMU User Emulation}
+a system cannot directly execute foreign architecture executables
+\begin{verbatim}
+$ ./hello
+bash: ./hello: cannot execute binary file: Exec format error
+\end{verbatim}
+but it can emulate them
+\begin{verbatim}
+$ qemu-arm -L /opt/.../arm-linux-gnueabihf/libc ./hello
+Hello, world!
+\end{verbatim}
+\end{frame}
+
+\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}
+from the target:
+\begin{verbatim}
+$ gdbserver :2345 ./hello
+Process ./hello created; pid = 310
+Listening on port 2345
+\end{verbatim}
+from the host:
+\begin{verbatim}
+$ arm-linux-gnueabihf-gdb ./hello
+(gdb) set solib-absolute-prefix /opt/.../arm-linux-gnueabihf/libc
+(gdb) target remote 192.168.2.2:2345
+Remote debugging using 192.168.2.2:2345
+0x30016180 in _start() from /opt/.../libc/lib/ld-linux-armhf.so.3
+(gdb) c
+\end{verbatim}
+\end{frame}
+
+\begin{frame}[containsverbatim]
+\frametitle{Automatically Execute gdb Commands}
+edit a gdb init script
+\begin{verbatim}
+vi gdbinit.txt
+\end{verbatim}
+add startup commands
+\begin{verbatim}
+set solib-absolute-prefix /opt/.../arm-linux-gnueabihf/libc
+target remote 192.168.2.2:2345
+\end{verbatim}
+specify init script when starting gdb
+\begin{verbatim}
+arm-linux-gnueabihf-gdb -x gdbinit.txt ./hello
+\end{verbatim}
+\end{frame}
+
+\subsection{Memory Debugging}
+
+\begin{frame}
+\frametitle{Common Problems}
+\begin{itemize}
+\item writing/reading beyond memory regions
+\item memory leaks
+\item ''use after free()''
+\end{itemize}
+\end{frame}
+
+\begin{frame}[containsverbatim]
+\frametitle{The glibc Mechanism: mtrace}
+add support for mtrace to a program
+\begin{verbatim}
+#include <mcheck.h>
+[...]
+int main(void)
+{
+ mtrace();
+[...]
+\end{verbatim}
+activate mtrace
+\begin{verbatim}
+MALLOC_TRACE=hello.trace ./hello
+\end{verbatim}
+view the mtrace results
+\begin{verbatim}
+mtrace ./hello.dbg hello.trace
+\end{verbatim}
+\end{frame}
+
+\begin{frame}[containsverbatim]
+\frametitle{The glibc Mechanism: mtrace}
+create a test program with a memory leak
+\begin{verbatim}
+/* mem_leak.c */
+#include <mcheck.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+int main(void)
+{
+ int i = 0;
+ char *p = NULL;
+
+ mtrace();
+
+ for(i = 0; i < 50; i++)
+ p = malloc(sizeof(char));
+
+ free(p);
+}
+\end{verbatim}
+\end{frame}
+
+\begin{frame}[containsverbatim]
+\frametitle{The glibc Mechanism: mtrace}
+build the test program with debug symbols
+\begin{verbatim}
+$ gcc -g -omem_leak mem_leak.c
+\end{verbatim}
+run the test program with mtrace activated
+\begin{verbatim}
+$ MALLOC_TRACE=mem_leak.trace ./mem_leak
+\end{verbatim}
+view the trace results
+\begin{verbatim}
+$ mtrace ./mem_leak mytrace.log
+
+Memory not freed:
+-----------------
+Address Size Caller
+0x1536460 0x1 at /home/devel/work/mem_leak.c:13
+0x1536480 0x1 at /home/devel/work/mem_leak.c:13
+0x15364a0 0x1 at /home/devel/work/mem_leak.c:13
+[...]
+\end{verbatim}
+\end{frame}
+
+\begin{frame}[containsverbatim]
+\frametitle{glibc Hooks for malloc()}
+\_\_malloc\_hook:\\
+\begin{verbatim}
+void *function (size\_t size, const void *caller)
+\end{verbatim}
+\_\_realloc\_hook:\\
+\begin{verbatim}
+void *function (void *ptr, size\_t size, const void *caller)\\
+\end{verbatim}
+\_\_free\_hook:\\
+\begin{verbatim}
+void *function (void *ptr, const void *caller)\\
+\end{verbatim}
+\_\_memalign\_hook:\\
+\begin{verbatim}
+void *function (size\_t size, size\_t alignment, const void *caller)
+\end{verbatim}
+Do not use them! Use mtrace instead!
+\end{frame}
+
+\begin{frame}[containsverbatim]
+\frametitle{libduma / electric fence}
+create a test program with memory access beyond a region
+\begin{verbatim}
+/* array_access.c */
+#include <stdio.h>
+#include <stdlib.h>
+
+int main(void)
+{
+ int *a;
+ int i;
+
+ a = calloc(10, sizeof(*a));
+
+ for(i = 0; i < 11; i++)
+ printf("%d ", a[i]);
+ printf("\n");
+ return 0;
+}
+\end{verbatim}
+build and run the test program
+\begin{verbatim}
+$ gcc -g -oarray_access array_access.c
+$ ./array_access
+0 0 0 0 0 0 0 0 0 0 135121
+\end{verbatim}
+Invalid access and nobody cared!
+\end{frame}
+
+\begin{frame}[containsverbatim]
+\frametitle{libduma / electric fence}
+enable core dumps
+\begin{verbatim}
+$ ulimit -c unlimited
+\end{verbatim}
+run the program with libduma active
+\begin{verbatim}
+$ LD_PRELOAD=libduma.so.0 ./array_access
+[...]
+Segmentation fault (core dumped)
+\end{verbatim}
+investigate core dump
+\begin{verbatim}
+$ gdb ./array_access core
+[...]
+Core was generated by `./array_access'.
+Program terminated with signal SIGSEGV, Segmentation fault.
+#0 0x00000000004005ce in main () at array_access.c:13
+13 printf("%d ", a[i]);
+(gdb) print i
+$1 = 10
+\end{verbatim}
+\end{frame}
+
+\begin{frame}
+\frametitle{Valgrind}
+\begin{alertblock}{Advantages}
+\begin{itemize}
+\item high success rate
+\item lots of functionality and features
+\end{itemize}
+\end{alertblock}
+\begin{alertblock}{Disadvantage}
+\begin{itemize}
+\item runtime dramatically affected
+\end{itemize}
+\end{alertblock}
+\end{frame}
+
+\begin{frame}[containsverbatim]
+\frametitle{Valgrind}
+\begin{verbatim}
+$ valgrind --leak-check=full ./mem_leak
+[...]
+==8457== HEAP SUMMARY:
+==8457== in use at exit: 49 bytes in 49 blocks
+==8457== total heap usage: 50 allocs, 1 frees, 50 bytes allocated
+==8457==
+==8457== 49 bytes in 49 blocks are definitely lost in loss record 1 of 1
+==8457== at 0x4C28C20: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
+==8457== by 0x4005C4: main (mem_leak.c:14)
+==8457==
+==8457== LEAK SUMMARY:
+==8457== definitely lost: 49 bytes in 49 blocks
+[...]
+\end{verbatim}
+\end{frame}
+
+\begin{frame}[containsverbatim]
+\frametitle{Valgrind}
+\begin{verbatim}
+$ valgrind --leak-check=full ./array_access
+[...]
+==8493== Invalid read of size 4
+==8493== at 0x4005CE: main (array_access.c:13)
+==8493== Address 0x51e0068 is 0 bytes after a block of size 40 alloc'd
+==8493== at 0x4C2AD10: calloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
+==8493== by 0x4005AC: main (array_access.c:10)
+==8493==
+0 0 0 0 0 0 0 0 0 0 0
+==8493==
+==8493== HEAP SUMMARY:
+==8493== in use at exit: 40 bytes in 1 blocks
+==8493== total heap usage: 1 allocs, 0 frees, 40 bytes allocated
+==8493==
+==8493== 40 bytes in 1 blocks are definitely lost in loss record 1 of 1
+==8493== at 0x4C2AD10: calloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
+==8493== by 0x4005AC: main (array_access.c:10)
+==8493==
+==8493== LEAK SUMMARY:
+==8493== definitely lost: 40 bytes in 1 blocks
+[...]
+\end{verbatim}
+\end{frame}
+
+\input{tailpres}