[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

[HOWTO] Booting and debugging oskit-mach



I've written a short HOWTO on booting and debugging oskit-mach
over a serial console. Any questions, suggestions, and corrections
are welcome. It can also be found at
http://www.multiverse.ca/hurd/oskit-boot.txt. but I can't garantee
that this site will always be available, so I would appreciate if
someone could mirror it.

Thanks.

Igor
	Booting oskit-mach with a serial console
	========================================

	Author: Igor Khavkine <i_khavki@alcor.concordia.ca>
	Last Updated: Mon Jul 30 17:58:55 EDT 2001

Why?
----

Why? because it's covenient. If you have a second computer, but not
a second monitor or keyboard, you can connet your second box to your
main one using null-modem serial cables. Once that is done, you can
configure the GRUB bootloader to use the serial port when starting up
and boot oskit-mach without having to switch monitor cables or type
blindly at a second keyboard. Also, oskit-mach supports the GDB remote
debugging protocol over a serial line. This way it's now possible
to debug the running kernel relatively unobtrusively because, the
debugger will not be running on the same machine.

How?
----

First you need some equipment: two computers, each one should have at
least one (two is preferable) free serial ports, as many null-modem
serial cables. Then you need to follow the instructions given below.

(1)	The first step is to get sourcefor oskit-mach and
	oskit. Currently (2001-07-30) you have to get the sources for
	oskit from [2] and compile them yourself. You need to get the
	snapshot oskit-20000202, newer versions either don't work or
	have not been tested. Hoefuly this situation will change in the
	future.  Now is your chance (if you wish) to compile oskit with
	debugging symbols. (If you encounter errors while compiling, try
	removing anything that has to do with `unix' or `examples' from
	the file modules.x86.pc). Then you need to get the sources for
	oskit-mach. They are available from the GNU CVS repository[3],
	you need to check out the `gnumach' module with the flag
	`-roskit-branch'. Again now is your chance to compile oskit-mach
	with debugging symbols.

(2)	Now you need to setup GRUB on your second box so it would accept
	input from a serial port while booting up. This is simple to do
	by adding the following lines to your `menu.lst' file, before
	any of the menu entries:

		serial --unit=0 --speed=9600
		terminal serial

	Unit refers to the serial port you wish to use (0 is COM1), and
	speed is optional. For more information see the GRUB
	documentation.

(3)	You need to make sure that your main box has the necessary
	utilities to communicate with your second box over a serial
	line. You can use a terminal emulator like minicom(1), or a
	simple serial communication program cu(1) which comes with the
	GNU uucp package. Or if you feel really lazy you can use this
	hack:
		stty raw
		cat > /dev/ttyS1 # in one terminal window
		cat /dev/ttyS1   # in a second terminal window

(4)	Now you have to make sure your computer has an at least
	partially  setup Hurd partition. You can find instructions
	how to do that here [4,5]. Copy the oskit-mach kernel binary
	compressed with gzip to /boot/oskit-mach.gz and use the
	following command line[1] to boot it from GRUB:

/boot/gnumach.test.gz -h CONS_COM=1 -d GDB_COM=2 BAUD=9600 -- root=hd0s2

	-h (use serial console)
	CONS_COM=1 (COM1)
	CONS_COM=2 (COM2)
	CONS_COM=3 (COM3)
	CONS_COM=4 (COM4)

	-d (enable serial port debugging, optional)
	GDB_COM=2 (use a different port other then CONS_COM, default is
		to use the same as CONS_COM)
	BAUD=9600 (use this baud rate, optional, default is 9600)

	-- (delimits the arguments passed to the oskit from those to
		the kernel)

	root=hd0s2 (tell gnumach which is your root partition, in
		this case it's hd0s2)

(5)	Now I suggest that you familiarize yourself with the GDB
	documentation on remote debugging. If you pass the -d boot flag
	to oskit-mach, then it will automatically insert a breakpoint
	at main() and wait for further instructions from GDB over the
	serial line. Here's a simple example of how to attach GDB
	to a remote target over a serial line:

		$ script # record the debugging session
		$ gdb # assume you're in the oskit-mach build dir.
		(gdb) file kernel
		(gdb) target remote /dev/ttyS0
			[...gdb attached, blah, blah, blah...]
		(gdb) break panic
		(gdb) continue
			[...]
		(gdb) quit
		$ ^D # finish recording the session

	This way you can catch any kernel panics (except for the really
	nasty ones and try to debug them).

	I've noticed that once oskit-mach is running under GDB, pressing
	C-c from GDB will not suspend it, this makes it hard to set
	additional breakpoints after the kernel is running. So optinally
	you can modify oskit-mach to add a dummy system call that will
	be used only for setting breakpoints, and make a small program
	that calls it, you can use it whenever you want to pause the
	kernel and examine something under GDB. An example of how to
	do this is attached in Appendix A.

Now you're all set to do some serious kernel hacking. I hope more people
will take advantage of this opportunity.


Appendix A
----------

Apply this patch to oskit-mach to add a dummy system call:

--- gdb-stub.diff ---
Index: kern/syscall_sw.c
===================================================================
RCS file: /cvs/gnumach/kern/syscall_sw.c,v
retrieving revision 1.1.1.1.2.2
diff -u -r1.1.1.1.2.2 syscall_sw.c
--- kern/syscall_sw.c	2001/04/05 06:52:47	1.1.1.1.2.2
+++ kern/syscall_sw.c	2001/07/30 21:45:14
@@ -98,6 +98,8 @@
 extern kern_return_t	syscall_fipc_recv();
 #endif /* FIPC */
 
+/*XXX*/extern kern_return_t gdb_break_stub ();
+
 mach_trap_t	mach_trap_table[] = {
 	MACH_TRAP(kern_invalid, 0),		/* 0 */		/* Unix */
 	MACH_TRAP(kern_invalid, 0),		/* 1 */		/* Unix */
@@ -283,7 +285,14 @@
 	MACH_TRAP(kern_invalid, 0),		/* 126 */
 	MACH_TRAP(kern_invalid, 0),		/* 127 */
 	MACH_TRAP(kern_invalid, 0),		/* 128 */
-	MACH_TRAP(kern_invalid, 0),		/* 129 */
+	MACH_TRAP(gdb_break_stub, 1),		/* 129 */
 };
 
+volatile int gdb_break_stub (void *addr) /*XXX*/
+{
+	void *dummy;
+	dummy = addr;
+	return 0;
+}
+
 int	mach_trap_count = (sizeof(mach_trap_table) / sizeof(mach_trap_table[0]));
--- end ---

When starting an oskit-mach debug session with GDB set a break poit at
`gdb_break_stub'. Then use this program to invoke the system call when
desired:

--- gdb-break.c ---
/* Compile with: gcc -o gdb-break gdb-break.c gdb-break-stub.S */

#include <mach.h>

#include <stdio.h>
#include <string.h>

extern int gdb_break_stub (void *addr);

int main () {
	kern_return_t err;

	err = gdb_break_stub (&main);
	printf ("result from syscall: %s\n", strerror(err));

	return 0;
}
--- end ---
--- gdb-break-stub.S ---
#include <mach/syscall_sw.h>

kernel_trap(gdb_break_stub,-129,1)
--- end ---


References
----------

[1] OSKit documentation, section 1.6.3.
[2] http://www.cs.utah.edu/flux/oskit/
[3] http://www.gnu.org/software/devel
[4] http://www.walfield.org/papers/hurd-installation-guide/
[5] http://www.pick.ucam.org/~mcv21/hurd.html

 vim:ts=8:tw=72:sw=8:

Reply to: