Aleksi Torhamo
Aleksi Torhamo

Reputation: 6632

How can I find out the field offsets of a kernel struct?

I sometimes need to figure out the layout (as in, field offsets) of some kernel structure or another. What is the easiest way to do this?

An example usecase: A few days ago I wanted to attach a kprobe to a function (blk_account_io_done(struct request *req, u64 now)) - but in addition to the function name, I also wanted to log a few fields from the struct that the function gets as an argument. The problem, of course, is that instead of just being able to say req->rq_disk->disk_name, you have to know the field offsets, and instead say something like +12(+192(%di)):string. (The documentation actually seems to suggest perf probe blk_account_io_done req->rq_disk->disk_name could be used to do it automatically, but it would require having debug info enabled in the kernel - which I didn't have (and couldn't enable) on the target machine -- and even on machines with debug info enabled, I couldn't get it to work for whatever reason)

(In lieu of "describe what you've tried", I've self-answered this question with the methods that I've tried - that do work - but which only work in some situations and/or are really cumbersome; I was originally going to include them in the question, but the question started looking more like an answer. They're better than nothing, but I really am looking for something easier / more general)

Upvotes: 2

Views: 1830

Answers (1)

Aleksi Torhamo
Aleksi Torhamo

Reputation: 6632

Note: Previously, this answer contained many different methods for doing this, all with some limitation or another. I've since found what I consider to be the perfect solution, so to reduce clutter, I've removed the other methods from the latest revision of the answer; If you want to check out the other methods, see this earlier revision. While I feel that the method I've left here is the best one, you might want to check out the others as well, in case one of them fits your needs better.

Some of the earlier methods had the limitation that the kernel needed to be compiled with special configuration options or debug information enabled, and sometimes that might not be possible for one reason or another. However, you can instead compile a kernel module with debug information enabled, and extract the information from that.

Makefile:

CC += -g
ifneq ($(KERNELRELEASE),)
        obj-m := offsetof.o
else
        KERNELDIR ?= /lib/modules/$(shell uname -r)/build
        PWD := $(shell pwd)
default:
        make -C $(KERNELDIR) SUBDIRS=$(PWD) modules
endif

offsetof.c:

#include <linux/init.h>
#include <linux/module.h>
// The header where the struct you're interested in is defined
#include <linux/blkdev.h>
MODULE_LICENSE("GPL");

// Ensures that the struct we're interested in is included in the debug information
struct request myvar;

After running make, the resulting kernel module will contain all the information about the struct we need. To extract that information, you can use eg. pahole from the dwarves package: pahole -C request offsetof.ko

I've also automated this (using pyelftools instead of pahole, though) and put it up on github. Usage: offsetof --kernel linux/blkdev.h "struct request"

If your kernel already contains debug information, you can just point pahole directly at your [uncompressed] kernel image (vmlinux) instead of compiling the kernel module. If you only have a compressed kernel image (vmlinuz), you can use extract-vmlinux, which is found under scripts/ in the kernel source directory.

Upvotes: 3

Related Questions