{"id":473,"date":"2022-06-29T10:49:48","date_gmt":"2022-06-29T17:49:48","guid":{"rendered":"https:\/\/sysprogs.com\/tutorials\/?p=473"},"modified":"2022-09-09T13:44:13","modified_gmt":"2022-09-09T20:44:13","slug":"473-2","status":"publish","type":"post","link":"https:\/\/sysprogs.com\/VisualKernel\/documentation\/kernelsymbols\/","title":{"rendered":"Linux Kernel Symbol Overview"},"content":{"rendered":"<p>Debugging Linux kernel modules using gdb is different from debugging normal user-mode applications. Unlike user-mode where gdb can automatically load the symbols for the main executable and all loaded shared libraries, kernel-mode only supports loading the symbols for the kernel itself. Although VisualKernel fully automates the symbol loading process, this page explains what happens &#8220;under the hood&#8221; and what mechanisms are involved.<\/p>\n<h2>Manual symbol loading using GDB<\/h2>\n<p>To demonstrate how symbol loading is performed we can create and load a basic kernel module that includes an exit function:<\/p>\n<pre class=\"code\">static void __exit TestKernelModule_exit(void)\r\n{\r\n    printk(\"TestKernelModule: Goodbye, world!\\n\");\r\n}<\/pre>\n<p>If we load the module and start a kernel debugging session using <a href=\"http:\/\/sysprogs.com\/VisualKernel\/tutorials\/kgdb\/\">KGDB<\/a> or <a href=\"http:\/\/sysprogs.com\/VisualKernel\/tutorials\/vmware\/\">VMWare<\/a>, gdb will load the kernel symbols, but not the symbols for the module. E.g. we will be able to set breakpoints inside the kernel itself (e.g. the <strong>sys_open()<\/strong> function), but not inside <strong>TestKernelModule_exit()<\/strong>:<\/p>\n<pre class=\"code\">(gdb) file vmlinux-3.8.0-19-generic\r\nReading symbols from vmlinux-3.8.0-19-generic...done.\r\n(gdb) b sys_open\r\nBreakpoint 1 at 0xc115f000: file \/build\/buildd\/linux-3.8.0\/fs\/open.c, line 995.\r\n(gdb) b TestKernelModule_exit\r\nFunction \"TestKernelModule_exit\" not defined.\r\nMake breakpoint pending on future shared library load? (y or [n]) n<\/pre>\n<p>Unlike the kernel itself that is always loaded at the same address in memory, kernel modules can be loaded at arbitrary addresses. Before we can load the symbols for a module, we need to find out at which address it was loaded. The easiest way to do it is to set a breakpoint in the <strong>do_init_module()<\/strong> function and once it hits, checking the <strong>name<\/strong> and <strong>module_core<\/strong> fields of the <strong>mod <\/strong>variable:<\/p>\n<pre class=\"code\">(gdb) break do_init_module\r\nBreakpoint 2 at 0xc10ac8e8: file \/build\/buildd\/linux-3.8.0\/arch\/x86\/include\/asm\/\r\ncurrent.h, line 14.\r\n(gdb) continue\r\nContinuing.\r\nBreakpoint 2, load_module\r\nat \/build\/buildd\/linux-3.8.0\/kernel\/module.c:3271\r\n3271 \/build\/buildd\/linux-3.8.0\/kernel\/module.c: No such file or directory.\r\n(gdb) print mod\r\n$1 = (struct module *) 0xf9921000\r\n(gdb) print mod-&gt;name\r\n$2 = <strong>\"TestKernelModule\"<\/strong>, '\\000' &lt;repeats 43 times&gt;\r\n(gdb) print mod-&gt;module_core\r\n$3 = (void *) <strong>0xf9928000<\/strong><\/pre>\n<p>Now once we know the load address of the module, we can load the symbols for it using the <strong>add-symbol-file<\/strong> command. The symbols are contained in the file called <strong> &lt;module name&gt;.o<\/strong> in the module build directory:<\/p>\n<pre class=\"code\">(gdb) add-symbol-file TestKernelModule.o <strong>0xf9928000<\/strong>\r\nadd symbol table from file \"TestKernelModule.o\" at\r\n.text_addr = 0xf9928000\r\n(y or n) y\r\nReading symbols from TestKernelModule.o...done.<\/pre>\n<p>Note that if you now attempt to set a breakpoint in the <strong>TestKernelModule_exit()<\/strong> function, gdb will set it in an invalid address:<\/p>\n<pre class=\"code\">(gdb) break TestKernelModule_exit\r\nBreakpoint 3 at <strong>0x19<\/strong>: file TestKernelModule_main.c, line 13.<\/pre>\n<p>This happens because the <strong>TestKernelModule_exit()<\/strong> function is located in the &#8220;.exit.text&#8221; section and we have only loaded the symbols for the &#8220;.text&#8221; section. Use the following command to display all sections of TestKernelModule that has been loaded into the memory:<\/p>\n<pre class=\"\">(gdb) print *mod-&gt;sect_attrs-&gt;attrs@mod-&gt;sect_attrs-&gt;nsections\r\n$1 = {{\r\nmattr = {...},\r\nname = \".note.gnu.build-id\",\r\naddress = 0xf9929000\r\n}, {\r\nmattr = {...},\r\nname = \".init.text\",\r\naddress = 0xf842a000\r\n}, {\r\nmattr = {...},\r\nname = \".exit.text\",\r\naddress = 0xf9928000\r\n}, {\r\nmattr = {...},\r\nname = \".rodata\",\r\naddress = 0xf9929024\r\n}, {\r\nmattr = {...},\r\nname = \".data\",\r\naddress = 0xf992a000\r\n}, {\r\nmattr = {...},\r\nname = \".gnu.linkonce.this_module\",\r\naddress = 0xf992a020\r\n}, {\r\nmattr = {...},\r\nname = \".bss\",\r\naddress = 0xf992a1a0\r\n}, {\r\nmattr = {...},\r\nname = \".symtab\",\r\naddress = 0xf842b000\r\n}, {\r\nmattr = {...},\r\nname = \".strtab\",\r\naddress = 0xf842b270\r\n}}<\/pre>\n<p>To load the symbols for those sections as well we need to specify their addresses manually in the <strong>add-symbol-file<\/strong> command:<\/p>\n<pre class=\"\">add-symbol-file KernelModule.o 0xf9928000 -s .init.text 0xf842a000 -s .exit.text 0xf9928000\r\nadd symbol table from file \"TestKernelModule.o\" at\r\n.text_addr = 0xf9928000\r\n.init.text_addr = 0xf842a000\r\n.exit.text_addr = 0xf9928000\r\n(y or n) y\r\nReading symbols from TestKernelModule.o...done.\r\n(gdb) b TestKernelModule_exit\r\nBreakpoint 5 at 0xf9928006: file TestKernelModule_main.c, line 17.<\/pre>\n<p>Now the breakpoint was set at the correct address. Note that in order to see the global variables in the debugger, you need to also manually specify the addresses of the <strong>.data<\/strong>, <strong>.rodata<\/strong> and <strong>.bss<\/strong> sections.<\/p>\n<p>You can explore all modules loaded into the kernel by looking through the global &#8216;modules&#8217; list. Simply use the &#8216;next&#8217; field to get the pointer to the list item corresponding to the next module and subtract 4 (the offset of the list item inside the module structure) from it to get the address of the module object:<\/p>\n<pre class=\"\">(gdb) print &amp;((struct module *)0)-&gt;list\r\n$10 = (struct list_head *) 0x4\r\n(gdb) print modules\r\n$11 = {\r\nnext = 0xf9962024,\r\nprev = 0xf8453024\r\n}\r\n(gdb) print *((struct module *)(0xf9962024 - 0x4))\r\n$12 = {\r\nstate = MODULE_STATE_LIVE,\r\nlist = {\r\nnext = 0xf98fc004,\r\nprev = 0xc18a1658 &lt;modules&gt;\r\n},\r\nname = \"TestKernelModule\", '\\000' &lt;repeats 43 times&gt;,\r\n...<\/pre>\n<h2>Automatic symbol loading using VisualKernel<\/h2>\n<p>When you start your debugging session, VisualKernel will automatically set breakpoints inside the kernel functions responsible for loading and unloading the modules. When your module is loaded or unloaded, VisualKernel will automatically load\/unload the symbols for it:<a href=\"https:\/\/sysprogs.com\/tutorials\/wp-content\/uploads\/2022\/06\/modload.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-474\" src=\"https:\/\/sysprogs.com\/tutorials\/wp-content\/uploads\/2022\/06\/modload.png\" alt=\"\" width=\"662\" height=\"429\" \/><\/a><\/p>\n<p>You can use the Modules window in Visual Studio to see the list of currently loaded kernel modules and load symbols for them:<a href=\"https:\/\/sysprogs.com\/tutorials\/wp-content\/uploads\/2022\/06\/modules.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-475\" src=\"https:\/\/sysprogs.com\/tutorials\/wp-content\/uploads\/2022\/06\/modules.png\" alt=\"\" width=\"698\" height=\"287\" \/><\/a><\/p>\n<p>You can configure VisualKernel to automatically load symbols for all or some of the in-tree kernel modules (that ones that are included in the original Linux kernel tree):<a href=\"https:\/\/sysprogs.com\/tutorials\/wp-content\/uploads\/2022\/06\/modulesettings.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-476\" src=\"https:\/\/sysprogs.com\/tutorials\/wp-content\/uploads\/2022\/06\/modulesettings.png\" alt=\"\" width=\"499\" height=\"263\" \/><\/a><\/p>\n<p>See our <a href=\"http:\/\/sysprogs.com\/VisualKernel\/tutorials\/kgdb\/\">KGDB tutorial<\/a> for a step-by-step guide on debugging your kernel with VisualKernel.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Debugging Linux kernel modules using gdb is different from debugging normal user-mode applications. Unlike user-mode where gdb can automatically load<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[58],"tags":[],"_links":{"self":[{"href":"https:\/\/sysprogs.com\/tutorials\/wp-json\/wp\/v2\/posts\/473"}],"collection":[{"href":"https:\/\/sysprogs.com\/tutorials\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/sysprogs.com\/tutorials\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/sysprogs.com\/tutorials\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/sysprogs.com\/tutorials\/wp-json\/wp\/v2\/comments?post=473"}],"version-history":[{"count":6,"href":"https:\/\/sysprogs.com\/tutorials\/wp-json\/wp\/v2\/posts\/473\/revisions"}],"predecessor-version":[{"id":483,"href":"https:\/\/sysprogs.com\/tutorials\/wp-json\/wp\/v2\/posts\/473\/revisions\/483"}],"wp:attachment":[{"href":"https:\/\/sysprogs.com\/tutorials\/wp-json\/wp\/v2\/media?parent=473"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/sysprogs.com\/tutorials\/wp-json\/wp\/v2\/categories?post=473"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/sysprogs.com\/tutorials\/wp-json\/wp\/v2\/tags?post=473"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}