使用printk打印变量等方法,是调试内核的有效方法之一,但是这种方法必须重新构建并用新内核启动,调试效率比较低。以内核模块的方式使用kprobes、jprobes,就可以在任意地址插入侦测器,执行包括printk在内的各种调试工作,而无须重新构建内核,也无须重启。

一、首先内核必须支持kprobes、jprobes:

#make menuconfig

General setup  --->

[*] Kprobes

使内核支持kprobes。

二、kprobes的使用方法:
1、分配一个kprobe结构体供kprobes运行时使用。
2、在kprobe结构体的addr成员中设置要插入侦测器的函数地址,可以通过查看system.map查找,或者通过proc文件系统查找

# cat /proc/kallsyms | grep "do_execve"

c00bbfb8 T do_execve
3、如果不想设置addr成员,可以设置symbol_name成员为"do_execve"(想要侦测的函数),需要内核版本在2.6.19以上才支持。

4、在kprob结构的pre_handler成员设置侦测函数exec_pre_handler。

5、调用register_kprobe函数注册侦测器函数。

以下是一个用kprobes监测do_execve()函数的例子,在每次调用do_execve()函数之前,就会打印当前的进程pid、jiffies值等全局变量信息。#include <linux/module.h>

  1. #include <linux/kprobes.h>
  2. #include <linux/kallsyms.h>
  3. struct kprobe exec_kp;
  4. static int exec_pre_handler(struct kprobe *p, struct pt_regs *regs)
  5. {
  6. printk("Enter into %s\n", __func__);
  7. printk("pt_regs:%p, pid:%d, jiffies:%ld\n", regs, current->tgid, jiffies);
  8. return 0;
  9. }
  10. static __init int kprobes_exec_init(void)
  11. {
  12. /*设置要检测的函数do_execve()的地址*/
  13. //exec_kp.addr = (kprobe_opcode_t *)0xc00bbfb8;
  14. /*如果不想直接给addr成员设置地址,也可以使用符号名*/
  15. exec_kp.symbol_name = "do_execve";
  16. exec_kp.pre_handler = exec_pre_handler;
  17. /*注册kprobes*/
  18. register_kprobe(&exec_kp);
  19. return 0;
  20. }
  21. static __exit void kprobes_exec_cleanup(void)
  22. {
  23. /*撤销kprobes注册*/
  24. unregister_kprobe(&exec_kp);
  25. }
  26. module_init(kprobes_exec_init);
  27. module_exit(kprobes_exec_cleanup);
  28. MODULE_LICENSE("GPL");

编译并insmod上述ko,那么在do_execve()函数执行之前就会先执行kprobes的pre_handler所指向的exec_pre_handler,打印内核的当前进程pid、jiffies等全局变量的值。由于do_exec函数用于生成进程,因此每次执行ls等命令都会显示一次:

pt_regs:c52ebf08, pid:110, jiffies:155286

pt_regs:c5313f08, pid:113, jiffies:159137

pt_regs:c52ebf08, pid:112, jiffies:159137

利用kprobes也可以查看内核函数内部任意位置的信息,此时需要把内核函数反汇编,确定想要查看位置相对于函数起始地址的偏移量,在初始化kprobes时,设置kprobe结构体的offset成员,就可以查看内核内部函数任意位置的信息。

三、jprobes的使用方法

用kprobes可以方便的查看内核内部任意位置的信息,相反,jprobes则是特别为函数开头的侦测准备的,通过jprobes,可以更容易的获取传递给函数的参数。使用jprobes与使用kprobes大体上一样,主要有以下区别:

1、分配给jprobes的结构体是jprobe结构体,并将指针传递给register_jprobe。jprobe结构的成员如下所示,只包括kprobe和entry两者。

  1. struct jprobe {
  2. struct kprobe kp;
  3. void *entry;    /* probe handling code to jump to */
  4. };

struct kprobe kp成员设置的是要侦测函数的符号或地址,entry中为通过JPROBE_ENTRY()宏处理过的侦测器处理程序。

2、侦测器处理程序的参数应当与需要侦测的函数的参数相同,这样可以方便的打印被侦测函数的形参。使用kprobes时,必须通过寄存器或者栈才能计算出参数的值。而计算方法还依赖于cpu架构,如果使用jprobes,则无须了解架构的详细知识,也能查看参数的值。
3、侦测器处理函数的尾部必须加上jprobe_return();

以下是使用jprobes打印do_execve函数的参数的例子,每次调用do_execve之前,都会打印相应的参数:

  1. #include <linux/module.h>
  2. #include <linux/kprobes.h>
  3. #include <linux/kallsyms.h>
  4. struct jprobe exec_jp;
  5. int jp_do_execve(const char * filename,
  6. const char __user *const __user *argv,
  7. const char __user *const __user *envp,
  8. struct pt_regs * regs)
  9. {
  10. int cnt = 0;
  11. printk("filename = %s\n", filename);
  12. for(; *argv != NULL;argv++,cnt++)
  13. printk("argv[%d] = %s\n", cnt, *argv);
  14. jprobe_return();
  15. return 0;
  16. }
  17. static __init int jprobes_exec_init(void)
  18. {
  19. exec_jp.kp.symbol_name = "do_execve";
  20. exec_jp.entry = JPROBE_ENTRY(jp_do_execve);
  21. /*注册jprobes*/
  22. register_jprobe(&exec_jp);
  23. return 0;
  24. }
  25. static __exit void jprobes_exec_cleanup(void)
  26. {
  27. /*撤销jprobes注册*/
  28. unregister_jprobe(&exec_jp);
  29. }
  30. module_init(jprobes_exec_init);
  31. module_exit(jprobes_exec_cleanup);
  32. MODULE_LICENSE("GPL");

