[bootlin/training-materials updates] master: embedded-linux-qemu: temporarily revive old labs (2d23f048)

Michael Opdenacker michael.opdenacker at bootlin.com
Thu Jan 19 18:59:03 CET 2023


Repository : https://github.com/bootlin/training-materials
On branch  : master
Link       : https://github.com/bootlin/training-materials/commit/2d23f04887359fe863423f843dae3eec12ce81ce

>---------------------------------------------------------------

commit 2d23f04887359fe863423f843dae3eec12ce81ce
Author: Michael Opdenacker <michael.opdenacker at bootlin.com>
Date:   Thu Jan 19 18:59:03 2023 +0100

    embedded-linux-qemu: temporarily revive old labs
    
    Namely, the "appdev" and "debugging" labs.
    Until we can align the QEMU labs better with the STM32 and BBB versions
    (when several issues are addressed, such as sound support in QEMU)
    
    Signed-off-by: Michael Opdenacker <michael.opdenacker at bootlin.com>


>---------------------------------------------------------------

2d23f04887359fe863423f843dae3eec12ce81ce
 lab-data/embedded-linux-qemu/appdev                |   1 -
 lab-data/embedded-linux-qemu/appdev/app.c          |  91 ++++++++++
 .../debugging/data/vista-emulator.c                |  78 ++++++++
 .../sysdev-application-debugging-qemu.tex          | 201 +++++++++++++++++++++
 .../sysdev-application-development-qemu.tex        |  50 +++++
 .../sysdev-buildroot-qemu.tex                      |  10 +-
 mk/embedded-linux-qemu.mk                          |   3 +-
 7 files changed, 430 insertions(+), 4 deletions(-)

