Michał Matczuk Tomasz Dziedzicki i Piotr Wygodzki
Debugowanie Jądra


Printk() - Coś co naprawdę ma sens ...

Co to jest?


Funkcja printk() działa niemal identycznie, jak funkcja printf() z biblioteki dostępnej przy programowaniu przestrzeni użytkownika. Tak więc jest to funkcja wypisująca sformatowany ciąg znakowy. Nie jest jednak do końca taka zwyczajna.



Przykład

printk(KERN_DEBUG "Nazwa pliku = %s", filename);

printk(KERN_WARNING "Minister zdrowia ostrzega: palenie tytoniu powoduje choroby płuc.\n");

printk("Nie został określony poziom rejestrowania.\n");





Priorytety

KERN_EMERG < 0> Sytuacja awaryjna
KERN_ALERT < 1> Problem wymagający natychmiastowej interwencji
KERN_CRIT < 2> Sytuacja krytyczna
KERN_ERR < 3> Błąd
KERN_WARNING < 4> Ostrzeżenie
KERN_NOTICE < 5> Sytuacja normalna, warta odnotowania
KERN_INFO < 6> Informacja
KERN_DEBUG < 7> Komunikat diagnostyczny




Jak to jest?

Za pobieranie komunikatów jądra z bufora odpowiedzialny jest demon przestrzeni użytkownika klogd. Demon ten zapisuje komunikaty do systemowego pliku dziennika, korzystając przy tym z pomocy demona syslogd. klogd w celu odczytywania komunikatów korzysta z pliku /proc/kmsg (bądź też z systemowego wywołania syslog()). klog budzi się, gdy przychodzi nowy komunikat i przekazuje go do demona syslogd.




Ważne pliki

/var/log/messages
/etc/syslog.conf




Przydatne Makra

BUG()
BUG_ON()
panic()
dump_stack()




Linux/arch/v850/kernel/bug.c

void __bug ()
{
printk (KERN_CRIT "kernel BUG at PC 0x%x (SP ~0x%x)!\n",
ret_addr() - 4, /* - 4 for `jarl' */
stack_addr());
machine_halt ();
}



http://lisa.cs.uni-potsdam.de/lxr/source/



ltrace czyli Krzysztof Gibas i problemy z kde

Problem ze startowaniem KDE. Zwrócony błąd:

"_KDE_IceTransSocketCreateListener: failed to bind listener
_KDE_IceTransSocketUNIXCreateListener: ...SocketCreateListener() failed
_KDE_IceTransMakeAllCOTSServerListeners: failed to create listener for local

Cannot establish any listening sockets DCOPServer self-test failed."


ROZWIAZANIE=
strace -f -F -o ~/dcop-strace.txt dcopserver


27207 mkdir("/tmp/.ICE-unix", 0777) = -1 EEXIST (File exists)
27207 lstat64("/tmp/.ICE-unix", {st_mode=S_IFDIR|S_ISVTX|0755, st_size=4096, ...}) = 0
27207 unlink("/tmp/.ICE-unix/dcop27207-1066844596") = -1 ENOENT (No such file or directory)
27207 bind(3, {sin_family=AF_UNIX, path="/tmp/.ICE-unix/dcop27207-1066844596"}, 38) = -1 EACCES (Permission denied)
27207 write(2, "_KDE_IceTrans", 13) = 13
27207 write(2, "SocketCreateListener: failed to "..., 46) = 46
27207 close(3) = 0 27207 write(2, "_KDE_IceTrans", 13) = 13
27207 write(2, "SocketUNIXCreateListener: ...Soc"..., 59) = 59
27207 umask(0) = 0 27207 write(2, "_KDE_IceTrans", 13) = 13
27207 write(2, "MakeAllCOTSServerListeners: fail"..., 64) = 64
27207 write(2, "Cannot establish any listening s"..., 39) = 39




ltrace = wywolania funkcji bibliotecznych


KDB (Built-in kernel debugger for Linux)

Debugger'y - czy naprawdę potrzebne?
Linus Torvalds:
I don't like debuggers. Never have, probably never will. I use gdb all the time, but I tend to use it not as a debugger, but as a disassembler on steroids that you can program.
None of the arguments for a kernel debugger has touched me in the least. And trust me, over the years I've heard quite a lot of them. In the end, they tend to boil down to basically: It would be so much easier to do development, and we'd be able to add new things faster.
And quite frankly, I don't care. I don't think kernel development should be "easy". I do not condone single-stepping through code to find the bug. I do not think that extra visibility into the system is necessarily a good thing.

