From: Octavian Purdila <t...@cs.pub.ro>

Add the documentation and templates for the kernel modules lab which
focuses on: creating simple modules; describing the process of kernel
module compilation; presenting how a module can be used with a kernel;
simple kernel debugging methods

Signed-off-by: Octavian Purdila <t...@cs.pub.ro>
Signed-off-by: Daniel Baluta <daniel.bal...@gmail.com>
---
 Documentation/labs/index.rst                       |   1 +
 Documentation/labs/kernel_modules.rst              | 961 +++++++++++++++++++++
 .../templates/kernel_modules/1-2-test-mod/Kbuild   |   3 +
 .../kernel_modules/1-2-test-mod/hello_mod.c        |  21 +
 .../templates/kernel_modules/3-error-mod/Kbuild    |   3 +
 .../templates/kernel_modules/3-error-mod/err_mod.c |  26 +
 .../templates/kernel_modules/4-multi-mod/Kbuild    |   5 +
 .../templates/kernel_modules/4-multi-mod/mod1.c    |  27 +
 .../templates/kernel_modules/4-multi-mod/mod2.c    |   4 +
 .../templates/kernel_modules/5-oops-mod/Kbuild     |   4 +
 .../templates/kernel_modules/5-oops-mod/oops_mod.c |  27 +
 .../labs/templates/kernel_modules/6-cmd-mod/Kbuild |   3 +
 .../templates/kernel_modules/6-cmd-mod/cmd_mod.c   |  26 +
 .../templates/kernel_modules/7-list-proc/Kbuild    |   3 +
 .../kernel_modules/7-list-proc/list_proc.c         |  35 +
 .../labs/templates/kernel_modules/8-kprobes/Kbuild |   3 +
 .../templates/kernel_modules/8-kprobes/kprobes.c   |  92 ++
 tools/labs/templates/kernel_modules/9-kdb/Kbuild   |   3 +
 .../templates/kernel_modules/9-kdb/hello_kdb.c     | 144 +++
 19 files changed, 1391 insertions(+)
 create mode 100644 Documentation/labs/kernel_modules.rst
 create mode 100644 tools/labs/templates/kernel_modules/1-2-test-mod/Kbuild
 create mode 100644 tools/labs/templates/kernel_modules/1-2-test-mod/hello_mod.c
 create mode 100644 tools/labs/templates/kernel_modules/3-error-mod/Kbuild
 create mode 100644 tools/labs/templates/kernel_modules/3-error-mod/err_mod.c
 create mode 100644 tools/labs/templates/kernel_modules/4-multi-mod/Kbuild
 create mode 100644 tools/labs/templates/kernel_modules/4-multi-mod/mod1.c
 create mode 100644 tools/labs/templates/kernel_modules/4-multi-mod/mod2.c
 create mode 100644 tools/labs/templates/kernel_modules/5-oops-mod/Kbuild
 create mode 100644 tools/labs/templates/kernel_modules/5-oops-mod/oops_mod.c
 create mode 100644 tools/labs/templates/kernel_modules/6-cmd-mod/Kbuild
 create mode 100644 tools/labs/templates/kernel_modules/6-cmd-mod/cmd_mod.c
 create mode 100644 tools/labs/templates/kernel_modules/7-list-proc/Kbuild
 create mode 100644 tools/labs/templates/kernel_modules/7-list-proc/list_proc.c
 create mode 100644 tools/labs/templates/kernel_modules/8-kprobes/Kbuild
 create mode 100644 tools/labs/templates/kernel_modules/8-kprobes/kprobes.c
 create mode 100644 tools/labs/templates/kernel_modules/9-kdb/Kbuild
 create mode 100644 tools/labs/templates/kernel_modules/9-kdb/hello_kdb.c

diff --git a/Documentation/labs/index.rst b/Documentation/labs/index.rst
index 9e61a8e..9af739f 100644
--- a/Documentation/labs/index.rst
+++ b/Documentation/labs/index.rst
@@ -31,3 +31,4 @@ then point your browser at 
**Documentation/output/labs/index.html**.
 
    vm.rst
    exercises.rst
