10

I have put a kprobe on a function and now I need to get values of its arguments in kprobe's prehandler function.

Here is my function:

void foobar(int arg, int arg2, int arg3, int arg4, int arg5, int arg6, int arg7, int arg8)
{
    printk("foobar called\n");
}

Putting kprobe on it and calling the function:

...
kp.addr = (kprobe_opcode_t *) foobar;
register_kprobe(&kp);

foobar(0xdead1, 0xdead2, 0xdead3, 0xdead4, 0xdead5, 0xdead6, 0xdead7, 0xdead8);

And finally prehandler function (taken from here):

static int inst_generic_make_request(struct kprobe *p, struct pt_regs *regs)
{
  printk(KERN_INFO "eax: %08lx   ebx: %08lx   ecx: %08lx   edx: %08lx\n",
    regs->ax, regs->bx, regs->cx, regs->dx);
    printk(KERN_INFO "esi: %08lx   edi: %08lx   ebp: %08lx   esp: %08lx\n",
      regs->si, regs->di, regs->bp, regs->sp);
    regs++;
    //...
}

The output from the prehandler function looks like this (I incremented regs pointer 3 times)

May 10 22:58:07 kernel: [  402.640994] eax: 000dead1   ebx: f7d80086   ecx: 000dead3   edx: 000dead2
May 10 22:58:07 kernel: [  402.640996] esi: 00000000   edi: b77c8040   ebp: 00000000   esp: f7d8006c

May 10 22:58:07 kernel: [  402.641006] eax: f7d8032c   ebx: 000dead5   ecx: 000dead6   edx: 000dead7
May 10 22:58:07 kernel: [  402.641007] esi: 000dead8   edi: f7d800e0   ebp: f7d80330   esp: 08049674

May 10 22:58:07 kernel: [  402.641014] eax: 00000080   ebx: 0992b018   ecx: 0000108e   edx: 0992b008
May 10 22:58:07 kernel: [  402.641015] esi: 08049674   edi: b77c8040   ebp: bfe23fb8   esp: bfe23f50

Now I can see arguments of foobar function in various registers (but where's 0xdead4?), shouldn't they be in a stack? How can I access the stack from prehandler function? Or how can I get arguments of any function without knowing their types and count? I know that this might not be an easy task (and not even possible to get all values), but only approximately values should be enough. I'm calculating correlation between arguments of two functions and I really don't need exact values. Would it help if I had assembly code of caller function where the arguments are pushed onto the stack)?

Peter Krejci
  • 3,182
  • 6
  • 31
  • 49

2 Answers2

17

There are at least two approaches.

Approach 1: Jprobes

Probably the most easy one: if Jprobes are suitable for your task, you could give them a try. They are the close relatives of kprobes (see their detailed description and links to the examples in the kernel docs).

Jprobes allow to call your function with the same signature as the probed one on entry to the latter. You get all of the arguments automatically this way.

Approach 2: Registers and Stack

Another approach could be to extend a bit what you already do and retrieve the arguments from the registers and the stack. From the output log in your question, I assume you are working on a 32 bit x86 system.

x86, 32 bit

As far as I have seen, there are two most common conventions on argument passing in the Linux kernel on x86 (the details are available in the manual by Agner Fog). Note that system calls follow other conventions (see the manual for details) but I assume you are interested in analysing an "ordinary" function rather than a system call.

Convention 1

For the functions marked with asmlinkage as well as for the functions with variable argument lists, all parameters are passed on stack. The return address of the function should be at the top of the stack on entry to the function, the first parameter being located right below it. The second parameter is below the first one, and so on.

As you have the saved value of esp, you can find what it points to. *(esp+4) should be the first argument, *(esp+8) - the second one, etc., if this convention is used.

Convention 2

It seems to be used for the most of the kernel functions including the one you mentioned in the question.

The kernel is compiled with -mregparm=3 and therefore the first 3 arguments are passed in eax, edx and ecx, in that order, the rest go on stack. *(esp+4) should be the 4th argument, *(esp+8) - the 5th one, and so on.

