For the purposes of kernel debugging that will be covered later in this course, it's sometimes extremely useful to have on hand the raw, uncompressed
vmlinux file that corresponds to the running kernel. More specifically, it's useful to have a
vmlinux file that's been configured with the kernel settings
Make sure you understand that, by
vmlinux file, we're not talking about the
vmlinuz-* file corresponding to the running kernel that you can find under
/boot -- that's not the one you want. Some distros make it very easy to get your hands on the matching
vmlinux file; Ubuntu makes you do a bit more work, but it's still feasible.
One last point -- if you have the freedom to configure, build and reboot a new kernel, then this whole issue is trivial since the
vmlinux file is generated as part of the build process, and you can find it at the top of the kernel source tree once the build is done. This little tutorial is for those people who don't have the freedom to build and boot a new kernel, and therefore have to work with the kernel that's currently running.
Acknowledgements: Much of what follows is based on the Ubuntu kernel compilation page here, plus some very helpful people on the Ubuntu kernel mailing list.
While it's not strictly necessary, it never hurts to be running the most up-to-date kernel available, so do the standard update and upgrade before going any further. If you want, you can check the current version with:
$ uname -r 2.6.32-23-generic $
The Ubuntu folks have added an entire extra layer of build infrastructure to the standard kernel source tree, so you first need to install all the necessary utilities:
$ sudo apt-get build-dep linux-image-$(uname -r)
While there are a couple ways to get the appropriate kernel source tree, the simplest way appears to be using
git, so pick a convenient location and:
$ git clone git://kernel.ubuntu.com/ubuntu/ubuntu-lucid.git
whereupon you'll end up with a
ubuntu-lucid directory that contains not just a standard kernel source tree, but quite a lot of Ubuntu additions.
Now that you have your local
git clone, it's essential that you check out exactly the tag that corresponds to your running kernel. Get that information with:
$ uname -a Linux lynx 2.6.32-23-generic #37-Ubuntu SMP ... snip ... $
The above tells you that you should check out the tag:
$ git checkout Ubuntu-2.6.32-23.37
in order to have a source tree that corresponds to the one used to build your running kernel. Next, clean the source in preparation for the build:
$ fakeroot debian/rules clean
and start the build:
$ fakeroot debian/rules binary-generic
Once this is done, you should find your (sizable)
vmlinux file here:
$ ls -l debian/build/build-generic/vmlinux ... 114276028 2010-07-01 15:31 debian/build/build-generic/vmlinux $ file debian/build/build-generic/vmlinux ELF 64-bit LSB executable, x86-64, version 1 (SYSV), \ statically linked, not stripped $
Don't bother doing anything with it, just remember how to get it since you'll be needing it down the road.
vmlinuxfile actually work?
As in, will this built
vmlinux file actually match exactly the running kernel? That's not at all clear -- there are all kinds of reasons why there might be subtle but sufficient differences that you can't use it for debugging, because the symbol table entries are slightly off.
The only way to guarantee compatibility is to configure and build your own kernel, then boot to that new kernel, knowing you have the original
vmlinux file for it. Really, that's the only way to guarantee correctness.
The whole reason for building a
vmlinux file in the first place is to have an unstripped, uncompressed kernel image that you can use later for debugging your running kernel. And part of that value comes from configuring your kernel with the appropriate kernel config options -- specificially,
CONFIG_DEBUG_INFO -- for reasons that will become obvious in a later lesson.
When using Ubuntu's build infrastructure, the config file used is constructed hierarchically, based on the following files (at least, in my case on my 64-bit laptop and choosing to build a "generic" kernel)):
Unsurprisingly, the more specific file settings override the more generic ones.
In fact, it's easy to check that the config file used for the build is equivalent to the one you can see in
$ diff debian/build/build-generic/.config /boot/config-2.6.32-23-generic 4c4 < # Thu Jul 1 14:50:17 2010 --- > # Fri Jun 11 08:03:19 2010 $
That tells me that the only difference is the internal timestamp and the rest of the two files are identical. That's what you want to see.
If you update your Ubuntu system to a newer kernel, it should be easy to see how to rebuild your
vmlinux file accordingly. Just clean the result of the current build with:
$ fakeroot debian/rules clean
then follow the same instructions for your newer kernel version.
This tutorial is a free part of a larger, subscriber-only introductory course in Linux kernel programming that you can read about here.