Reputation: 6632
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
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