10. Building a vmlinux file

Big deal about a vmlinux file

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 CONFIG_PROC_KCORE and CONFIG_DEBUG_INFO.

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.

Which kernel should you be running?

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 -r2.6.32-23-generic$

Installing the build tools

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)

Getting the source tree

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.

Building the appropriate vmlinux file

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 -aLinux 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/vmlinuxELF 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.

So … will this vmlinux file 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.

Oh, about that config file …

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_PROC_KCORE and 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)):

  • ./debian.master/config/config.common.ubuntu
  • ./debian.master/config/amd64/config.common.amd64
  • ./debian.master/config/amd64/config.flavour.generic

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 /boot:

$ diff debian/build/build-generic/.config /boot/config-2.6.32-23-generic4c4< # 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.

Moving up to a newer kernel

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.

Comments are closed.
%d bloggers like this: