Depurando o Kernel do Linux com Kprobes
De Wiki do Veiga
Tabela de conteúdo |
Intrudução
Kprobes permite registrar breakpoints capazes de parar dinamicamente em qualquer rotina do kernel e coletar informações de debug e desempenho.
Existem atualmente três tipos de probres:
- kprobes: podem ser inseridos virtualmente em qualquer instrução do kernel.
- jprobes: são inseridos no ponto de entrada de uma função do kernel e provê acesso aos seus argumentos.
- kretprobes (return probes): são chamadas quando uma função do kernel especificada retorna.
Um descrição detalhada de como funciona cada tipo de probe pode ser obtida em Documentation/kprobes.txt.
Existem ferramentas de depuração superiores construídas em cima do Kprobes, como o SystemTap. No entanto, o SystemTap ainda não funciona redondo em sistemas cross-compilados e algumas arquiteturas. :-(
Este texto descreve como habilitar o Kprobes no kernel e como criar um probe simples.
Compilando o Kernel para Suportar Kprobes
Seleção da funcionalidade no make menuconfig:
General setup --->
[*] Kprobes
Resultado no .config:
CONFIG_KPROBES=y CONFIG_KALLSYMS=y CONFIG_KALLSYMS_ALL=y
Interface via debugfs
Kprobes utiliza o debugfs file system como interface com o usuário.
Para montar o debugfs:
mkdir /debug mount -t debugfs nodev /debug
O arquivo enabled permite habilitar ou desabilitar o Kprobes:
cat /debug/kprobes/enabled 1
Por default, todos os kprobes são habilitados.
# Habilitar os kprobes echo 1 > /debug/kprobes/enabled # Desabilitar os kprobes echo 0 > /debug/kprobes/enabled
Uma lista de todos os kprobes habilitados pode ser visualizada em:
cat /debug/kprobes/list c015d71a k vfs_read+0x0 c011a316 j do_fork+0x0 c03dedc5 r tcp_v4_rcv+0x0
Criação de kprobes
Os kprobes são inseridos no kernel tipicamente na forma de módulos. A seguir é descrito como criar um módulo do kernel que registra kprobes.
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/kprobes.h>
static struct kprobe kp = {
.symbol_name = "do_fork",
};
static int handler_pre(struct kprobe *p, struct pt_regs *regs)
{
printk(KERN_INFO "pre_handler: p->addr = 0x%p\n", p->addr);
return 0;
}
static void handler_post(struct kprobe *p, struct pt_regs *regs,
unsigned long flags)
{
printk(KERN_INFO "post_handler: p->addr = 0x%p\n", p->addr);
}
static int handler_fault(struct kprobe *p, struct pt_regs *regs, int trapnr)
{
printk(KERN_INFO "fault_handler: p->addr = 0x%p, trap #%dn",
p->addr, trapnr);
return 0;
}
static int __init kprobe_init(void)
{
int ret;
kp.pre_handler = handler_pre;
kp.post_handler = handler_post;
kp.fault_handler = handler_fault;
ret = register_kprobe(&kp);
if (ret < 0) {
printk(KERN_INFO "register_kprobe failed, returned %d\n", ret);
return ret;
}
printk(KERN_INFO "Planted kprobe at %p\n", kp.addr);
return 0;
}
static void __exit kprobe_exit(void)
{
unregister_kprobe(&kp);
printk(KERN_INFO "kprobe at %p unregistered\n", kp.addr);
}
module_init(kprobe_init)
module_exit(kprobe_exit)
MODULE_LICENSE("GPL");
Criar Makefile para compilar o módulo:
cat > Makefile
Compilar e carregar o módulo:
make ls kprobe_example.ko insmode kprobe_example.ko ...
Referências
- Kernel Probes (Kprobes): Documentation/kprobes.txt
- An introduction to KProbes: http://lwn.net/Articles/132196/
- Kernel debugging with Kprobes: http://www.ibm.com/developerworks/library/l-kprobes.html
Marcelo Veiga Neves < marcelo.veiga at gmail.com >