+   kernel_modules.rst
diff --git a/Documentation/labs/kernel_modules.rst 
b/Documentation/labs/kernel_modules.rst
new file mode 100644
index 0000000..99ceb9a
--- /dev/null
+++ b/Documentation/labs/kernel_modules.rst
@@ -0,0 +1,961 @@
+==============
+Kernel modules
+==============
+
+Lab objectives
+==============
+
+* creating simple modules
+* describing the process of kernel module compilation
+* presenting how a module can be used with a kernel
+* simple kernel debugging methods
+
+Overview
+========
+
+A monolithic kernel, though faster than a microkernel, has the disadvantage of
+lack of modularity and extensibility. On modern monolithic kernels, this has
+been solved by using kernel modules. A kernel module (or loadable kernel mode)
+is an object file that contains code that can extend the kernel functionality
+at runtime (it is loaded as needed); When a kernel module is no longer needed,
+it can be unloaded. Most of the device drivers are used in the form of kernel
+modules.
+
+For the development of Linux device drivers, it is recommended to download the
+kernel sources, configure and compile them and then install the compiled 
version
+on the test / development tool machine.
+
+An example of kernel module
+===========================
+
+Below is a very simple example of kernel module. When loading into the kernel,
+it will generate the message "Hi". When unloading the kernel module, the "Bye"
+message will be generated.
+
+.. code-block:: c
+
+    #include <linux/kernel.h>
+    #include <linux/init.h>
+    #include <linux/module.h>
+     
+    MODULE_DESCRIPTION("My kernel module");
+    MODULE_AUTHOR("Me");
+    MODULE_LICENSE("GPL");
+     
+    static int dummy_init(void)
+    {
+            pr_debug("Hi\n");
+            return 0;
+    }
+     
+    static void dummy_exit(void)
+    {
+            pr_debug("Bye\n");
+    }
+     
+    module_init(dummy_init);
+    module_exit(dummy_exit);
+
+
+The generated messages will not be displayed on the console but will be saved
+in a specially reserved memory area for this, from where they will be extracted
+by the logging daemon (syslog). To display kernel messages, you can use the 
dmesg
+command or inspect the logs:
+
+.. code-block:: bash
+   
+   # cat /var/log/syslog | tail -2
+   Feb 20 13:57:38 asgard kernel: Hi
+   Feb 20 13:57:43 asgard kernel: Bye
+    
+   # dmesg | tail -2
+   Hi
+   Bye
+
+Compiling kernel modules
+========================
+
+Compiling a kernel module differs from compiling an user program. First, other
+headers should be used. Also, the module should not be linked to libraries.
+And, last but not least, the module must be compiled with the same options as
+the kernel in which we load the module. For these reasons, there is a standard
+compilation method (kbuild). This method requires the use of two files:
+a Makefile and a Kbuild file.
+
+Below is an example of a Makefile:
+
+.. code-block:: bash
+   
+   KDIR = /lib/modules/`uname -r`/build
+    
+   kbuild:
+           make -C $(KDIR) M=`pwd`
+    
+   clean:
+           make -C $(KDIR) M=`pwd` clean
+
+And the example of a Kbuild file used to compile a module:
+
+.. code-block:: bash
+   
+   EXTRA_CFLAGS = -Wall -g
+    
+   obj-m        = modul.o
+   
+
+As you can see, making the Makefile file in the example shown will result in 
+the make invocation in the kernel source directory (``/lib/modules/`uname 
-r`/build``)
+and referring to the current directory (``M = `pwd```). This process ultimately
+leads to reading the Kbuild file from the current directory  and compiling
+the module as instructed in this file.
+
+For labs we will configure different KDIR, according to the virtual machine
+specifications:
+
+.. code-block:: bash
+   
+   KDIR = /usr/src/linux-so2
+   [...]
+
+A Kbuild file contains one or more directives for compiling a kernel module.
+The easiest example of such a directive is ``obj-m = modul.o``. Following this
+directive, a kernel module (ko - kernel object) will be created,
+starting from the ``module.o`` file. ``module.o`` will be created starting from
+``module.c`` or ``module.S``. All of these files can be found in the Kbuild's
+directory.
+
+An example of a Kbuild file that uses several sub-modules is shown below:
+
+.. code-block:: bash
+   
+   EXTRA_CFLAGS = -Wall -g
+    
+   obj-m        = supermodul.o
+   supermodul-y = module-a.o module-b.o
+
+For the example above, the steps to compile are:
+   
+   * compile the module-a.c and module-b.c source, resulting in module-a.o and
+     module-b.o objects
+   * module-a.o and module-b.o will then be linked in supermodule.o
+   * from supermodul.o will create supermodul.ko module
+
+
+The suffix of targets in Kbuild determines how they are used, as follows:
+
+   * M (modules) is a target for loadable kernel modules
+   * Y (yes) represents a target for object files to be compiled and then 
linked
+     to a module (``$(mode_name)-y``) or within the kernel (``obj-y``)
+   * any other target suffix will be ignored by Kbuild and will not be compiled
+
+
+These suffixes are used to easily configure the kernel by running the ``make
+menuconfig`` command or directly editing the .config file. This file sets a
+series of variables that are used to determine which features are added to the
+kernel at build time. For example, when adding BTRFS support with
+``make menuconfig``, add the line CONFIG_BTRFS_FS = y to the .config file.
+The BTRFS kbuild contains the line ``obj-$(CONFIG_BTRFS_FS):= btrfs.o``, which
+becomes ``obj-y:= btrfs.o``. This will compile the btrfs.o object and will be
+linked to the kernel. Before the variable was set, the line became 
``obj:=btrfs.o``
+and so it was ignored, and the kernel was build-at without BTRFS support.
+
+For more details, see the ``makefiles.txt`` file and the ``modules.txt`` file 
within
+the kernel sources.
+
+Loading/unloading a kernel module
+=================================
+
+To load a kernel module, use the insmod utility. This utility receives as a
+parameter the path to the .ko file in which the module was compiled and linked.
+Unloading the module from the kernel is done using the rmmod command, which 
receives
+the module name as a parameter.
+
+.. code-block:: bash
+   
+   $ insmod module.ko
+   $ rmmod module.ko
+
+When loading the kernel module, the routine specified as a parameter of the
+``module_init`` macro will be executed. Similarly, when the module is unloaded
+the routine specified as a parameter of the ``module_exit`` will be executed.
+
+A complete example of compiling and loading/unloading mode is presented below:
+
+.. code-block:: bash
+   
+   faust:~/lab-01/modul-lin# ls
+   Kbuild  Makefile  modul.c
+    
+   faust:~/lab-01/modul-lin# make
+   make -C /lib/modules/`uname -r`/build M=`pwd`
+   make[1]: Entering directory `/usr/src/linux-2.6.28.4'
+     LD      /root/lab-01/modul-lin/built-in.o
+     CC [M]  /root/lab-01/modul-lin/modul.o
+     Building modules, stage 2.
+     MODPOST 1 modules
+     CC      /root/lab-01/modul-lin/modul.mod.o
+     LD [M]  /root/lab-01/modul-lin/modul.ko
+   make[1]: Leaving directory `/usr/src/linux-2.6.28.4'
+    
+   faust:~/lab-01/modul-lin# ls
+   built-in.o  Kbuild  Makefile  modul.c  Module.markers
+   modules.order  Module.symvers  modul.ko  modul.mod.c
+   modul.mod.o  modul.o
+    
+   faust:~/lab-01/modul-lin# insmod modul.ko
+    
+   faust:~/lab-01/modul-lin# dmesg | tail -1
+   Hi
+    
+   faust:~/lab-01/modul-lin# rmmod modul
+    
+   faust:~/lab-01/modul-lin# dmesg | tail -2
+   Hi
+   Bye
+
+Information about modules loaded into the kernel can be found using the lsmod
+command or by inspecting the ``/proc/modules``, ``/sys/module`` directories.
+
+Debugging
+=========
+
+Troubleshooting a kernel module is much more complicated than debugging a
+regular program. First, a mistake in a kernel module can lead to blocking the
+entire system. Troubleshooting is therefore much slowed down. To avoid reboot,
+it is recommended to use a virtual machine (qemu, virtualbox, vmware).
+
+When a module containing bugs is inserted into the kernel, it will eventually
+generate a `kernel oops <https://en.wikipedia.org/wiki/Linux_kernel_oops>`_.
+A kernel oops is an invalid operation detected by the kernel and can only
+be generated by the kernel. For a stable kernel version, it almost certainly 
+means that the module contains a bug. After the oops appears, the kernel will
+continue to work.
+
+Very important to the appearance of a kernel oops is saving the generated
+message. As noted above, messages generated by the kernel are saved in logs and
+can be displayed with the dmesg command. To make sure that no kernel message
+is lost, it is recommended to insert/test the kernel directly from the console,
+or periodically check the kernel messages. Noteworthy is that an oops can occur
+because of a programming error, but also a hardware error.
+
+If a fatal error occurs, after which the system can not return to a stable
+state, a panic kernel is generated.
+
+Look at the kernel module below that contains a bug to generate an oops:
+
+.. code-block:: c
+    
+    /*
+     * Oops generating kernel module
+     */
+     
+    #include <linux/kernel.h>
+    #include <linux/module.h>
+    #include <linux/init.h>
+     
+    MODULE_DESCRIPTION ("Oops");
+    MODULE_LICENSE ("GPL");
+    MODULE_AUTHOR ("PSO");
+     
+    #define OP_READ         0
+    #define OP_WRITE        1
+    #define OP_OOPS         OP_WRITE
+     
+    static int my_oops_init (void)
+    {
+            int *a;
+     
+            a = (int *) 0x00001234;
+    #if OP_OOPS == OP_WRITE
+            *a = 3;
+    #elif OP_OOPS == OP_READ
+            printk (KERN_ALERT "value = %d\n", *a);
+    #else
+    #error "Unknown op for oops!"
+    #endif
+     
+            return 0;
+    }
+     
+    static void my_oops_exit (void)
+    {
+    }
+     
+    module_init (my_oops_init);
+    module_exit (my_oops_exit);
+
+.. **
+
+Inserting this module into the kernel will generate an oops:
+
+.. code-block:: bash
+   
+   faust:~/lab-01/modul-oops# insmod oops.ko
+   [...]
+   
+   faust:~/lab-01/modul-oops# dmesg | tail -32
+   BUG: unable to handle kernel paging request at 00001234
+   IP: [<c89d4005>] my_oops_init+0x5/0x20 [oops]
+     *de = 00000000
+   Oops: 0002 [#1] PREEMPT DEBUG_PAGEALLOC
+   last sysfs file: /sys/devices/virtual/net/lo/operstate
+   Modules linked in: oops(+) netconsole ide_cd_mod pcnet32 crc32 cdrom [last 
unloaded: modul]
+   
+   Pid: 4157, comm: insmod Not tainted (2.6.28.4 #2) VMware Virtual Platform
+   EIP: 0060:[<c89d4005>] EFLAGS: 00010246 CPU: 0
+   EIP is at my_oops_init+0x5/0x20 [oops]
+   EAX: 00000000 EBX: fffffffc ECX: c89d4300 EDX: 00000001
+   ESI: c89d4000 EDI: 00000000 EBP: c5799e24 ESP: c5799e24
+    DS: 007b ES: 007b FS: 0000 GS: 0033 SS: 0068
+   Process insmod (pid: 4157, ti=c5799000 task=c665c780 task.ti=c5799000)
+   Stack:
+    c5799f8c c010102d c72b51d8 0000000c c5799e58 c01708e4 00000124 00000000
+    c89d4300 c5799e58 c724f448 00000001 c89d4300 c5799e60 c0170981 c5799f8c
+    c014b698 00000000 00000000 c5799f78 c5799f20 00000500 c665cb00 c89d4300
+   Call Trace:
+    [<c010102d>] ? _stext+0x2d/0x170
+    [<c01708e4>] ? __vunmap+0xa4/0xf0
+    [<c0170981>] ? vfree+0x21/0x30
+    [<c014b698>] ? load_module+0x19b8/0x1a40
+    [<c035e965>] ? __mutex_unlock_slowpath+0xd5/0x140
+    [<c0140da6>] ? trace_hardirqs_on_caller+0x106/0x150
+    [<c014b7aa>] ? sys_init_module+0x8a/0x1b0
+    [<c0140da6>] ? trace_hardirqs_on_caller+0x106/0x150
+    [<c0240a08>] ? trace_hardirqs_on_thunk+0xc/0x10
+    [<c0103407>] ? sysenter_do_call+0x12/0x43
+   Code: <c7> 05 34 12 00 00 03 00 00 00 5d c3 eb 0d 90 90 90 90 90 90 90 90
+   EIP: [<c89d4005>] my_oops_init+0x5/0x20 [oops] SS:ESP 0068:c5799e24
+   ---[ end trace 2981ce73ae801363 ]---
+
+Although relatively cryptic, the message provided by the kernel to the 
+appearance of an oops provides valuable information about the error. First 
line:
+
+.. code-block:: bash
+   
+   BUG: unable to handle kernel paging request at 00001234
+   EIP: [<c89d4005>] my_oops_init + 0x5 / 0x20 [oops]
+
+Tells us the cause and the address of the instruction that generated the error.
+In our case this is an invalid access to memory.
+
+Next line
+
+   ``Oops: 0002 [# 1] PREEMPT DEBUG_PAGEALLOC``
+
+Tells us that it's the first oops (#1). This is important in the context that
+an oops can lead to other oopses. Usually only the first oops is relevant.
+Furthermore, the oops code (0002) provides information about the error type
+(in memory manager -> fault.c ):
+
+   * Bit 0 == 0 means no page found, 1 means protection fault
+   * Bit 1 == 0 means read, 1 means write
+   * Bit 2 == 0 means kernel, 1 means user - mode 
+
+In this case, we have a write access that generated the oops (bit 1 is 1).
+
+Below is a dump of the registers. It decodes the instruction pointer (EIP)
+value and notes that the bug appeared in the my_oops_init function with a
+5-byte offset (``EIP: [<c89d4005>] my_oops_init+0x5``). The message also shows
+the stack content and a backtrace of calls until then.
+
+If an invalid read call is generated ( ``#define OP_OOPS OP_READ``), the 
message
+will be the same, but the oops code will differ, which would now be 0000 :
+
+.. code-block:: bash
+   
+   faust:~/lab-01/modul-oops# dmesg | tail -33
+   BUG: unable to handle kernel paging request at 00001234
+   IP: [<c89c3016>] my_oops_init+0x6/0x20 [oops]
+     *de = 00000000
+   Oops: 0000 [#1] PREEMPT DEBUG_PAGEALLOC
+   last sysfs file: /sys/devices/virtual/net/lo/operstate
+   Modules linked in: oops(+) netconsole pcnet32 crc32 ide_cd_mod cdrom
+   
+   Pid: 2754, comm: insmod Not tainted (2.6.28.4 #2) VMware Virtual Platform
+   EIP: 0060:[<c89c3016>] EFLAGS: 00010292 CPU: 0
+   EIP is at my_oops_init+0x6/0x20 [oops]
+   EAX: 00000000 EBX: fffffffc ECX: c89c3380 EDX: 00000001
+   ESI: c89c3010 EDI: 00000000 EBP: c57cbe24 ESP: c57cbe1c
+    DS: 007b ES: 007b FS: 0000 GS: 0033 SS: 0068
+   Process insmod (pid: 2754, ti=c57cb000 task=c66ec780 task.ti=c57cb000)
+   Stack:
+    c57cbe34 00000282 c57cbf8c c010102d c57b9280 0000000c c57cbe58 c01708e4
+    00000124 00000000 c89c3380 c57cbe58 c5db1d38 00000001 c89c3380 c57cbe60
+    c0170981 c57cbf8c c014b698 00000000 00000000 c57cbf78 c57cbf20 00000580
+   Call Trace:
+    [<c010102d>] ? _stext+0x2d/0x170
+    [<c01708e4>] ? __vunmap+0xa4/0xf0
+    [<c0170981>] ? vfree+0x21/0x30
+    [<c014b698>] ? load_module+0x19b8/0x1a40
+    [<c035d083>] ? printk+0x0/0x1a
+    [<c035e965>] ? __mutex_unlock_slowpath+0xd5/0x140
+    [<c0140da6>] ? trace_hardirqs_on_caller+0x106/0x150
+    [<c014b7aa>] ? sys_init_module+0x8a/0x1b0
+    [<c0140da6>] ? trace_hardirqs_on_caller+0x106/0x150
+    [<c0240a08>] ? trace_hardirqs_on_thunk+0xc/0x10
+    [<c0103407>] ? sysenter_do_call+0x12/0x43
+   Code: <a1> 34 12 00 00 c7 04 24 54 30 9c c8 89 44 24 04 e8 58 a0 99 f7 31
+   EIP: [<c89c3016>] my_oops_init+0x6/0x20 [oops] SS:ESP 0068:c57cbe1c
+   ---[ end trace 45eeb3d6ea8ff1ed ]---
+
+objdump
+-------
+
+Detailed information about the instruction that generated the oops can be found
+using the objdump utility. Useful options to use are ``-d`` to disassemble the
+code and ``-S`` for interleaving code C in assembly language code.
+For efficient decoding, however, we need the address where the kernel module 
was
+loaded. This can be found in /proc/modules.
+
+Here's an example of using objdump on the above module to identify the 
instruction
+that generated the oops:
+
+.. code-block:: bash
+   
+   faust:~/lab-01/modul-oops# cat /proc/modules
+   oops 1280 1 - Loading 0xc89d4000
+   netconsole 8352 0 - Live 0xc89ad000
+   pcnet32 33412 0 - Live 0xc895a000
+   ide_cd_mod 34952 0 - Live 0xc8903000
+   crc32 4224 1 pcnet32, Live 0xc888a000
+   cdrom 34848 1 ide_cd_mod, Live 0xc886d000
+   
+   faust:~/lab-01/modul-oops# objdump -dS --adjust-vma=0xc89d4000 oops.ko
+   
+   oops.ko:     file format elf32-i386
+   
+   
+   Disassembly of section .text:
+   
+   c89d4000 <init_module>:
+   #define OP_READ         0
+   #define OP_WRITE        1
+   #define OP_OOPS         OP_WRITE
+   
+   static int my_oops_init (void)
+   {                             
+   c89d4000:       55                      push   %ebp
+   #else                                              
+   #error "Unknown op for oops!"                      
+   #endif
+   
+           return 0;
+   }
+   c89d4001:       31 c0                   xor    %eax,%eax
+   #define OP_READ         0
+   #define OP_WRITE        1
+   #define OP_OOPS         OP_WRITE
+   
+   static int my_oops_init (void)
+   {
+   c89d4003:       89 e5                   mov    %esp,%ebp
+           int *a;
+   
+           a = (int *) 0x00001234;
+   #if OP_OOPS == OP_WRITE
+           *a = 3;
+   c89d4005:       c7 05 34 12 00 00 03    movl   $0x3,0x1234
+   c89d400c:       00 00 00
+   #else
+   #error "Unknown op for oops!"
+   #endif
+   
+           return 0;
+   }
+   c89d400f:       5d                      pop    %ebp
+   c89d4010:       c3                      ret
+   c89d4011:       eb 0d                   jmp    c89c3020 <cleanup_module>
+   c89d4013:       90                      nop
+   c89d4014:       90                      nop
+   c89d4015:       90                      nop
+   c89d4016:       90                      nop
+   c89d4017:       90                      nop
+   c89d4018:       90                      nop
+   c89d4019:       90                      nop
+   c89d401a:       90                      nop
+   c89d401b:       90                      nop
+   c89d401c:       90                      nop
+   c89d401d:       90                      nop
+   c89d401e:       90                      nop
+   c89d401f:       90                      nop
+   
+   c89d4020 <cleanup_module>:
+   
+   static void my_oops_exit (void)
+   {
+   c89d4020:       55                      push   %ebp
+   c89d4021:       89 e5                   mov    %esp,%ebp
+   }
+   c89d4023:       5d                      pop    %ebp
+   c89d4024:       c3                      ret
+   c89d4025:       90                      nop
+   c89d4026:       90                      nop
+   c89d4027:       90                      nop
+
+Note that the instruction that generated the oops (``c89d4005`` identified
+earlier) is:
+
+  ``C89d4005: c7 05 34 12 00 00 03 movl $ 0x3,0x1234``
+
+That is exactly what was expected - storing value 3 at 0x0001234.
+
+The /proc/modules is used to find the address where a kernel module is loaded.
+The --adjust-vma option allows you to display instructions relative to
+``0xc89d4000``. The ``-l`` option displays the number of each line in the 
source code
+interleaved with the assembly language code.
+
+addr2line
+---------
+
+A more simplistic way to find the code that generated an oops is to use the
+addr2line utility:
+
+.. code-block:: bash
+
+   faust:~/lab-01/modul-oops# addr2line -e oops.o 0x5
+   /root/lab-01/modul-oops/oops.c:23
+
+Where ``0x5`` is the value of the program counter (``EIP = c89d4005``) that 
generated the
+oops, minus the base address of the module (``0xc89c4000``) according to 
``/proc/modules``
+
+minicom
+-------
+
+Minicom (or other equivalent utilities, eg ``picocom``, ``screen``) is a 
utility that
+can be used to connect and interact with a serial port. The serial port is the
+basic method for analyzing kernel messages or interacting with an embedded
+system in the development phase. There are two more common ways to connect:
+
+* a serial serial port where the device we are going to use is ``/dev/ttyS0``
+* a serial USB port (FDTI) in which case the device we are going to use is 
``/dev/ttyUSB``.
+
+For the virtual machine used in the lab, the device that we need to use is 
+displayed after the virtual machine starts:
+
+``char device redirected to /dev/pts/20 (label virtiocon0)``
+
+Minicom use:
+
+.. code-block:: bash
+   
+   #for connecting via COM1 and using a speed of 115,200 characters per second
+   minicom -b 115200 -D /dev/ttyS0
+   
+   #For USB serial port connection
+   minicom -D /dev/ttyUSB0
+   
+   #To connect to the serial port of the virtual machine
+   minicom -D /dev/pts/20
+
+netconsole
+----------
+
+Netconsole is a utility that allows logging of kernel debugging messages over
+the network. This is useful when the disk logging system does not work when
+serial ports are not available or when the terminal does not respond to
+commands. Netconsole comes in the form of a kernel module.
+
+To work, it needs the following parameters:
+
+   * port, IP address, and the source interface name of the debug station
+   * port, MAC address, and IP address of the machine to which the debug
+     messages will be sent 
+
+These parameters can be configured when the module is inserted into the kernel,
+or even while the module is inserted if it has been compiled with the
+CONFIG_NETCONSOLE_DYNAMIC option.
+
+An example configuration when inserting is as follows:
+
+.. code-block:: bash
+   
+   alice:~# modprobe netconsole 
netconsole=6666@192.168.191.130/eth0,6000@192.168.191.1/00:50:56:c0:00:08
+
+Thus, the debug messages on the station that has the address 192.168.191.130
+will be sent to the eth0 interface, having source port 6666. The messages will
+be sent to 192.168.191.1 with the MAC address 00: 50: 56: c0: 00: 08, on port
+6000.
+
+Messages can be played on the destination station using netcat :
+
+.. code-block:: bash
+
+   bob:~ # nc -l -p 6000 -u
+
+Alternatively, the destination station can configure syslogd to intercept these
+messages. More information can be found here .
+
+Printk debugging
+----------------
+
+``The two oldest and most useful debugging aids are Your brain and Printf``
+
+For debugging, a primitive way is often used, but it is quite effective: printk
+debugging. Although a debugger can also be used, it is generally not very
+useful: simple bugs (uninitialized variables, memory management problems, etc.)
+can be easily localized by control messages and the kernel-decoded oop message.
+
+For more complex bugs, even a debugger can not help us too much unless the
+operating system structure is very well understood. When debugging a kernel
+module, there are a lot of unknowns in the equation: multiple contexts (we have
+multiple processes and threads running at a time), interruptions, virtual
+memory, etc.
+
+You can use printk to display kernel messages to user space. It is similar to
+printf's functionality; The only difference is that the transmitted message
+can be prefixed with a string of "<n>", where n indicates the error level
+(loglevel) and has values between 0 and 7. Instead of "<n>", the levels
+
+Can also be coded by symbolic constants:
+
+.. code-block:: c
+
+    KERN_EMERG - n = 0
+    KERN_ALERT - n = 1
+    KERN_CRIT - n = 2
+    KERN_ERR - n = 3
+    KERN_WARNING - n = 4
+    KERN_NOTICE - n = 5
+    KERN_INFO - n = 6
+    KERN_DEBUG - n = 7 
+
+
+The definitions of all log levels are found in linux/kern_levels.h.
+Basically, these log levels are used by the system to route messages sent to
+various outputs: console, log files in /var/log etc.
+
+To display printk messages in user space, the printk log level must be of
+higher priority then ``console_loglevel`` variable. That is, the logging level 
is
+less strict than the console_loglevel variable. For example, if the 
+``console_loglevel`` has a value of 5 (specific to KERN_NOTICE), only messages
+with loglevel stricter than 5 (i.e KERN_EMERG, KERN_ALERT, KERN_CRIT,
+KERN_ERR, KERN_WARNING) will be shown.
+
+Console-redirected messages can be useful for quickly viewing the effect of
+executing the kernel code, but they are no longer so useful if the kernel
+encounters an irreparable error and the system freezes. In this case, the logs
+of the system must be consulted, as they keep the information between system
+restarts. These are found in ``/var/log``  and are text files, populated with
+syslogd and klogd during the kernel run. syslogd and klogd take the information
+from the virtual file system mounted in /proc. In principle, with syslogd and
+klogd turned on, all messages coming from the kernel will go to 
/var/log/kern.log.
+
+A simpler version for debugging is using the /var/log/debug file. It is 
populated
+only with the printk messages from the kernel with the KERN_DEBUG log level.
+
+Given that a production kernel (similar to the one we're probably running with)
+contains only release code, our module is among the few that send messages
+prefixed with KERN_DEBUG . In this way, we can easily navigate through the
+/var/log/debug information by finding the messages corresponding to a debugging
+session for our module.
+
+An example of use would be the following:
+
+.. code-block:: bash
+
+    # Clear the debug file of previous information (or possibly a backup)
+    $ echo "New debug session" > /var/log/debug
+    # Run the tests
+    # If there is no critical error causing a panic kernel, check the output
+    # if a critical error occurs and the machine only responds to a restart, 
+      restart the system and check /var/log/debug.
+
+The format of the messages must obviously contain all the information of 
+interest in order to detect the error, but inserting in the code "printk" to 
+provide detailed information can be as time-consuming as writing the code to 
+solve the problem. This is usually a trade-off between the completeness of the 
+debugging messages displayed using printk and the time it takes to insert 
these 
+messages into the text.
+
+A very simple way, less time-consuming for inserting printk and providing
+the possibility to analyze the flow of instructions for tests is 
+the use of the predefined constants __LINE__ , __LINE__ and __func__ :
+
+    * ``__FILE__`` is replaced by the compiler with the name of the source 
file it is
+      currently in the compilation.
+    * ``__LINE__`` is replaced by the compiler with the line number on which 
the
+      current instruction is found in the current source file.
+    * ``__func__`` /``__FUNCTION__`` is replaced by the compiler with the name 
of the
+      function in which the current instruction is found.
+
+Note : ``__LINE__`` and ``__LINE__`` are part of ANSI C specification 
specifications:
+``__func__`` is part of specification C99; ``__FUNCTION__`` is a GNU C
+extension and is not portable; However, since we write code for the Linux 
kernel,
+we can use it without any problems.
+
+The following macrodefinition can be used in this case:
+
+.. code-block:: c
+   
+   #define PRINT_DEBUG \ 
+          printk (KERN_DEBUG "[% s]: FUNC:% s: LINE:% d \ n", __FILE__,
+                  __FUNCTION__, __LINE__) 
+
+Then, at each point where we want to see if it is "reached" in execution,
+insert PRINT_DEBUG; This is a simple and quick way, and can yield by carefully 
+analyzing the output.
+
+The dmesg command is used to view the messages printed with printk but not
+appearing on the console.
+
+To delete all previous messages from a log file, run cat /dev/null > 
+/var/log/debug. To delete messages displayed by the dmesg command, dmesg -c.
+
+
+Dynamic debugging
+-----------------
+
+Dynamic ``dyndbg`` debugging enables dynamic debugging activation/deactivation.
+Unlike printk, it offers more advanced printk options for the messages we want
+to display - very useful for complex modules or troubleshooting subsystems.
+This significantly reduces the amount of messages displayed, leaving only
+those relevant for the debug context. To enable dyndbg, the kernel must be
+compiled with the CONFIG_DYNAMIC_DEBUG option. Once configured, pr_debug(),
+dev_dbg() and print_hex_dump_debug(), print_hex_dump_bytes() can be dynamically
+enabled per call.
+
+The ``/sys/kernel/debug/dynamic_debug/control`` file from the debugfs file 
debugfs
+(where /sys/kernel/debug is the path to which debugfs were mounted) is used to
+filter messages or view existing filters.
+
+.. code-block:: c
+
+   mount -t debugfs none /debug
+
+Debugfs is a simple file system, used as a kernel-space interface and
+user-space interface to configure different debug options. Any debug utility 
+can create and use its own files / folders in debugfs.
+
+For example, to display existing filters in dyndbg, you will use:
+
+.. code-block:: bash
+   
+   cat /debug/dynamic_debug/control
+
+And to enable the debug message from line 1603 in the svcsock.c file:
+
+.. code-block:: bash
+
+   echo 'file svcsock.c line 1603 +p' > /debug/dynamic_debug/control
+
+The /debug/dynamic_debug/control file is not a regular file. Its display shows
+the dyndbg settings on the filters. Writing in it with an echo will change
+these settings (it will not actually make a write). Be aware that the file
+contains settings for dyndbg debugging messages. Do not log in this file.
+
+Dyndbg Options
+~~~~~~~~~~~~~~
+
+* ``func`` - just the debug messages from the functions that have the same
+  name as the one defined in the filter.
+
+  .. code-block:: bash
+
+      echo 'func svc_tcp_accept +p' > /debug/dynamic_debug/control
+
+* ``file`` - the name of the file(s) for which we want to display the debug
+  messages. It can be just the source name, but also the absolute path or 
+  kernel-tree path. 
+
+  .. code-block:: bash
+
+    file svcsock.c
+    file kernel/freezer.c
+    file 
/usr/src/packages/BUILD/sgi-enhancednfs-1.4/default/net/sunrpc/svcsock.c
+
+* ``module`` - module name.
+
+  .. code-block:: bash
+
+     Modules sunrpc 
+
+* ``format`` - only messages whose display format contains the specified 
string. 
+
+   .. code-block:: bash
+
+      format "nfsd: SETATTR" 
+
+* line - the line or lines for which we want to enable debug calls.
+
+  .. code-block:: bash
+
+     # Triggers debug messages between lines 1603 and 1605 in the svcsock.c 
file
+     $ echo 'file svcsock.c line 1603-1605 +p' > 
/sys/kernel/debug/dynamic_debug/control
+     # Enables debug messages from the beginning of the file to line 1605
+     $ echo 'file svcsock.c line -1605 +p' > 
/sys/kernel/debug/dynamic_debug/control
+
+In addition to the above options, a series of flags can be specified that can
+be added, removed, or set with operators +, - or = :
+
+   * ``p`` activates the pr_debug() .
+   * ``f`` includes the name of the function in the printed message.
+   * ``I`` includes the line number in the printed message.
+   * ``M`` includes the module name in the printed message.
+   * ``T`` includes the thread id if it is not called from interrupt context
+   * ``_`` no flag is set. 
+
+Exercises
+=========
+
+.. important::
+
+   .. include:: exercises-summary.hrst
+   
+   .. |LAB_NAME| replace:: kernel_modules
+   
+
+0. Intro
+--------
+
+Using |LXR|_ find the definitions of the following symbols in the Linux kernel:
+
+* :c:func:`module_init` and :c:func:`module_exit`
+
+  - what does the two macros do? What is ``init_module`` and 
``cleanup_module``?
+* :c:data:`ignore_loglevel`
+
+  - What is this variable used for?
+
+1. Module
+---------
+
+Generate the skeleton for the task named **1-2-test-mod** then build and
+copy the module to the VM. Perform the following tasks:
+
+* load the kernel module.
+  
+* list the kernel modules and check if current module is present
+    
+* unload the kernel module
+    
+* view the messages displayed at loading/unloading the kernel module using
+  ``dmesg`` command
+
+.. note:: Read `Loading/unloading a kernel module`_ section. When unloading
+          a kernel module, only the module name (without extension) can
+          be specified.
+
+2. Printk
+---------
+
+Watch the virtual machine console. Why were the messages not displayed directly
+to the virtual machine console?
+
+Inspect the source code file. Change the source code file so that messages are
+displayed directly on the serial console.
+
+.. hint:: Read the `Printk debugging`_ section of the lab and change
+          the log level of the prints in the module source.
+
+.. hint:: Another option is to set the current log level by writting
+          the desired log level to ``/proc/sys/kernel/printk``
+
+.. hint:: An alternative approach is to edit the boot options in
+          ``tools/labs/qemu/Makefile``. Add ``ignore_loglevel`` option
+         to the qemu ``--append`` option.
+
+3. Error
+--------
+
+Generate the skeleton for the task named **3-error-mod**. Compile the
+sources and get the corresponding kernel module. Why have compilation
+errors occurred?
+
+.. hint:: How does this module differ from the previous module?
+
+Modify the module to solve the cause of those errors.
+
+4. Sub-modules
+--------------
+
+Generate the skeleton for the task named **4-multi-mod**. Inspect the
+C source files: ``mod1.c`` and ``mod2.c``. Module 2 contains only the
+definition of a function used by module 1.
+
+Create a Kbuild file that will lead to creating the ``multi_mod.ko``
+from the two source files.
+
+.. hint:: Read the `Compiling kernel modules`_ section of the lab.
+
+Compile, copy, load and unload the kernel module. Make sure messages
+are properly displayed on the console.
+
+5. Kernel oops
+--------------
+
+Generate the skeleton for the task named **5-oops-mod** and inspect the
+C source file. Notice where the problem will occur. Add -g to
+compilation in the Kbuild file.
+
+.. hint:: Read `Compiling kernel modules`_  section of the lab.
+
+Compile the associated module and load it into the kernel. Identify the memory
+address at which the oops appeared.
+
+.. hint:: Read `Debugging`_ section of the lab.  To identify the
+          address, follow the oops message and extract the value of
+          the instructions pointer (EIP) register.
+
+Determine which instruction has triggered the oops.
+
+.. hint:: Use the /proc/modules information to get the load address of
+          the kernel module.  Use, on the physical machine, objdump
+          and/or addr2line . Objdump needs debugging support for
+          compilation!  Read the lab's `objdump`_ and `addr2line`_
+          sections.
+
+Try to unload the kernel module. Notice that the operation does not
+work because there are references from the kernel module within the
+kernel since the oops; Until the release of those references (which is
+almost impossible in the case of an oops), the module can not be
+unloaded.
+
+6. Module parameters
+--------------------
+
+Generate the skeletons for **6-cmd-mod** and inspect the C
+``cmd_mod.c`` source file. Compile and copy the associated module and
+load the kernel module to see the printk message. Then unload the
+module from the kernel.
+
+Without modifying the sources, load the kernel module so that the
+message shown is ``Early bird gets tired``.
+
+.. hint:: The str variable can be changed by passing a parameter to
+          the module. Find more information `here
+          <http://tldp.org/LDP/lkmpg/2.6/html/x323.html>`_.
+
+.. _proc-info:
+
+7. Proc info
+------------
+
+Generate the skeleton for the task named **7-list-proc**. Add code to
+display the Process ID (``PID``) and the executable name. The
+information will be displayed both when loading and unloading the
+module.
+
+.. note::
+          * In the Linux kernel, a process is described by the
+           :c:type:`struct task_struct`.  Use |LXR|_ to find the
+           definition of ``struct task_struct``.
+         
+          * To find the structure field that contains the name of the
+           executable, look for the "executable" comment.
+
+          * The pointer to the structure of the current process
+           running at a given time in the kernel is given by the
+           :c:macro:`current` variable (of the type ``struct task_struct
+           *``).
+
+.. hint:: To use c:macro:`current` you'll need to include the header
+          in which the ``struct task_struct`` is defined, i.e
+          ``linux/sched.h``.
+
+Compile copy and load the module. Unload the kernel module.
+
+Repeat the loading/unloading operation. Note that the PIDs of the
+displayed processes differ. This is because a module is being loaded
+from the executable ``/sbin/insmod`` when the module is loaded and
+when the module is unloaded a process is created from the executable
+``/sbin/rmmod``.
diff --git a/tools/labs/templates/kernel_modules/1-2-test-mod/Kbuild 
b/tools/labs/templates/kernel_modules/1-2-test-mod/Kbuild
new file mode 100644
index 0000000..8aa44e4
--- /dev/null
+++ b/tools/labs/templates/kernel_modules/1-2-test-mod/Kbuild
@@ -0,0 +1,3 @@
+ccflags-y = -Wno-unused-function -Wno-unused-label -Wno-unused-variable
+
+obj-m = hello_mod.o
diff --git a/tools/labs/templates/kernel_modules/1-2-test-mod/hello_mod.c 
b/tools/labs/templates/kernel_modules/1-2-test-mod/hello_mod.c
new file mode 100644
index 0000000..0ed6520
--- /dev/null
+++ b/tools/labs/templates/kernel_modules/1-2-test-mod/hello_mod.c
@@ -0,0 +1,21 @@
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+
+MODULE_DESCRIPTION("Simple module");
+MODULE_AUTHOR("Kernel Hacker");
+MODULE_LICENSE("GPL");
+
+static int my_hello_init(void)
+{
+       pr_debug("Hello!\n");
+       return 0;
+}
+
+static void hello_exit(void)
+{
+       pr_debug("Goodbye!\n");
+}
+
+module_init(my_hello_init);
+module_exit(hello_exit);
diff --git a/tools/labs/templates/kernel_modules/3-error-mod/Kbuild 
b/tools/labs/templates/kernel_modules/3-error-mod/Kbuild
new file mode 100644
index 0000000..7bf41fb
--- /dev/null
+++ b/tools/labs/templates/kernel_modules/3-error-mod/Kbuild
@@ -0,0 +1,3 @@
+ccflags-y = -Wno-unused-function -Wno-unused-label -Wno-unused-variable
+
+obj-m = err_mod.o
diff --git a/tools/labs/templates/kernel_modules/3-error-mod/err_mod.c 
b/tools/labs/templates/kernel_modules/3-error-mod/err_mod.c
new file mode 100644
index 0000000..0570366
--- /dev/null
+++ b/tools/labs/templates/kernel_modules/3-error-mod/err_mod.c
@@ -0,0 +1,26 @@
+#include <linux/init.h>
+#include <linux/kernel.h>
+/* TODO: add missing kernel headers */
+#include <linux/module.h>
+
+MODULE_DESCRIPTION("Error module");
+MODULE_AUTHOR("Kernel Hacker");
+MODULE_LICENSE("GPL");
+
+static int n1, n2;
+
+static int err_init(void)
+{
+       n1 = 1; n2 = 2;
+       pr_info("n1 is %d, n2 is %d\n", n1, n2);
+
+       return 0;
+}
+
+static void err_exit(void)
+{
+       pr_info("sum is %d\n", n1 + n2);
+}
+
+module_init(err_init);
+module_exit(err_exit);
diff --git a/tools/labs/templates/kernel_modules/4-multi-mod/Kbuild 
b/tools/labs/templates/kernel_modules/4-multi-mod/Kbuild
new file mode 100644
index 0000000..1d211ca
--- /dev/null
+++ b/tools/labs/templates/kernel_modules/4-multi-mod/Kbuild
@@ -0,0 +1,5 @@
+ccflags-y = -Wno-unused-function -Wno-unused-label -Wno-unused-variable
+
+# TODO/2: add rules to create a multi object module
+obj-m   = multi-mod.o
+multi-mod-y =  mod1.o mod2.o
diff --git a/tools/labs/templates/kernel_modules/4-multi-mod/mod1.c 
b/tools/labs/templates/kernel_modules/4-multi-mod/mod1.c
new file mode 100644
index 0000000..9655f54
--- /dev/null
+++ b/tools/labs/templates/kernel_modules/4-multi-mod/mod1.c
@@ -0,0 +1,27 @@
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+
+MODULE_DESCRIPTION("Multi-file module");
+MODULE_AUTHOR("Kernel Hacker");
+MODULE_LICENSE("GPL");
+
+extern int add(int a, int b);
+
+static int n1, n2;
+
+static int my_hello_init(void)
+{
+       n1 = 1; n2 = 2;
+       pr_info("n1 is %d, n2 is %d\n", n1, n2);
+
+       return 0;
+}
+
+static void hello_exit(void)
+{
+       pr_info("sum id %d\n", add(n1, n2));
+}
+
+module_init(my_hello_init);
+module_exit(hello_exit);
diff --git a/tools/labs/templates/kernel_modules/4-multi-mod/mod2.c 
b/tools/labs/templates/kernel_modules/4-multi-mod/mod2.c
new file mode 100644
index 0000000..7c923bb
--- /dev/null
+++ b/tools/labs/templates/kernel_modules/4-multi-mod/mod2.c
@@ -0,0 +1,4 @@
+int add(int a, int b)
+{
+       return a + b;
+}
diff --git a/tools/labs/templates/kernel_modules/5-oops-mod/Kbuild 
b/tools/labs/templates/kernel_modules/5-oops-mod/Kbuild
new file mode 100644
index 0000000..09e3be5
--- /dev/null
+++ b/tools/labs/templates/kernel_modules/5-oops-mod/Kbuild
@@ -0,0 +1,4 @@
+# TODO: add flags to generate debug information
+ccflags-y = -Wno-unused-function -Wno-unused-label -Wno-unused-variable
+
+obj-m = oops_mod.o
diff --git a/tools/labs/templates/kernel_modules/5-oops-mod/oops_mod.c 
b/tools/labs/templates/kernel_modules/5-oops-mod/oops_mod.c
new file mode 100644
index 0000000..9fd1448
--- /dev/null
+++ b/tools/labs/templates/kernel_modules/5-oops-mod/oops_mod.c
@@ -0,0 +1,27 @@
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+
+MODULE_DESCRIPTION("Oops generating module");
+MODULE_AUTHOR("So2rul Esforever");
+MODULE_LICENSE("GPL");
+
+static int my_oops_init(void)
+{
+       char *p = 0;
+
+       pr_info("before init\n");
+       *p = 'a';
+       pr_info("after init\n");
+
+       return 0;
+}
+
+static void my_oops_exit(void)
+{
+       pr_info("module goes all out\n");
+}
+
+module_init(my_oops_init);
+module_exit(my_oops_exit);
diff --git a/tools/labs/templates/kernel_modules/6-cmd-mod/Kbuild 
b/tools/labs/templates/kernel_modules/6-cmd-mod/Kbuild
new file mode 100644
index 0000000..2c5fe9c
--- /dev/null
+++ b/tools/labs/templates/kernel_modules/6-cmd-mod/Kbuild
@@ -0,0 +1,3 @@
+ccflags-y = -Wno-unused-function -Wno-unused-label -Wno-unused-variable
+
+obj-m = cmd_mod.o
diff --git a/tools/labs/templates/kernel_modules/6-cmd-mod/cmd_mod.c 
b/tools/labs/templates/kernel_modules/6-cmd-mod/cmd_mod.c
new file mode 100644
index 0000000..3bd7588
--- /dev/null
+++ b/tools/labs/templates/kernel_modules/6-cmd-mod/cmd_mod.c
@@ -0,0 +1,26 @@
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+
+MODULE_DESCRIPTION("Command-line args module");
+MODULE_AUTHOR("Kernel Hacker");
+MODULE_LICENSE("GPL");
+
+static char *str = "the worm";
+
+module_param(str, charp, 0000);
+MODULE_PARM_DESC(str, "A simple string");
+
+static int __init cmd_init(void)
+{
+       pr_info("Early bird gets %s\n", str);
+       return 0;
+}
+
+static void __exit cmd_exit(void)
+{
+       pr_info("Exit, stage left\n");
+}
+
+module_init(cmd_init);
+module_exit(cmd_exit);
diff --git a/tools/labs/templates/kernel_modules/7-list-proc/Kbuild 
b/tools/labs/templates/kernel_modules/7-list-proc/Kbuild
new file mode 100644
index 0000000..45eb767
--- /dev/null
+++ b/tools/labs/templates/kernel_modules/7-list-proc/Kbuild
@@ -0,0 +1,3 @@
+ccflags-y = -Wno-unused-function -Wno-unused-label -Wno-unused-variable
+
+obj-m = list_proc.o
diff --git a/tools/labs/templates/kernel_modules/7-list-proc/list_proc.c 
b/tools/labs/templates/kernel_modules/7-list-proc/list_proc.c
new file mode 100644
index 0000000..96a659b
--- /dev/null
+++ b/tools/labs/templates/kernel_modules/7-list-proc/list_proc.c
@@ -0,0 +1,35 @@
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+/* TODO: add missing headers */
+#include <linux/sched/signal.h>
+
+MODULE_DESCRIPTION("List current processes");
+MODULE_AUTHOR("Kernel Hacker");
+MODULE_LICENSE("GPL");
+
+static int my_proc_init(void)
+{
+       struct task_struct *p;
+
+       /* TODO/2: print current process pid and its name */
+       pr_info("Current process: pid = %d; comm = %s\n",
+               current->pid, current->comm);
+
+       /* TODO/3: print the pid and name of all processes */
+       pr_info("\nProcess list:\n\n");
+       for_each_process(p)
+               pr_info("pid = %d; comm = %s\n", p->pid, p->comm);
+
+       return 0;
+}
+
+static void my_proc_exit(void)
+{
+       /* TODO/2: print current process pid and name */
+       pr_info("Current process: pid = %d; comm = %s\n",
+               current->pid, current->comm);
+}
+
+module_init(my_proc_init);
+module_exit(my_proc_exit);
diff --git a/tools/labs/templates/kernel_modules/8-kprobes/Kbuild 
b/tools/labs/templates/kernel_modules/8-kprobes/Kbuild
new file mode 100644
index 0000000..3681cb8
--- /dev/null
+++ b/tools/labs/templates/kernel_modules/8-kprobes/Kbuild
@@ -0,0 +1,3 @@
+ccflags-y = -Wno-unused-function -Wno-unused-label -Wno-unused-variable
+
+obj-m = kprobes.o
diff --git a/tools/labs/templates/kernel_modules/8-kprobes/kprobes.c 
b/tools/labs/templates/kernel_modules/8-kprobes/kprobes.c
new file mode 100644
index 0000000..21551c5
--- /dev/null
+++ b/tools/labs/templates/kernel_modules/8-kprobes/kprobes.c
@@ -0,0 +1,92 @@
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/kprobes.h>
+#include <linux/kallsyms.h>
+
+MODULE_DESCRIPTION("Probes module");
+MODULE_AUTHOR("Kernel Hacker");
+MODULE_LICENSE("GPL");
+
+/*
+ * Pre-entry point for do_execveat_common.
+ */
+static int my_do_execveat_common(int fd, struct filename * filename,
+                                char __user *__user *argv,
+                                char __user *__user *envp,
+                                int flags)
+{
+       pr_info("do_execveat_common for %s %s(%d) \n",
+               filename->name, current->comm, current->pid);
+       /* Always end with a call to jprobe_return(). */
+       jprobe_return();
+       /*NOTREACHED*/
+       return 0;
+}
+
+static struct jprobe my_jprobe = {
+       .entry = (kprobe_opcode_t *) my_do_execveat_common
+};
+
+static int my_ret_handler(struct kretprobe_instance *ri, struct pt_regs *regs)
+{
+       /* TODO/3: print return value, parent process PID and process PID. */
+       unsigned long ret_value = regs_return_value(regs);
+       pr_info("fork for process (PID: %d, PPID: %d) returned with value 
%ld\n",
+               current->pid, current->parent->pid, ret_value);
+       return 0;
+}
+
+static struct kretprobe my_kretprobe = {
+       .handler = my_ret_handler,
+};
+
+static int my_probe_init(void)
+{
+       int ret;
+
+       my_jprobe.kp.addr =
+               (kprobe_opcode_t *) kallsyms_lookup_name("do_execveat_common");
+       if (my_jprobe.kp.addr == NULL) {
+               pr_info("Couldn't find %s to plant jprobe\n", 
"do_execveat_common");
+               return -1;
+       }
+
+       ret = register_jprobe(&my_jprobe);
+       if (ret < 0) {
+               pr_info("register_jprobe failed, returned %d\n", ret);
+               return -1;
+       }
+       pr_info("Planted jprobe at %p, handler addr %p\n", my_jprobe.kp.addr,
+               my_jprobe.entry);
+
+       /* TODO/14: Find address of do_fork and register kretprobe. */
+       my_kretprobe.kp.addr =
+               (kprobe_opcode_t *) kallsyms_lookup_name("_do_fork");
+       if (my_kretprobe.kp.addr == NULL) {
+               pr_info("Couldn't find %s to plant jprobe\n", "do_fork");
+               return -1;
+       }
+
+       ret = register_kretprobe(&my_kretprobe);
+       if (ret < 0) {
+               pr_info("register_kretprobe failed, returned %d\n", ret);
+               return -1;
+       }
+       pr_info("Planted kretprobe at %p, handler addr %p\n",
+               my_kretprobe.kp.addr, my_kretprobe.handler);
+
+       return 0;
+}
+
+static void my_probe_exit(void)
+{
+       unregister_jprobe(&my_jprobe);
+       pr_info("jprobe unregistered\n");
+       /* TODO/2: Uregister kretprobe. */
+       unregister_kretprobe(&my_kretprobe);
+       pr_info("kretprobe unregistered\n");
+}
+
+module_init(my_probe_init);
+module_exit(my_probe_exit);
diff --git a/tools/labs/templates/kernel_modules/9-kdb/Kbuild 
b/tools/labs/templates/kernel_modules/9-kdb/Kbuild
new file mode 100644
index 0000000..4453b28
--- /dev/null
+++ b/tools/labs/templates/kernel_modules/9-kdb/Kbuild
@@ -0,0 +1,3 @@
+ccflags-y = -Wno-unused-function -Wno-unused-label -Wno-unused-variable
+
+obj-m        = hello_kdb.o
diff --git a/tools/labs/templates/kernel_modules/9-kdb/hello_kdb.c 
b/tools/labs/templates/kernel_modules/9-kdb/hello_kdb.c
new file mode 100644
index 0000000..9e730cad
--- /dev/null
+++ b/tools/labs/templates/kernel_modules/9-kdb/hello_kdb.c
@@ -0,0 +1,144 @@
+#include <linux/module.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+
+int write_address;
+EXPORT_SYMBOL(write_address);
+
+noinline void dummy_func18(void)
+{
+       panic("Hello KDB has paniced!");
+}
+noinline void dummy_func17(void)
+{
+       dummy_func18();
+}
+noinline void dummy_func16(void)
+{
+       dummy_func17();
+}
+noinline void dummy_func15(void)
+{
+       dummy_func16();
+}
+noinline void dummy_func14(void)
+{
+       dummy_func15();
+}
+noinline void dummy_func13(void)
+{
+       dummy_func14();
+}
+noinline void dummy_func12(void)
+{
+       dummy_func13();
+}
+noinline void dummy_func11(void)
+{
+       dummy_func12();
+}
+noinline void dummy_func10(void)
+{
+       dummy_func11();
+}
+noinline void dummy_func9(void)
+{
+       dummy_func10();
+}
+noinline void dummy_func8(void)
+{
+       dummy_func9();
+}
+noinline void dummy_func7(void)
+{
+       dummy_func8();
+}
+noinline void dummy_func6(void)
+{
+       dummy_func7();
+}
+noinline void dummy_func5(void)
+{
+       dummy_func6();
+}
+noinline void dummy_func4(void)
+{
+       dummy_func5();
+}
+noinline void dummy_func3(void)
+{
+       dummy_func4();
+}
+noinline void dummy_func2(void)
+{
+       dummy_func3();
+}
+noinline void dummy_func1(void)
+{
+       dummy_func2();
+}
+
+static int hello_proc_show(struct seq_file *m, void *v) {
+       seq_printf(m, "Hello proc!\n");
+       return 0;
+}
+
+static int hello_proc_open(struct inode *inode, struct  file *file) {
+       return single_open(file, hello_proc_show, NULL);
+}
+
+static int edit_write(struct file *file, const char *buffer,
+               size_t count, loff_t *data)
+{
+       write_address = 1;
+       return count;
+}
+
+static int bug_write(struct file *file, const char *buffer,
+               size_t count, loff_t *data)
+{
+       dummy_func1();
+       return count;
+}
+
+static const struct file_operations edit_proc_fops = {
+       .owner = THIS_MODULE,
+       .open = hello_proc_open,
+       .read = seq_read,
+       .write = edit_write,
+       .llseek = seq_lseek,
+       .release = single_release,
+};
+
+static const struct file_operations bug_proc_fops = {
+       .owner = THIS_MODULE,
+       .open = hello_proc_open,
+       .read = seq_read,
+       .write = bug_write,
+       .llseek = seq_lseek,
+       .release = single_release,
+};
+
+static int __init hello_proc_init(void) {
+       struct proc_dir_entry *file;
+       file = proc_create("hello_kdb_bug", 0, NULL, &bug_proc_fops);
+       if (file == NULL) {
+               return -ENOMEM;
+       }
+
+       file = proc_create("hello_kdb_break", 0, NULL, &edit_proc_fops);
+       if (file == NULL) {
+               remove_proc_entry("hello_kdb_bug", NULL);
+               return -ENOMEM;
+       }
+       return 0;
+}
+
+static void __exit hello_proc_exit(void) {
+       remove_proc_entry("hello_kdb_bug", NULL);
+       remove_proc_entry("hello_kdb_break", NULL);
+}
+
+MODULE_LICENSE("GPL");
+module_init(hello_proc_init);
+module_exit(hello_proc_exit);
-- 
2.7.4

--
To unsubscribe from this list: send the line "unsubscribe linux-doc" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to