diff --git a/lab-data/embedded-linux-qemu/appdev b/lab-data/embedded-linux-qemu/appdev
deleted file mode 120000
index 2b2bb16b..00000000
--- a/lab-data/embedded-linux-qemu/appdev
+++ /dev/null
@@ -1 +0,0 @@
-../embedded-linux/appdev
\ No newline at end of file
diff --git a/lab-data/embedded-linux-qemu/appdev/app.c b/lab-data/embedded-linux-qemu/appdev/app.c
new file mode 100644
index 00000000..31e98ee3
--- /dev/null
+++ b/lab-data/embedded-linux-qemu/appdev/app.c
@@ -0,0 +1,91 @@
+#include <curses.h>
+#include <stdlib.h>
+#include <time.h>
+
+int main(void)
+{
+	WINDOW * mainwin;
+	int ch, x, y, mx, my, tx, ty;
+	int won = 0;
+
+	srand(time(NULL));
+
+	/*  Initialize ncurses  */
+	mainwin = initscr();
+	if (mainwin == NULL) {
+		fprintf(stderr, "Error initializing ncurses.\n");
+		exit(EXIT_FAILURE);
+	}
+
+	noecho();					/*  Turn off key echoing                 */
+	keypad(mainwin, TRUE);		/*  Enable the keypad for non-char keys  */
+	curs_set(0);				/* Turn off cursor */
+
+	getmaxyx(mainwin, mx, my);
+	mx--;
+	my--;
+
+	x = mx / 2;
+	y = my / 2;
+	tx = rand() % mx;	/* Never do that, distribution is not uniform */
+	ty = rand() % my;	/* Never do that, distribution is not uniform */
+
+	mvaddstr(0, my / 2 - 6, "Hello World!");
+	mvaddstr(mx, 0, "Move to the target (X), 'q' to quit");
+	mvprintw(x, y, "O");
+	mvprintw(tx, ty, "X");
+	move(mx, my); /* In case the cursor can't be turned off */
+	refresh();
+
+	/*  Loop until user presses 'q'  */
+	while ((ch = getch()) != 'q') {
+		if (won)
+			continue;
+
+		mvaddch(x, y, ' ');
+		switch(ch) {
+			case KEY_DOWN:
+				ch = 'v';
+				x++;
+				break;
+			case KEY_LEFT:
+				ch = '<';
+				y--;
+				break;
+			case KEY_RIGHT:
+				ch = '>';
+				y++;
+				break;
+			case KEY_UP:
+				ch = '^';
+				x--;
+				break;
+		}
+
+		if (x < 1)
+			x = 1;
+		if (x > mx - 1)
+			x = mx - 1;
+		if (y < 0)
+			y = 0;
+		if (y > my)
+			y = my;
+		mvaddch(x, y, ch);
+
+		if ((x == tx) && (y == ty))
+		{
+			mvaddch(x, y, ' ');
+			mvprintw(mx / 2, my / 2 - 4, "You won!");
+			won = 1;
+		}
+		move(mx, my); /* In case the cursor can't be turned off */
+		refresh();
+	}
+
+	/* Clean */
+	delwin(mainwin);
+	endwin();
+	refresh();
+
+	return EXIT_SUCCESS;
+}
diff --git a/lab-data/embedded-linux-qemu/debugging/data/vista-emulator.c b/lab-data/embedded-linux-qemu/debugging/data/vista-emulator.c
new file mode 100644
index 00000000..c7582d19
--- /dev/null
+++ b/lab-data/embedded-linux-qemu/debugging/data/vista-emulator.c
@@ -0,0 +1,78 @@
+/* Vista emulator on Linux
+ * Copyright 2002, B. Gates
+ *
+ * Permission to run this program without restriction,
+ * especially on Linux systems!
+ */
+
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+int cycles = 0;
+
+void bsod (char *msg)
+{
+	printf ("%s", msg);
+	exit (EXIT_FAILURE);
+}
+
+int file_exists(const char * filename)
+{
+    FILE *file;
+
+    if (file = fopen(filename, "r"))
+    {
+        fclose(file);
+        return 1;
+    }
+    return 0;
+}
+
+
+void log_activity (void *buffer)
+{
+	/* Look for traces of "Premium" content in system memory */
+
+	if (strstr(buffer, "Mickey Mouse"))
+	{
+		bsod("Found unencrypted media on your system. Calling the cops\n");
+	}
+
+	++cycles;
+}
+
+int init_resources (void)
+{
+	void *buffer;
+	int buffer_size = 655360; /* 640 KB, the limit that can never be exceeded */
+	buffer = malloc(buffer_size);
+	log_activity(buffer);
+}
+
+int main (void)
+{
+	int i;
+
+	do
+	{
+		/* Refuse to run until the activation key file is found */
+
+		while (! file_exists("/etc/vista.key"))
+		{
+		      sleep(1);
+		}
+
+		/* Now, start gathering system resources */
+
+		for (i=0; i < 10000; i++)
+		{
+			init_resources();
+		}
+
+	} while (cycles < 100);
+
+	bsod ("ERROR: Vista has been running for too long\nRestart it to improve performance\n");
+}
diff --git a/labs/sysdev-application-debugging-qemu/sysdev-application-debugging-qemu.tex b/labs/sysdev-application-debugging-qemu/sysdev-application-debugging-qemu.tex
new file mode 100644
index 00000000..48ec82af
--- /dev/null
+++ b/labs/sysdev-application-debugging-qemu/sysdev-application-debugging-qemu.tex
@@ -0,0 +1,201 @@
+\subchapter{Remote application debugging}{Objective: Use \code{strace}
+  and \code{ltrace} to diagnose program issues. Use \code{gdbserver} and a
+  cross-debugger to remotely debug an embedded application}
+
+\section{Setup}
+
+Go to the \code{$HOME/__SESSION_NAME__-labs/debugging} directory.
+Create an \code{nfsroot} directory.
+
+\section{Debugging setup}
+
+Because of issues in {\em gdb} and {\em ltrace} in the uClibc version
+that we are using in our toolchain, we will use a different toolchain
+in this lab, based on {\em glibc}.
+
+As {\em glibc} has more complete features than lighter libraries,
+it looks like a good idea to do your application debugging work
+with a {\em glibc} toolchain first, and then switch to lighter libraries
+once your application and software stack is production ready.
+
+As done in the {\em Buildroot} lab, clone once again the Buildroot
+{\em Git} repository, and checkout the tag corresponding to the latest
+2022.02.<n> release (Long Term Support), which we have tested for this lab.
+
+Then, in the \code{menuconfig} interface, configure the target
+architecture as done previously but configure the toolchain and
+target packages differently:
+
+\begin{itemize}
+\item In \code{Toolchain}:
+   \begin{itemize}
+   \item \code{Toolchain type}: \code{External toolchain}
+   \item \code{Toolchain}: \code{Bootlin toolchains}
+   \item \code{Toolchain origin}: \code{Toolchain to be downloaded and installed}
+   \item \code{Bootlin toolchain variant}: \code{armv7-eabihf glibc stable 2021.11-1}
+   \item Select \code{Copy gdb server to the Target}
+   \end{itemize}
+ \item \code{Target packages}
+   \begin{itemize}
+   \item \code{Debugging, profiling and benchmark}
+     \begin{itemize}
+     \item Select \code{ltrace}
+     \item Select \code{strace}
+     \end{itemize}
+   \end{itemize}
+\end{itemize}
+
+Now, build your root filesystem.
+
+Go back to the \code{$HOME/__SESSION_NAME__-labs/debugging} directory
+and extract the \code{buildroot/output/images/rootfs.tar}
+archive in the \code{nfsroot} directory.
+
+Add this directory to the \code{/etc/exports} file and run
+\code{sudo exportfs -r}.
+
+Boot your ARM board over NFS on this new filesystem, using the same
+kernel as before.
+
+\section{Using strace}
+
+Now, go to the \code{$HOME/__SESSION_NAME__-labs/debugging} directory.
+
+\code{strace} allows to trace all the system calls made by a process:
+opening, reading and writing files, starting other processes,
+accessing time, etc. When something goes wrong in your application,
+strace is an invaluable tool to see what it actually does, even when
+you don't have the source code.
+
+
+Update the PATH:
+%\footnotesize
+\begin{bashinput}
+$ export PATH=$HOME/__SESSION_NAME__-labs/debugging/buildroot/output/host/bin:$PATH
+\end{bashinput}
+\normalsize
+
+With your cross-compiling toolchain
+compile the \code{data/vista-emulator.c} program, strip it with
+\code{arm-linux-strip}, and copy the resulting binary to the
+\code{/root} directory of the root filesystem.
+
+Back to target system, try to run the \code{/root/vista-emulator}
+program. It should hang indefinitely!
+
+Interrupt this program by hitting \code{[Ctrl] [C]}.
+
+Now, running this program again through the \code{strace} command and
+understand why it hangs. You can guess it without reading the source
+code!
+
+Now add what the program was waiting for, and now see your program
+proceed to another bug, failing with a segmentation fault.
+
+\section{Using ltrace}
+
+Now run the program through \code{ltrace}.
+
+Now you should see what the program does: it tries to consume as much
+system memory as it can!
+
+Also run the program through \code{ltrace -c}, to see what function call
+statistics this utility can provide.
+
+It's also interesting to run the program again with \code{strace}. You
+will see that memory allocations translate into \code{mmap()} system
+calls. That's how you can recognize them when you're using
+\code{strace}.
+
+\section{Using gdbserver}
+
+We are now going to use \code{gdbserver} to understand why the program
+segfaults.
+
+Compile \code{vista-emulator.c} again with the \code{-g} option to
+include debugging symbols. This time, just keep it on your workstation,
+as you already have the version without debugging symbols on your target.
+
+Then, on the target side, run \code{vista-emulator} under
+\code{gdbserver}. \code{gdbserver} will listen on a TCP port for a
+connection from \code{gdb}, and will control the execution of
+\code{vista-emulator} according to the \code{gdb} commands:
+
+\ubootcmd{=> gdbserver localhost:2345 vista-emulator}
+
+On the host side, run \code{arm-linux-gdb} (also found in your toolchain):
+\bashcmd{$ arm-linux-gdb vista-emulator}
+
+\code{gdb} starts and loads the debugging information from the
+\code{vista-emulator} binary that has been compiled with \code{-g}.
+
+Then, we need to tell where to find our libraries, since they are not
+present in the default \code{/lib} and \code{/usr/lib} directories on
+your workstation. This is done by setting the \code{gdb} \code{sysroot}
+variable (on one line):
+
+\begin{bashinput}
+(gdb) set sysroot /home/<user>/__SESSION_NAME__-labs/debugging/\
+    buildroot/output/staging
+\end{bashinput}
+
+Of course, replace \code{<user>} by your actual user name.
+
+And tell \code{gdb} to connect to the remote system:
+\begin{bashinput}
+(gdb) target remote <target-ip-address>:2345
+\end{bashinput}
+
+Then, use \code{gdb} as usual to set breakpoints, look at the source
+code, run the application step by step, etc. Graphical versions of
+\code{gdb}, such as \code{ddd} can also be used in the same way.
+In our case, we'll just start the program and wait for it to hit
+the segmentation fault:
+\begin{bashinput}
+(gdb) continue
+\end{bashinput}
+
+You could then ask for a backtrace to see where this happened:
+\begin{bashinput}
+(gdb) backtrace
+\end{bashinput}
+
+This will tell you that the segmentation fault occurred in a function
+of the C library, called by our program. This should help you in
+finding the bug in our application.
+
+\section{Post mortem analysis}
+
+Following the details in the slides, configure your shell on the
+target to get a \code{core} file dumped when you run \code{vista-emulator}
+again.
+
+Once you have such a file, inspect it with \code{arm-linux-gdb} on
+the target, set the \code{sysroot} setting, and then generate
+a backtrace to see where the program crashed.
+
+This way, you can have information about the crash without
+running the program through the debugger.
+
+\section{What to remember}
+
+During this lab, we learned that...
+\begin{itemize}
+
+\item It's easy to study the behavior of programs and diagnose issues
+  without even having the source code, thanks to \code{strace} and
+  \code{ltrace}.
+
+\item You can leave a small \code{gdbserver} program (about 300 KB) on your target
+  that allows to debug target applications, using a standard \code{gdb}
+  debugger on the development host.
+
+\item It is fine to strip applications and binaries on the target
+  machine, as long as the programs and libraries with debugging
+  symbols are available on the development host.
+
+\item Thanks to \code{core} dumps, you can know where a program crashed,
+  without having to reproduce the issue by running the program through
+  the debugger.
+
+\end{itemize}
diff --git a/labs/sysdev-application-development-qemu/sysdev-application-development-qemu.tex b/labs/sysdev-application-development-qemu/sysdev-application-development-qemu.tex
new file mode 100644
index 00000000..f1d0d93f
--- /dev/null
+++ b/labs/sysdev-application-development-qemu/sysdev-application-development-qemu.tex
@@ -0,0 +1,50 @@
+\subchapter{Application development}{Objective: Compile and run your
+  own ncurses application on the target.}
+
+\section{Setup}
+
+Go to the \code{$HOME/__SESSION_NAME__-labs/appdev} directory.
+
+\section{Compile your own application}
+
+We will re-use the system built during the {\em Buildroot lab} and add
+to it our own application.
+
+In the lab directory the file \code{app.c} contains a very simple
+{\em ncurses} application. It is a simple game where you need to reach
+a target using the arrow keys of your keyboard.  We will compile and
+integrate this simple application to our Linux system.
+
+Buildroot has generated toolchain wrappers in
+\code{output/host/bin}, which make it easier to use the toolchain,
+since these wrappers pass some mandatory flags (especially the
+\code{--sysroot} {\em gcc} flag, which tells {\em gcc} where to look
+for the headers and libraries).
+
+Let's add this directory to our \code{PATH}:
+
+\begin{bashinput}
+$ export PATH=$HOME/__SESSION_NAME__-labs/buildroot/buildroot/output/host/bin:$PATH
+\end{bashinput}
+\normalsize
+
+Let's try to compile the application:
+
+\bashcmd{$ arm-linux-gcc -o app app.c}
+
+It complains about undefined references to some symbols. This is
+normal, since we didn't tell the compiler to link with the necessary
+libraries. So let's use \code{pkg-config} to query the {\em
+pkg-config} database about the location of the header files and the
+list of libraries needed to build an application against
+{\em ncurses}\footnote{Again, \code{output/host/bin} has a special
+\code{pkg-config} that automatically knows where to look, so it
+already knows the right paths to find \code{.pc} files and their
+sysroot.}:
+
+\bashcmd{$ arm-linux-gcc -o app app.c $(pkg-config --libs --cflags ncurses)}
+
+Our application is now compiled! Copy the generated binary to the NFS
+root filesystem (in the \code{root/} directory for example), start
+your system, and run your application!
+
diff --git a/labs/sysdev-buildroot-qemu/sysdev-buildroot-qemu.tex b/labs/sysdev-buildroot-qemu/sysdev-buildroot-qemu.tex
index 21f5a9d1..5b0af6df 100644
--- a/labs/sysdev-buildroot-qemu/sysdev-buildroot-qemu.tex
+++ b/labs/sysdev-buildroot-qemu/sysdev-buildroot-qemu.tex
@@ -135,7 +135,11 @@ button whenever you need more details about a given option:
     \begin{itemize}
     \item Select \code{alsa-utils}, and in the submenu:
     \begin{itemize}
