Kprobes是一种运行时动态调试内核的机制, 你可以用它设置断点并收集调试信息, 甚至改变内核行为.

Kprobes分三种, 普通kprobes以及基于普通kprobes的jprobes和kretprobes. kprobes可以注入某个地址, jprobes用来注入某个函数入口, 而kretprobes则用来注入某个函数返回.

实现原理

Kprobes的实现主要利用了处理器的异常和单步执行特性. 以普通kprobes举例, 注册时它会复制一份被注入的指令, 并加入断点(例如x86的int 3), 当CPU执行到被注入的指令时就会陷入到Kprobes中, 此时Kprobes先运行钩子函数”pre_handler”, 然后单步执行被复制的指令, 并且由于是单步执行模式, 指令执行完毕后会再次触发异常而陷入到Kprobes中, 此时Kprobes会运行钩子函数”post_handler”并最终返回.

使用方法

通常情况下, Kprobes以内核模块的形式工作, 模块的init函数用来注册Kprobes, exit函数相应得用来注销, pre_handler和post_handler分别在单步执行被复制的指令前后运行, fault_handler则在单步执行发生异常时运行.

Kprobes模块写起来很简单, 下面是一个内核源码中的例子, 演示如何在每次do_fork()的时候打印选定寄存器中的内容.

 #include <linux/kernel.h>
#include <linux/module.h>
#include <linux/kprobes.h> /* For each probe you need to allocate a kprobe structure */
static struct kprobe kp = {
.symbol_name = "do_fork",
}; /* kprobe pre_handler: called just before the probed instruction is executed */
static int handler_pre(struct kprobe *p, struct pt_regs *regs)
{
printk(KERN_INFO "pre_handler: p->addr = 0x%p, ip = %lx,"
" flags = 0x%lx\n",
p->addr, regs->ip, regs->flags); /* A dump_stack() here will give a stack backtrace */
return ;
} /* kprobe post_handler: called after the probed instruction is executed */
static void handler_post(struct kprobe *p, struct pt_regs *regs,
unsigned long flags)
{
printk(KERN_INFO "post_handler: p->addr = 0x%p, flags = 0x%lx\n",
p->addr, regs->flags);
} /*
* fault_handler: this is called if an exception is generated for any
* instruction within the pre- or post-handler, or when Kprobes
* single-steps the probed instruction.
*/
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 because we don't handle the fault. */
return ;
} 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 < ) {
printk(KERN_INFO "register_kprobe failed, returned %d\n", ret);
return ret;
}
printk(KERN_INFO "Planted kprobe at %p\n", kp.addr);
return ;
} 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");

这只是一个简单的打印示例, Kprobes还可以修改被注入函数的上下文, 如内核数据结构和寄存器, 并且都是在运行时动态修改, 多么美好!

ref:

1, https://lwn.net/Articles/132196/
2, https://www.kernel.org/doc/Documentation/kprobes.txt
3, http://www.ibm.com/developerworks/library/l-kprobes/index.html