x86, 64bit

It seems that things are a bit simpler on x86-64. Most of the kernel functions (including those with variable argument list) get the first 6 arguments in rdi, rsi, rdx, rcx, r8, r9, in that order, the remaining ones go on stack. *(esp+8) should be the 7th argument, *(esp+16) - the 8th and so on.

EDIT:

Note that on x86-32, the value of esp is not saved in pt_regs for kernel-mode traps (including the software breakpoints that KProbes rely upon). <asm/ptrace.h> provides kernel_stack_pointer() function to retrieve the correct value of esp, it works both on x86-32 and on x86-64. See the description of kernel_stack_pointer() in that header file for details.

In addition, regs_get_kernel_stack_nth() (also defined in that header) provides a convenient way to get the contents of the stack in the handler.

Community
  • 1
  • 1
Eugene
  • 5,977
  • 2
  • 29
  • 46
  • Thank you for nice answer. I'm a little bit confused with esp register, it should point to memory location where function return address is stored (start of the stack), right? But `regs->esp` contains the return address itself, the same value returns macro `__builtin_return_address(0)` in `foobar` function. So `*(esp+4)` doesn't point to the right location, how can I access the stack then? – Peter Krejci May 13 '12 at 23:53
  • Good point! I have looked through the implementation of KProbes on x86-32. It seems that for optimized KProbes `esp` is not saved in `pt_regs`. The good news is, `regs` argument of the handler actually points to an area on stack and from what I could see in the implementation of KProbes, the stack area you need starts 60 bytes after `regs`. That is, `(unsigned long)regs + 60` is the address of the stack location for the return address, `(unsigned long)regs + 64` - for the argument #4 (yes, `dead4` is there), and so on. Checked this on Linux kernel 3.1 and 3.3. – Eugene May 14 '12 at 09:22
  • (continued) As for where the offset `60` came from. In the optimized KProbes, a jump to a special function is places at the probe site. The template the special function is generated from is in [kprobes_optinsn_template_holder() function](http://lxr.free-electrons.com/ident?i=kprobes_optinsn_template_holder). On entry to the special function, `esp` is the same as on entry to the probed function. `pushf` and `SAVE_REGS_STRING` subtract 60 from it and then it is passed as the 2nd argument to the handler. On x86-64 things are different, though. – Eugene May 14 '12 at 09:28
  • I have investigated it a bit further and found a more reliable way to get the stack pointer and the contents of the stack. It looks like `esp` is not saved in `pt_regs` no matter if the KProbe is optimized or not. However, `kernel_stack_pointer()` function defined in `asm/ptrace.h` may be what you are looking for. It returns the correct value of `esp`. It works on my system, at least. I have edited my answer accordingly. – Eugene May 14 '12 at 13:48
0

As far as I know analysing the assembly code and finding function arguments will be a difficult task, especially in case of Linux kernel code. One of the ways to find out the function arguments is to use the debugging information. Let me put this in step by step way.

1) Build your kernel or module with debugging information (-g option), for an example let's assume that I have built a module named 'test.ko' with debugging information.

2) Use readelf command to decode the debugging information. Like this:

   $readelf debug-dump=info test.ko > log.info

Here I redirected readelf output to log.info file.

3) Now open the log.info and search for the function for which you want to find out the function arguments, in our case let's say 'foobar()'. There will be a Dwarf entry with TAG DW_TAG_subprogram for the function foobar(). After this TAG you will find the some other dwarf entries with function arguments names. In this entries you will find the location of these function arguments when a function is called. For example, it says that first argument 'arg' will be in the ebx register, second arguments will be in the esp+8 and third argument will be in the ecx register and so on.

4) After you get these information, in your kprobe prehandler print all registers. And also print the stack data, this you can print as you know the esp register in the prehandler.

5) Based on the information you get in the 3rd step search for the arguments values.

mohanreddykv
  • 207
  • 1
  • 2