Search code examples
linux-kernelarmarmv7systemtapkprobe

What is the role of undefined exception handler (__und_svc) in kprobes?


I tried to convert the kprobe as loadable kernel module.

I am able to run the samples available in samples/kprobes/ folder from kernel tree.

If we configure kprobes in kernel(CONFIG_KPROBES), then svc_entry macro will be expanded with 64 bytes in __und_svc() handler.

Reference : http://lxr.free-electrons.com/source/arch/arm/kernel/entry-armv.S?a=arm#L245

My aim is without touching kernel side, make kprobe as kernel module.

so kernel is compiled without enabling CONFIG_KPROBES. so svc_entry macro will be expanded with 0 in __und_svc()

I would like to get cleared from these doubts.

  1. If kprobe is handled undefined instruction exception(bcos kprobe only created), then why __und_svc() is invoked. what is the role of __und_svc() handler with respect to kprobes??

  2. If 64 bytes memory is compulsory, then how to allocate without compiling the kernel. i.e How to do it dynamically.??

Please share your knowledge.


Solution

  • You may not get responses as your understanding of things is not very good and it will take some time for anyone on the linux-arm-kernel list to respond. Read kprobes.txt and study the ARM architecture in detail.

    If kprobe is handled undefined instruction exception(bcos kprobe only created), then why __und_svc() is invoked. what is the role of __und_svc() handler with respect to kprobes?

    On the ARM, mode 0b11011 is the undefined instruction mode. The flow when an undefined instruction happens is,

    1. lr_und = pc of undef instruction + 4
    2. SPSR_und = CPSR of mode where the instruction occurred.
    3. Change mode to ARM with interrupt disabled.
    4. PC = vector base + 4

    The main vector table of step four is located at __vectors_start and this just branches to vector_und. The code is a macro called vector_stub, which makes a descision to call either __und_svc or __und_usr. The stack is the 4/8k page that is reserved per process. It is the kernel page which contains both the task structure and the kernel stack.

    kprobe works by placing undefined instructions at code addresses that you wish to probe. Ie, it involves the undefined instruction handler. This should be pretty obvious. It calls two routines, call_fpe or do_undefinstr(). You are interested in the 2nd case, which gets the opcode and calls call_undef_hook(). Add a hook with register_undef_hook(); which you can see arch_init_kprobes(). The main callback kprobe_handler is called with a struct pt_regs *regs, which happens to be the extra memory reserved in __und_svc. Notice for instance, kretprobe_trampoline(), which is playing tricks with the stack that it is currently executing with.

    If 64 bytes memory is compulsory, then how to allocate without compiling the kernel. i.e How to do it dynamically.?

    No it is not. You can use a different mechanism, but you may have to modify the kprobes code. Most likely you will have to limit functionality. It is also possible to completely re-write the stack frame and reserve the extra 64bytes after the fact. It is not an allocation as in kmalloc(). It is just adding/subtracting a number from the supervisor stack pointer. I would guess that the code re-writes the return address from the undefined handler to execute in the context (ISR, bottom half/thread IRQ, work_queue, kernel task) of the kprobed address. But there are probably additional issues you haven't yet encountered. If arch_init_kprobes() is never called, then you can just always do the reservation in __und_svc; it just eats 64 bytes of stack which will make it more likely that the kernel stack will overflow. Ie, change,

    __und_svc:
        @ Always reserve 64 bytes, even if kprobe is not active.
        svc_entry 64
    

    arch_init_kprobes() is what actually installs the feature.