[fw]用Kprobes调试(debug)内核的更多相关文章

  1. 【转】TI-Davinci开发系列之六CCS5.2调试Linux内核

    上转博文<TI-Davinci开发系列之五CCS5.2使用gdbserver远程调试应用程序> 使用CCS5.2远程调试内核时,只需导入Linux内核源码,而不需要编译内核,也就不会用到交 ...

  2. 在qemu环境中用gdb调试Linux内核

    简介 对用户态进程,利用gdb调试代码是很方便的手段.而对于内核态的问题,可以利用crash等工具基于coredump文件进行调试.其实我们也可以利用一些手段对Linux内核代码进行gdb调试,qem ...

  3. 使用 ftrace 调试 Linux 内核【转】

    转自:http://blog.csdn.net/adaptiver/article/details/7930646 使用 ftrace 调试 Linux 内核,第 1 部分 http://blog.c ...

  4. 手把手教你使用eclipse+qemu+gdb来单步调试ARM内核【学习笔记】

    平台信息:linux4.0 平台:qemu 作者:庄泽彬 说明:笨叔叔的Linux视频的笔记 一.编译linux源码 export CROSS_COMPILE=arm-linux-gnueabi- e ...

  5. 用qemu+gdb tcp server+CDT调试linux内核启动-起步

    用qemu+gdb tcp server+CDT调试linux内核启动-起步 说明: 环境信息与 用virtualbox+模拟串口+CDT调试linux内核 TCP IP协议栈-起步 提到的一样,并且 ...

  6. 用 kGDB 调试 Linux 内核

    简介 这个文档记录了用kGDB调试Linux内核的全过程,都是在前人工作基础上的一些总结.以下操作都是基于特定板子来进行,但是大部分都能应用于其他平台. 要使用KGDB来调试内核,首先需要修改conf ...

  7. 学习构建调试Linux内核网络代码的环境MenuOS系统

    构建调试Linux内核网络代码的环境MenuOS系统 一.前言 这是网络程序设计的第三次实验,主要是学习自己编译linux内核,构建一个具有简易功能的操作系统,同时在系统上面进行调试linux内核网络 ...

  8. 使用QEMU调试Linux内核代码

    http://blog.chinaunix.net/uid-20729583-id-1884617.html http://www.linuxidc.com/Linux/2014-08/105510. ...

  9. Gdb远程调试Linux内核遇到的Bug

    知识共享许可协议本作品采用知识共享署名 4.0 国际许可协议进行许可.转载保留声明头部与原文链接https://luzeshu.com/blog/gdb-bug 本博客同步在http://www.cn ...

随机推荐

  1. C#面试 笔试题 六

    1.String str=new String("a")和String str = "a"有什么区别? String str = "a"; ...

  2. JS中对象数据类型的基本结构和操作

    Object类型 ECMAScript中的队形其实就是一组数据和功能的集合.对象可以通过执行new操作符后跟要创建的对象类型的名称来创建.而创建Object类型的示例并为其添加属性和(或)方法,就可以 ...

  3. Python中字符串的格式化

    字符串的格式化 格式化是对字符串进行格式表示的方式.使用槽({})按顺序格式化字符串. 格式化方式 <模板字符串>.format(<逗号分割参数>) "{ }:计算机 ...

  4. ssh-add - 向认证代理添加 RSA 或 DSA 身份数据

    总览 (SYNOPSIS) ssh-add [-lLdDx ] [-t life ] [file ... ] ssh-add -s reader ssh-add -e reader 描述 (DESCR ...

  5. 几种激活Profile的方式

    方法一: 选择spring.profiles.active spring.profiles.active=prodspring.profiles.active=dev 方法二: 选择spring.pr ...

  6. 英伟达GPU 嵌入式开发平台

    英伟达GPU  嵌入式开发平台 1.         JETSON TX1 开发者组件 JETSON TX1 开发者组件是视觉计算的全功能 开发平台,旨在让您能够快速地安装和运行. 该组件带有 Lin ...

  7. Linux防火墙--iptables--白名单配置

    1.服务器22端口和1521端口开通给指定IP [root@node2 sysconfig]# iptables -t filter -nL INPUT Chain INPUT (policy ACC ...

  8. 用Matlab的.m脚本文件处理实验室数据

    找到相应的文件 findfile %1 打开文件夹 %2 拷贝第一个文件 %3 关闭当前文件,再次拷贝新的文件,直到文件末尾结束 clc clear DST_PATH_t = 'C:\Users\Ma ...

  9. No enclosing instance of type TestGson is accessible. Must qualify the allocation with an enclosing instance of type TestGson (e.g. x.new A() where x is an instance of TestGson).

    main方法中实例化内部类报错: public class TestGson { public static void main(String[] args) { Gson gson=new Gson ...

  10. Vue 左右翻页,点赞动画

    因做小活动比较多,使用了一些动画,做些笔记,供大家参考 翻页动画 router -> index.js import Vue from 'vue'; import Router from 'vu ...