-         \item Only keep \code{speaker-test}
+         \item Select \code{alsamixer}. You will be able to
+	       test this application too, and that will also pull
+	       the \code{ncurses} library, which we will also use
+	       in the next lab.
+         \item Select \code{speaker-test}
     \end{itemize}
     \item Select \code{mpd}, and in the submenu:
     \begin{itemize}
@@ -217,7 +221,9 @@ Boot the board, and log in (\code{root} account, no password).
 
 You should now reach a shell.
 
-You can run \code{speaker-test} to check that this application works.
+Even though we have no sound at the moment, you can run \code{speaker-test}
+to check that this application works. You can also test the \code{alsamixer}
+command too.
 
 By running the \code{ps} command, you may also check whether the \code{mpd}
 server was started on your system. However, as said earlier, we won't try
diff --git a/mk/embedded-linux-qemu.mk b/mk/embedded-linux-qemu.mk
index b3b41cd2..faf0dc3a 100644
--- a/mk/embedded-linux-qemu.mk
+++ b/mk/embedded-linux-qemu.mk
@@ -56,4 +56,5 @@ EMBEDDED_LINUX_QEMU_LABS   = \
                 sysdev-block-filesystems-qemu \
                 sysdev-thirdparty-qemu \
                 sysdev-buildroot-qemu \
-		sysdev-application-development-and-debugging
+		sysdev-application-development-qemu \
+		sysdev-application-debugging-qemu \




More information about the training-materials-updates mailing list