每次执行ls时都会调用do_execve函数,具体的打印如下:

# ls

filename = /bin/ls

argv[0] = ls

 

[FW]使用kprobes查看内核内部信息的更多相关文章

  1. 使用kprobes查看内核内部信息

    前言:使用printk打印变量等方法,是调试内核的有效方法之一,但是这种方法必须重新构建并用新内核启动,调试效率比较低.以内核模块的方式使用kprobes.jprobes,就可以在任意地址插入侦测器, ...

  2. [linux系统]查看内核版本和系统版本方法

    查看内核版本信息的两个命令: uname -a cat /proc/version 查看系统版本的命令: lsb_release -a more /etc/issue cat /etc/redhat- ...

  3. linux查看内核版本、系统版本、系统位数(32or64)

     linux查看内核版本.系统版本.系统位数(32or64) 2011-05-01 22:05:12 标签:linux 内核版本 休闲 系统版本 系统位数 1. 查看内核版本命令: 1) [root@ ...

  4. 在linux下查看内核版本、gcc版本、操作系统多少位等参数

    1. 查看linux版本 cat /etc/issue Ubuntu 11.04 \n \l 2. 查看内核版本 1)cat /proc/version Linux version 2.6.38-13 ...

  5. Linux下查看内核、CPU、内存及各组件版本的命令和方法

    Linux下查看内核.CPU.内存及各组件版本的命令和方法 Linux查看内核版本: uname -a                        more /etc/*release       ...

  6. Ubuntu 中查看内核版本和系统版本的三个命令

    一.查看内核版本:cat /proc/version 二.查看内核版本:uname -a 三.查看系统版本:lsb_release -a 四.查看发行版类型:cat /etc/issue

  7. Linux查看内核和系统版本

    1. 查看内核版本命令: 1) [root@q1test01 ~]# cat /proc/version Linux version 2.6.9-22.ELsmp (bhcompile@crowe.d ...

  8. Linux查看内核信息或系统信息

    先说说为什么会写这个.这是我去面试的时候面试官问的一个问题,我感觉是一个普遍会被问到的问题.为了让我自己记住,也便于收集下Linux运维方向考官的题目. 第一,查看内核信息 cat /proc/ver ...

  9. Ubuntu 中查看内核版本和系统版本的四个命令

    一.查看内核版本:cat /proc/version 二.查看内核版本:uname -a 三.查看系统版本:lsb_release -a 四.查看发行版类型:cat /etc/issue

随机推荐

  1. JVM(10)之 年老代收集器

    开发十年,就只剩下这套架构体系了! >>>   在上一篇博文我们介绍了JAVA新生代收集器,本篇博文我们要讲的就是关于老年代的一些收集器.老年代存活的一般是大对象以及生命很顽强的对象 ...

  2. 20180209-sys模块

    sys模块常用操作如下: 1.命令行参数 sys.argv  第一个元素是程序本身路径 # 1.命令行参数 第一个元素是程序本身路径 ret = sys.argv print('命令行参数:',ret ...

  3. rpmcache - 缓存 RPM 打包头部

    SYNOPSIS rpmcache [ PACKAGE_NAME ... ] DESCRIPTION rpmcache 遍历文件树,可能通过 FTP 使用远程文件,使用 glob(7) 表达式过滤路径 ...

  4. Thymeleaf入门——入门与基本概述

    https://www.cnblogs.com/jiangbei/p/8462294.html 一.概述 1.是什么 简单说, Thymeleaf 是一个跟 Velocity.FreeMarker 类 ...

  5. Kvm--02 安装centos6系统 ,kvm磁盘管理

    目录 1.安装一个CentOS6的系统的虚拟主机 2.虚拟机的备份 3.企业案例: 4.Kvm磁盘管理 1.安装一个CentOS6的系统的虚拟主机 #上传一个CenOS6系统的镜像到/opt目录下 [ ...

  6. Git --05 Gitlab使用

    目录 Gitlab使用 01. 外观配置 02. Gitlab汉化配置 03. 注册限制 04. 创建用户及组 05. 创建用户 06. 把用户添加到组 07. 创建项目 08. 推送代码到Gitla ...

  7. 四、Angular新建组件和使用

    1.新建组件命令 ng component 组件路径 如果报错换成 ng generate component 组件路径 2.组件 ts 文件详解 3.组件会自动引入到app.mudule.ts里面 ...

  8. HTML基础iframe 实现聚合浏览器

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...

  9. 非阻塞套接字与IO多路复用(转,python实现版)

    非阻塞:指在不能立刻得到结果之前,该函数不会阻塞当前线程,而会立刻返回.epoll工作在非阻塞模式时,才会发挥作用. 我们了解了socket之后已经知道,普通套接字实现的服务端的缺陷:一次只能服务一个 ...

  10. vue2.0 使用 vue-aplayer

    1.安装 npm i vue-aplayer 2.引入 import VueAplayer from 'vue-aplayer' name: "Aplayer", props: [ ...