Jak widać nie wszyscy sądzą, że są one niezbędne, niemniej naszym zdaniem warto sprawdzić, czy nie ułatwią nam one choćby pracy nad projektami z laboratorium.



KDB - Co to właściwie jest?

  • Patch na jądro.
  • Mało inwazyjny - możliwa kompilacja bez frame pointers.
  • Możemy testować jądro na tej maszynie, na której je odplamy.
  • Mało użyteczny - brak możliwości debugowania z poziomu kodu (jedynie assembler).


  • KDB - Możliwości

  • Breakpointy.
  • Możliwość wykonywania instrukcja po instrukcji.
  • Podglądanie rejestrów i komórek pamięci.
  • Zmiana zawartości rejestrów lub komórek pamięci.
  • Podgląd stosu aktualnego procesu, procesu o danym PID.
  • Deasemblacja instrukcji.

  • KDB - miłe złego początki, czyli nieco o instalacji.
    Instalacja:
    1. Pobieramy kod jądra i rozpakowujemy.
      wget ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.17.13.tar.bz2
      tar -jxvf linux-2.6.17.13.tar.bz2
    2. Pobieramy patch-e i rozpakowujemy je poleceniem bunzip nazwa_patcha.bz2
      wget ftp://oss.sgi.com/www/projects/kdb/download/v4.4/kdb-v4.4-2.6.17-common-1.bz2
      wget ftp://oss.sgi.com/www/projects/kdb/download/v4.4/kdb-v4.4-2.6.17-i386-1.bz2
    3. Ładujemy patch-e w folderze z rozpakowanymi źródłami (zakładamy że patche są folder wyżej)
      patch -p1 < ../kdb-v4.2-2.6.17-common-1
      patch -p1 < ../kdb-v4.2-2.6.17-i386-1
    4. Kopiujemy jakiegoś działającego configa (np tego z /boot) do folderu ze źródłami i zapisujemy go jako plik .config
    5. Wykonujemy polecenie make menuconfig, zaznaczając w kernel hacking opcje:
      Built-in Kernel Debugger support - wymagane
      Compile the kernel with framepointers - nie wymagane, nieco inwazyjne, ale wspiera debuggowanie (lepsze śledzenie stosu)
      KDB off by default - opcjonalne, wtedy aby przywołać kdb musimy wykonać polecenie:
      echo "1" > /proc/sys/kernel/kdb aby ustawić odpowiednią flagę umożliwiającą uruchomienie kdb
    6. Możemy ręcznie przywołać KDB naciskając Ctrl-Pause . Zostanie wyświetlony prompt KDB i możemy korzystać jego dobrodziejstw. Każdorazowo przy kernel panic kdb zostanie przywołane automatycznie.



    Trochę praktyki...



    KGDB (Kernel Debugging with remote GDB)



    Co to właściwie jest?
    1. Potrzebne są dwie maszyny połączone przez port szeregowy.
      Target Machine: Musi miec jadro skompilowane z patchami niezbędnymi do oblugi KGDB.
      Development Machine: Musi mieć zainstalowane GDB.
    2. Debugowanie z poziomu kodu.
    3. Konieczna kompilacja z frame pointers - jest więc nieco inwazyjny.

    Możliwości:
    1. Debugowanie z poziomu kodu. Możliwość wykonania kodu jądra instukcja po instrukcji.
    2. Breakpointy (na zmiennych, instrukcjach, rejestrach)
    3. Podgląd wartości zmiennych, rejestrów.
    4. Modyfikowanie w locie wartości zmiennych, rejestrów.
    5. Możliwość przekierowania informacji konsolowych na zdalną konsolę.
    6. Wsparcie dla mechanizmu wątków.
    7. Wsparcie dla debugowania modułów.
    8. Wsparcie dla architektur wieloprocesorowych.
    9. Wygodny debug - wszystkie możliwości gdb, a to już chyba wszyscy znamy.

    Przypadatne linki:
  • źródła jądra
    http://www.kernel.org/pub/linux/kernel
  • Główna strona projetku KGDB
    http://kgdb.linsyssoft.com/
  • instalacja pod VMware - polecamy, sami korzystaliśmy, proponujemy robić to wszystko na jądrze 2.6.15.6, mimo ze wersja kgdb jest oficjalnie pod jądro 2.6.15.5
    http://oslab.info/index.php/Misc/KGDB
  • nieco o gdb
    http://safari.phptr.com/0131492470/ch03#ch03


  • UML Czyli User-Mode-Linux
    Wiemy dobrze z poprzedniej prezentacji czym zajmuje się wirtualizacja. Dziś spróbuję zapoznać was bliżej ze specyficzną maszyną wirtualną - UML. Oraz postaram się pokazać jak UML może nam pomóc

    Co różni UML od innych wirtualizacji?
    O UML mówi się czasem: Wirtualny System Operacyjny

    VVware - pełna wirtualizacja sprzętowa ["dowolny" OS]

    UML - "port of Linux to Linux" oparty na Linuxowych wywołaniach systemowych


    Przewaga UML nad innymi podejściami do wirtualizacji
    Najbardziej odczuwalna różnica - Prędkość

    Łatwość zmiany urządzeń i interfejsów
    [./linux ubd0=rootfs.debian ubd1=swapfs.debian con0=fd:0,fd:1 eth0=tuntap,FE:FD,78:DD:AG:CC
    uml-debby mem=512M ... szczegóły w dalszej części]

    Wiele instancji UML może korzystać z tych samych plików [root_fs]

    Można zagnieżdżać instancje UML w sobie

    Można zainstalować dowolną dystrybucje Linux'a

    Dobra izolacja
    UML działa jako zestaw procesów w przestrzeni Użytkownika [poziom izolacji procesów]

    Gdzie jest UML...
    [Xen - VMware - .... - UML - ... - chroot]


    Wirtualizacja i wsparcie dla sprzętu
    UML wymaga wirtualnego sprzętu i jest dostarczany ze sterownikami
    1. konsoli
    2. wirtualnego systemu plików [VFS]
    3. sieci
    4. specjalnego urządzenia pozwalającego na zarządzanie UML'em


    Baśń o 2 jądrach
    Do działania UML potrzebujemy 2 jąder
    1. Jądro gościa (guest kernel)
    2. Jądro gospodarza (host kernel)

    UML działa w jednym z trybów TTmode lub SKASmode.

    Potencjalnie każde jądro (>2.2) powinno móc obsłużyć UML w trybie TT lub SKAS0
    tryb SKAS3 wymaga nałożenia łaty na jądro gospodarza (host kernel)


    Jak to działa [Design] i czym się różni tryb SKAS od trybu TT
    UML jest zaprojektowany jako przeniesienie (port) jądra Linuxa na specjalną platformę um.

    UML(guest kernel) jest uruchamiany pod kontrolą jądra systemu(host kernel) jako proces użytkownika.

    UML korzysta z jądra systemu(host kernel) tylko do emulowania wirtualnego sprzętu.

    UML ma swój własny scheduler, pamięć wirtualną i w pełni sam zarządza swoimi procesami.
    [w szczególności jeśli system
    (host kernel) działa na jądrze 2.4 a UML(guest kernel) jest w
    wersji 2.6 to procesy
    gościa szeregowane są w O(1) tzn. system przydziela UMLowi procesor
    ale dalej UML szereuje swoje procesy sam]

    TT - Tracing Thread ... przeszłość
    Każdy proces w jądrze UML jest jednocześnie procesem w systemie nadrzędnym

    Jest specjalny wątek nazywany wątkiem śledzącym (tracing thread) który wyłapuje
    żądania systemowe i przekierowuje je do jądra UML.

    Każdy proces gościa ma ma kod jądra w swojej przestrzeni adresowej i domyślnie jest zapisywalny.
    [bezpieczeństwo / prędkość]

    SKAS - Single Kernel Address Space
    Jądra mają oddzielną przestrzeń adresową

    procesy gościa wyglądaja(przestrzeń adresowa) tak jak wyglądałyby nanormalnej maszynie

    Są 4 procesy UML widoczne z poziomu hosta

    FILOZOFIA: CELEM SKAS JEST POSIADANIE 1 PROCESU KTÓRY PRZEŁĄCZA SIĘ MIĘDZY WIELOMA PRZESTRZENIAMI ADRESOWYMI TAK BY NIE TRZYMAC CZEKAJĄCYCH PROCESÓW NA LISCIE PROCESÓW HOSTA


    wzięte z [1]

    wzięte z [1]

    UML w praktyce
    zbudujemy jądro gościa ze źródeł:

    $ cd ~/

    ściągamy jądro
    $ wget ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.17.13.tar.bz2
    $ mkdir UML
    $ cd UML
    $ tar zfx ../linux-2.6.17.13.tar.bz2
    $ ls -al
    drwxr-xr-x  19 miami users      4096 Nov  4 12:05 linux-2.6.17.13
    $ cd linux-2.6.17.13
    $ make defconfig ARCH=um
    $ make menuconfig ARCH=um


    musimy ustawić flagi CONFIG_DEBUGSYM oraz CONFIG_PT_PROXY
    to spowoduje kompilację jądra z opcja -g tak by można było używać gdb.

    w tym celu:























    następnie wybieramy opcje jak poniżej [wybór z górką]




    wychodzimy zapisując zmiany

    $ make linux ARCH=um
    $ make modules ARCH=um
    $ make modules_install ARCH=um INSTALL_MOD_PATH=/tmp
    $ strip linux
    $ ls -al
    ...
    drwxr-xr-x   4 miami users     8192 Nov  4 12:13 kernel
    drwxr-xr-x   5 miami users     4096 Nov  4 12:16 lib
    -rwxr-xr-x   2 miami users  1733692 Nov  4 12:28 linux
    drwxr-xr-x   2 miami users     4096 Nov  4 12:13 mm
    drwxr-xr-x  36 miami users     4096 Nov  4 12:16 net
    drwxr-xr-x   8 miami users     4096 Nov  4 12:12 scripts
    drwxr-xr-x   4 miami users     4096 Nov  4 12:14 security
    drwxr-xr-x  16 miami users     4096 Nov  4 12:16 sound
    drwxr-xr-x   2 miami users     4096 Nov  4 12:12 usr
    -rwxr-xr-x   2 miami users  1733692 Nov  4 12:28 vmlinux


    linux i vmlinux są twardymi połączeniami (hard link) do tego samego pliku.

    Spróbujmy uruchomić

    $ ./linux
    Checking that ptrace can change system call numbers...OK
    Checking syscall emulation patch for ptrace...OK
    Checking advanced syscall emulation patch for ptrace...OK
    Checking for tmpfs mount on /dev/shm...OK
    Checking PROT_EXEC mmap in /dev/shm/...OK
    Checking for the skas3 patch in the host:
      - /proc/mm...not found
      - PTRACE_FAULTINFO...not found
      - PTRACE_LDT...not found
    UML running in SKAS0 mode
    ...
    Failed to open 'root_fs', errno = 2
    VFS: Cannot open root device "98:0" or unknown-block(98,0)
    Please append a correct "root=" boot option
    Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(98,0)



    Oprócz jądra potrzebujemy jeszcze do działania - części "GNU" naszego systemu.
    Gdy uruchamiany ./linux szuka pliku root_fs w lokalnym katalogu, w tym pliku
    oczekuje znaleźć obraz sytemu plików ext2 zawierający narzędzia.

    istnieje wiele gotowych root_fs do ściągnięcia
    [http://sourceforge.net/project/showfiles.php?group_id=429&package_id=472]
    oraz narzędzi ułatwiających tworzenie własnych systemów plików.

    My posłużymy się gotowym slacwarem 8.1
    [http://mirror.usermodelinux.de/root_fs_slack8.1.bz2]

    $ cd ~/
    $ wget http://mirror.usermodelinux.de/root_fs_slack8.1.bz2
    $ mv root_fs_slack8.1.bz2 uml/root_fs.bz2
    $ cd uml
    $ bzip2 -fd root_fs.bz2
    $ mkdir mnt
    $ ls -al
    total 205832
    drwxr-xr-x   4 miami users        61 Nov  4 13:11 .
    drwxr-xr-x  52 miami users      4096 Nov  4 12:41 ..
    drwxr-xr-x  20 miami users      4096 Nov  4 12:28 linux-2.6.17.13
    drwxr-xr-x   2 miami users         6 Nov  4 13:11 mnt
    -rw-r--r--   1 miami users 210763776 Nov  4 12:52 root_fs


    zobaczmy co kryje się w tym pliku

    $ mount root_fs mnt/ -o loop
    $ cd mnt
    $ ls
    bin   dev  home  lost+found  proc  sbin  usr
    boot  etc  lib   mnt         root  tmp   var


    zgodnie z oczekiwaniami to co zwykle w kożeniu systemu plików.

    UWAGA!!

    $ ls dev/ubd*
    dev/ubd0  dev/ubd1  dev/ubd2

    to są urządzenia (uml block device) na które uml przypisuje obraz z pliku root_fs

    $ cat etc/fstab
    #/dev/ubd0      /            ext2    defaults                1   1
    /dev/ubd/0      /            ext2    defaults                1   1
    none            /dev/pts     devpts  gid=5,mode=620          0   0
    none            /proc        proc    defaults                0   0


    zwróćmy uwagę na komentarz w pliku fstab i na nazwy urządzeń.

    Jeśli pozostawimy ten komentarz system nie zadziała poprawnie
    fsck [file system check] będzie zgloszał błąd podczas startu


    usuwamy komentarz i odmontowujemy wolumin

    $ vim etc/fstab
    $ cd ../
    $ umount mnt


    uruchamiamy UML [skutecznie]

    $ cd linux-2.6.17.13
    $ ./linux ubd0=../root_fs


    udało sie...

    UML przy starcie otwiera 3 okna xterm [3 konsole] oraz czwartą w okienku w którym został uruchomiony.
    Możemy się zalogować
    $ Login: root
    $ Password: root


    By wyjść wydajemy komendę halt

    4 rzeczy które mogą sie nieudać [bardzo skończony podzbiór]

    niechce się skompilować

      1. ściągnij uml-patch-2.6.patch.bz2 [dla odpowiedniego jądra] z [7] [folder guest]
      2. cd linux-2.6.x.y
      3. bzcat uml-patch-2.6.patch.bz2 | patch -p1

    nieładuje root_fs


    nieotwierają się konsole [w xterm]
      1. można go ściągnąć z [6]
      2. skompilowac i umiescic w /user/bin

    Opcje uruchamiania
    $ ./linux
        mem=size[ K | M | G ]
        mem=300M

        ethn=interface configuration

        ubd<n><flags>=filename
        <flags> = {readonly = r; O_SYNC = s; data = d; shared = c}
        ubd0=../root_fs
     
        mode=skas0
        mode=tt
        debug

    Debugowanie w trybie tt

    Koncepcja polega na tym że przy starcie uruchamiany jest dodatkowy terminal z gdb
    z którego możemy kontrolowac system.

    Niestety tryb tt niedlugo zniknie. Nizaleca się stosowania.
    W jądrze jest oznaczony jako Deprecated.
    Przy uruchmianiu powoduje segfault.

    Debugowanie modułów przy pomocy umlgdb

    skrypt umlgdb jest częścią pakietu umltools którego składniki ściągamy z [6]

    chmod 700 umlgdb

    musimy zedytować treść skryptu:

    set MODULE_PATHS {
    "md5" "/tmp/crypto/md5.ko"
    "sha1" "/tmp/crypto/sha1.ko"

    "<nazwa>" "<adres>"
    }

    żeby uruchomić umlgdb potrzebujemy pakietu except
    ./umlgdb
                ******** GDB pid is 14931 ********
    Start UML as: ./linux <kernel switches> debug gdb-pid=14931



    GNU gdb 6.4
    Copyright 2005 Free Software Foundation, Inc.
    GDB is free software, covered by the GNU General Public License, and you are
    welcome to change it and/or distribute copies of it under certain conditions.
    Type "show copying" to see the conditions.
    There is absolutely no warranty for GDB.  Type "show warranty" for details.
    This GDB was configured as "i686-pc-linux-gnu"...Using host libthread_db library "/lib/libthread_db.so.1".

    następnie na innej konsoli uruchamiamy
    ./linux mode=tt debug gdb-pid=14931
    ...segfault

    Debugowanie w trybie SKAS

    jak zwykły program

    r - run
    n - next
    c - continue
    b - break
    p - print
    i - info
    l - list

    $ gdb linux
    gdb> b schedule
    Breakpoint 1 at 0xa020d039: file thread_info.h, line 50.
    gdb> handle SIGSEGV pass nostop noprint
    gdb>
    handle SIGUSR1 pass nostop noprint
    gdb> r ubd0=root_fs
    Breakpoint 1, schedule () at thread_info.h:50
    50              ti = (struct thread_info *) (((unsigned long) &ti) & ~mask);
    gdb> l
    45      /* how to get the thread information struct from C */
    46      static inline struct thread_info *current_thread_info(void)
    47      {
    48              struct thread_info *ti;
    49              unsigned long mask = THREAD_SIZE - 1;
    50              ti = (struct thread_info *) (((unsigned long) &ti) & ~mask);
    51              return ti;
    52      }
    53
    54      /* thread information allocation */
    gdb> i registers
    eax            0x1      0x1
    ecx            0x0      0x0
    edx            0xa025ce00       0xa025ce00
    ebx            0x0      0x0
    esp            0xa025bbac       0xa025bbac
    ebp            0xa025bc04       0xa025bc04
    esi            0x0      0x0
    edi            0xa0019638       0xa0019638
    eip            0xa020d039       0xa020d039 <schedule+9>
    eflags         0x296    0x296
    cs             0x73     0x73
    ss             0x7b     0x7b
    ds             0x7b     0x7b
    es             0x7b     0x7b
    fs             0x0      0x0
    gs             0x33     0x33

    gdb> i
    "info" must be followed by the name of an info command.
    List of info subcommands:

    info address -- Describe where symbol SYM is stored
    info all-registers -- List of all registers and their contents
    info args -- Argument variables of current stack frame
    info auxv -- Display the inferior's auxiliary vector
    info breakpoints -- Status of user-settable breakpoints
    info catch -- Exceptions that can be caught in the current stack frame
    info classes -- All Objective-C classes
    info common -- Print out the values contained in a Fortran COMMON block
    info copying -- Conditions for redistributing copies of GDB
    info dcache -- Print information on the dcache performance
    info display -- Expressions to display when program stops
    info extensions -- All filename extensions associated with a source language
    info files -- Names of targets and files being debugged
    info float -- Print the status of the floating point unit
    info frame -- All about selected stack frame
    info functions -- All function names
    info handle -- What debugger does when program gets various signals
    info line -- Core addresses of the code for a source line
    info locals -- Local variables of current stack frame
    info macro -- Show the definition of MACRO
    info mem -- Memory region attributes
    info proc -- Show /proc process information about any running process
    info program -- Execution status of the program
    info registers -- List of integer registers and their contents
    info scope -- List the variables local to a scope
    info selectors -- All Objective-C selectors
    info set -- Show all GDB settings
    info sharedlibrary -- Status of loaded shared object libraries
    info signals -- What debugger does when program gets various signals
    info source -- Information about the current source file
    info sources -- Source files in the program
    info stack -- Backtrace of the stack
    info symbol -- Describe what symbol is at location ADDR
    info target -- Names of targets and files being debugged
    info terminal -- Print inferior's saved terminal status
    info threads -- IDs of currently known threads
    info tracepoints -- Status of tracepoints
    info types -- All type names
    info variables -- All global and static variable names
    info vector -- Print the status of the vector unit
    info warranty -- Various kinds of warranty you do not have
    info watchpoints -- Synonym for ``info breakpoints''
    info win -- List of all displayed windows

    Type "help info" followed by info subcommand name for full documentation.
    Command name abbreviations are allowed if unambiguous.
    gdb> quit


    bibliografia:
    [0]
    http://user-mode-linux.sourceforge.net/sdotm.html
    [1]Dike Jeff - User Mode Linux, Prentice Hall April 12, 2006
    [2]http://user-mode-linux.sourceforge.net
    [3]http://user-mode-linux.sourceforge.net/UserModeLinux-HOWTO.html
    [4]http://www.user-mode-linux.org/~blaisorblade/howtoapply.html
    [5]http://www.redhat.com/magazine/001nov04/features/usermode/
    [6]http://www.user-mode-linux.org/cvs/tools/
    [7]http://www.user-mode-linux.org/~blaisorblade/patches/