Linux内核调试技术之Kprobes

合集下载

使用Kprobes(转)

使用Kprobes(转)

使用Kprobes调试内核将printk插入到运行中的Linux 内核Prasanna S. Panchamukhi, 开发人员,Linux Technology Center, IBM India Software Labs 简介:使用printk收集Linux ™ 内核的调试信息是一个众所周知的方法——而使用了Kprobes,不需要经常重新引导和重新编译内核就可以完成这一任务。

Kprobes与2.6 内核结合起来提供了一个动态插入printk's的轻量级、无干扰而且强大的装置。

记录调试信息(比如内核栈追踪、内核数据结构和寄存器)日志从来没有这么简单过!本文的标签:tools标记本文!发布日期: 2004 年9 月19 日级别:初级访问情况: 5004 次浏览评论: 0 (查看 | 添加评论 - 登录)平均分(7个评分)为本文评分Kprobes是Linux 中的一个简单的轻量级装置,让您可以将断点插入到正在运行的内核之中。

Kprobes提供了一个强行进入任何内核例程并从中断处理器无干扰地收集信息的接口。

使用Kprobes可以轻松地收集处理器寄存器和全局数据结构等调试信息。

开发者甚至可以使用Kprobes来修改寄存器值和全局数据结构的值。

为完成这一任务,Kprobes向运行的内核中给定地址写入断点指令,插入一个探测器。

执行被探测的指令会导致断点错误。

Kprobes钩住(hook in)断点处理器并收集调试信息。

Kprobes甚至可以单步执行被探测的指令。

安装要安装Kprobes,需要从Kprobes主页下载最新的补丁(参阅参考资料中的链接)。

打包的文件名称类似于kprobes-2.6.8-rc1.tar.gz。

解开补丁并将其安装到Linux 内核:$tar -xvzf kprobes-2.6.8-rc1.tar.gz$cd /usr/src/linux-2.6.8-rc1$patch -p1 < ../kprobes-2.6.8-rc1-base.patchKprobes利用了SysRq键,这个DOS 时代的产物在Linux 中有了新的用武之地(参阅参考资料)。

ftrace hook函数

ftrace hook函数

ftrace hook函数一、概述ftrace是Linux内核中的一个跟踪框架,它提供了一种轻量级的方法来监控内核函数的调用。

在ftrace中,可以通过hook函数来实现对内核函数的跟踪。

本文将详细介绍如何编写ftrace hook函数,并提供一个全面的详细的函数。

二、编写ftrace hook函数1. 确定要跟踪的内核函数首先,需要确定要跟踪的内核函数。

可以通过查看内核源代码或使用工具(如SystemTap)来确定需要跟踪的函数。

2. 编写hook函数接下来,需要编写hook函数。

在Linux内核中,可以使用两种方式来编写hook函数:kprobes和uprobes。

kprobes是一种在内核代码中插入probe点(即断点)并执行用户定义回调函数的技术。

通过kprobes,可以实现对任意内核代码段进行跟踪。

uprobes是一种在用户空间程序中插入probe点并执行用户定义回调函数的技术。

通过uprobes,可以实现对用户空间程序中任意代码段进行跟踪。

本文将以kprobes为例进行讲解。

3. 注册hook函数注册hook函数时,需要指定要跟踪的内核函数和回调函数。

可以使用以下代码注册hook:```cstatic struct kprobe kp = {.symbol_name = "function_to_trace",.pre_handler = pre_handler,};int register_hook(void)int ret;ret = register_kprobe(&kp);if (ret < 0) {printk(KERN_ERR "Failed to register kprobe\n");return ret;}printk(KERN_INFO "Registered kprobe forfunction_to_trace\n");return 0;}```在上述代码中,kp是一个kprobe结构体,其中symbol_name字段指定要跟踪的内核函数名,pre_handler字段指定回调函数。

Linux内核调试和工具使用

Linux内核调试和工具使用

Linux内核调试和工具使用1.摘要Linux内核调试跟普通用户态c程序调试的工作有点不同,如果所添加或修改代码是以模块形式加载于内核,则除了编码过程中包含的头文件、各种锁、信号量不同外,跟用户态的c程序的调试工作也没什么差别;但如果所修改代码是必须直接加入内核,并且会随linux系统启动而启动,则为了更容易调试,免于因代码错误系统死机而无法获得bug环境,就得使用kgdb远程调试或通过串口信将打印信息打印到另一台机子上。

本文主要介绍在虚拟机上进行linux内核调试时一些常用工具的使用和可能经常会遇到的一些问题的解决方法。

编写此份文档的目的是为了不让一部分同事对linux内核编译从未知开始摸索(将花费大量时间),提高工作效率。

本文档知识量不高,主要是针对从未接触过linux内核编码的同事使用。

2.Linux内核中编码注意项事1.不同版本的内核源码,相同模块中的部分代码可能不同,如一些头文件或接口所在位置或参数可能不同,因此在编码前要确定在哪一个版本中编码,否者在不同版本进行代码移植时出现莫名其妙的bug是件令人头痛的事情。

Linux的内核源码放在/usr/src/ 或/usr/src/kernels中,查看当前系统所使用的内核的命令是:uname –r3.调试相关工具使用简介3.1.samba工具共享文件夹Samba是在Linux和UNIX系统上实现SMB协议的一个免费软件,由服务器及客户端程序构成。

samba是一个工具套件,在Unix上实现SMB(Server Message Block)协议,或者称之为NETBIOS/LanManager协议.SMB协议通常是被windows 系列用来实现磁盘和打印机共享.1.安装samba工具时,首先要确保虚拟机与pc能够相互ping通,虚拟机有自己的的ip,同时虚拟机的连接模式是bridged,虚拟机不能上外网没关系。

Pc:虚拟机:2.如果是redhat的linxu系统,一般都装好了samba的图形界面软件,我用的是centos,是redhat其中一个版本,所以也有带。

Linux内核调试工具Kprobe机制的研究

Linux内核调试工具Kprobe机制的研究

Linux内核调试工具Kprobe机制的研究李清干* 邵作之(华北电力大学计算机科学与技术学院,北京 102206)摘 要:在传统内核调试过程中,我们经常使用print k作为内核调试的一种方法,但这种方法执行速度相对较慢,在对响应时间要求比较严格的内核控制路径(如中断)中不宜采用它。

Kprobe(K erne l probe)与2 6内核结合起来提供了一个动态插入pri n t k的轻量级、无干扰而且强大的装置,使用K probe不需要经常重新引导和重新编译内核就可以完成这一任务。

本文重点介绍K probe调试机制原理以及同内核接口。

关键词:L inux内核;K probe;探测点一、Kp robe机制简介K probe是IB M公司开发的一个轻量级调试工具,它允许内核运行时通过加载模块设置探测器,内核运行到探测点时便执行其相应的处理函数,这是以前的所有工具都做不到的。

K probe作为一个动态地收集调试和性能信息的工具,它从Dprobe项目派生而来,是一种非破坏性工具,用户用它几乎可以跟踪任何函数或被执行的指令以及一些异步事件(如ti m er)。

它的基本工作机制是:用户指定一个探测点,并把一个用户定义的处理函数关联到该探测点,当内核执行到该探测点时,相应的关联函数被执行,然后继续执行正常的代码路径。

使用K probe可以轻松地通过收集处理器寄存器和全局数据结构等调试信息。

开发者甚至可以使用K probe来修改寄存器值和全局数据结构的值。

K probe实现了三种类型的探测点:kprobes、j probes和kretprobes(也叫返回探测点)。

kprobes是可以被插入到内核的任何指令位置的探测点,j probes则只能被插入到一个内核函数的入口,而kre t probes则是在指定的内核函数返回时才被执行。

这三种类型可以用在不同情况的上下文中。

二、Kp robe机制实现原理当安装一个kprobes探测点时,K probe首先备份被探测的指令,然后使用断点指令(即在i386和x86_64的i nt3指令)来取代被探测指令的头一个或几个字节。

Linux内核调试技术——kprobe使用与实现

Linux内核调试技术——kprobe使用与实现

Linux内核调试技术——kprobe使用与实现一、kprobes技术背景开发人员在内核或者模块的调试过程中,往往会需要要知道其中的一些函数有无被调用、何时被调用、执行是否正确以及函数的入参和返回值是什么等等。

比较简单的做法是在内核代码对应的函数中添加日志打印信息,但这种方式往往需要重新编译内核或模块,重新启动设备之类的,操作较为复杂甚至可能会破坏原有的代码执行过程。

而利用kprobes技术,用户可以定义自己的回调函数,然后在内核或者模块中几乎所有的函数中(有些函数是不可探测的,例如kprobes自身的相关实现函数,后文会有详细说明)动态的插入探测点,当内核执行流程执行到指定的探测函数时,会调用该回调函数,用户即可收集所需的信息了,同时内核最后还会回到原本的正常执行流程。

如果用户已经收集足够的信息,不再需要继续探测,则同样可以动态的移除探测点。

因此kprobes技术具有对内核执行流程影响小和操作方便的优点。

kprobes技术包括的3种探测手段分别时kprobe、jprobe和kretprobe。

首先kprobe是最基本的探测方式,是实现后两种的基础,它可以在任意的位置放置探测点(就连函数内部的某条指令处也可以),它提供了探测点的调用前、调用后和内存访问出错3种回调方式,分别是pre_handler、post_handler和fault_handler,其中pre_handler函数将在被探测指令被执行前回调,post_handler会在被探测指令执行完毕后回调(注意不是被探测函数),fault_handler会在内存访问出错时被调用;jprobe基于kprobe实现,它用于获取被探测函数的入参值;最后kretprobe从名字种就可以看出其用途了,它同样基于kprobe实现,用于获取被探测函数的返回值。

kprobes的技术原理并不仅仅包含存软件的实现方案,它也需要硬件架构提供支持。

其中涉及硬件架构相关的是CPU的异常处理和单步调试技术,前者用于让程序的执行流程陷入到用户注册的回调函数中去,而后者则用于单步执行被探测点指令,因此并不是所有的架构均支持,目前kprobes技术已经支持多种架构,包括i386、x86_64、ppc64、ia64、sparc64、arm、ppc和mips(有些架构实现可能并不完全,具体可参考内核的Documentation/kprobes.txt)。

Linux内核参数及Oracle相关参数调整

Linux内核参数及Oracle相关参数调整

Linux内核参数及Oracle相关参数调整修改内核参数的⽅法RedHat向管理员提供了⾮常好的⽅法,使我们可以在系统运⾏时更改内核参数,⽽不需要重新引导系统。

这是通过/proc虚拟⽂件系统实现的。

/proc/sys⽬录下存放着⼤多数的内核参数,并且设计成可以在系统运⾏的同时进⾏更改。

更改⽅法有两种:⽅法⼀:修改/proc/sys⽬录下的相应⽂件,⽐如:/proc/sys/net/ipv4/ip_forward,修改后⽴刻可⽤,不⽤重启系统,但重启系统,会恢复到默认值。

⽅法⼆:修改/etc/sysctl.conf ⽂件,该⽂件中以(变量=值)的形式设置内核参数,修改后,不能⽴刻⽣效,需要执⾏/sbin/sysctl –p 命令,使配置⽂件⽣效。

注意: /etc/sysctl.conf和/proc/sys下的⽂件其实都对应着⼀个参数,它们之间的对应关系,有简单规则:将/proc/sys中的⽂件转换成sysctl中的变量的规则:1.去掉前⾯部分/proc/sys2.将⽂件名中的斜杠变为点这两条规则可以将/proc/sys中的任⼀⽂件名转换成sysctl中的变量名。

例如:/proc/sys/net/ipv4/ip_forward =》 net.ipv4.ip_forward/proc/sys/kernel/hostname =》 kernel.hostname可以使⽤下⾯命令查询所有可修改的变量名例⼦:以打开内核的转发功能。

IP转发是指允许系统对来源和⽬的地都不是本机的数据包通过⽹络,RedHat默认屏蔽此功能,在需要⽤本机作为路由器、NAT等情况下需要开启此功能。

⽅法⼀:修改/proc下内核参数⽂件内容直接修改内核参数ip_forward对应在/proc下的⽂件/proc/sys/net/ipv4/ip_forward。

⽤下⾯命令查看ip_forward⽂件内容:# cat /proc/sys/net/ipv4/ip_forward该⽂件默认值0是禁⽌ip转发,修改为1即开启ip转发功能。

Linux内核调试机制源代码分析

Linux内核调试机制源代码分析

kimage_entry_t *entry; kimage_entry_t *last_entry; unsigned long destination; unsigned long start; struct page *control_code_page; struct page *swap_page; unsigned long nr_segments; struct kexec_segment segment[KEXEC_SEGMENT_MAX]; /*段数组*/ struct list_head control_pages; struct list_head dest_pages; struct list_head unuseable_pages; /* 分配给崩溃内核的下一个控制页的地址*/ unsigned long control_page; /* 指定特殊处理的标识*/ unsigned int type : 1; #define KEXEC_TYPE_DEFAULT 0 #define KEXEC_TYPE_CRASH 1 unsigned int preserve_context : 1; };
内核 kexec 接口函数说明如下:
extern void machine_kexec(struct kimage *image); /*启动内核映像*/ extern int machine_kexec_prepare(struct kimage *image); /*建立内核映 像所需要的控制页*/ extern void machine_kexec_cleanup(struct kimage *image); extern asmlinkage long sys_kexec_load(unsigned long entry, unsigned long nr_segments, struct kexec_segment __user *segments, unsigned long flags); /*装 载内核的系统调用*/ extern int kernel_kexec(void); /*启动内核*/

kprobe

kprobe

通过kprobe跟踪do_execve函数的执行环境 (2012-07-12 14:56)标签: 转载原文地址:通过kprobe跟踪do_execve函数的执行环境作者:MagicBoy2010kprobe可以动态跟踪某一内核函数的执行情况而无需修改内核,当然为了达到这样目的,我们需要自己写一个小的内核模块,不过这也要比修改内核源码要来得方便的多,我觉得这种方法可以形象地称之为“无损探测”。

下面是利用<<DEBUG HACKS>>中的一小段代码,经过适当改写完善,来探测一个U盘加入系统时,do_execve所执行的环境参数。

kprobe的原理大约是在执行被探测函数前先行获得控制权,执行内核模块所注册的回调函数,之后再把控制权转给被探测的函数,这个原理很有意思,有进一步分析的必要。

以下是内核模块代码:1.#include <linux/module.h>2.#include <linux/kprobes.h>3.#include <linux/kallsyms.h>4.5.struct kprobe kp;6.7.int handler_pre(struct kprobe *p, struct pt_regs *regs)8.{9.printk(KERN_INFO "|pid: %6d |comm: %10s |filename = %10s|\n",10.current->pid, current->comm,(char *)regs->di);11.return 0;12.}13.14.static __init int init_kprobe_sample(void)15.{16.kp.symbol_name ="do_execve";17.kp.pre_handler = handler_pre;18.register_kprobe(&kp);19.printk(KERN_INFO "---------------kprobe forexecve--------------\n");20.return 0;21.}22.23.static __exit void cleanup_kprobe_sample(void)24.{25.unregister_kprobe(&kp);26.}27.28.module_init(init_kprobe_sample);29.module_exit(cleanup_kprobe_sample);30.31.MODULE_LICENSE("GPL");insmod这个模块之后,探测活动就正式开始了,下面是往系统插入一个U盘时,kprobe回调函数的输出:1.root@build-server:/home/dennis/debug/kprobe# dmesg -c2.[10370.912471]usb 1-1.3:new high-speed USB device number 9 usingehci_hcd3.[10370.988796]|pid: 3296 |comm: kworker/u:3 |filename =/sbin/myhotplug|4.[10370.989038]|pid: 3297 |comm: kworker/u:3 |filename =/sbin/myhotplug|5.[10370.989146]|pid: 3298 |comm: udevd |filename =/lib/udev/mtp-probe|6.[10370.989192]|pid:3299 |comm:myhotplug |filename =/bin/touch|7.[10370.989496]|pid:3300 |comm:myhotplug |filename =/bin/touch|8.[10370.989730] scsi11 : usb-storage 1-1.3:1.09.[10370.989768]|pid: 3303 |comm: kworker/u:3 |filename =/sbin/myhotplug|10.[10370.989861]|pid: 3304 |comm: kworker/u:3 |filename =/sbin/myhotplug|11.[10370.990137]|pid:3305 |comm:myhotplug |filename =/bin/touch|12.[10370.990212]|pid:3306 |comm:myhotplug |filename =/bin/touch|13.[10371.249360]|pid: 3307 |comm: udevd |filename =/lib/udev/usb_id|14.[10371.992667] scsi 11:0:0:0: Direct-Access TOSHIBA TransMemory1.00 PQ: 0 ANSI: 215.[10371.992972]|pid: 3309 |comm: kworker/u:3 |filename =/sbin/myhotplug|16.[10371.993341]|pid:3310 |comm:myhotplug |filename =/bin/touch|17.[10371.993360]|pid: 3311 |comm: kworker/u:3 |filename =/sbin/myhotplug|18.[10371.993636]|pid:3312 |comm:udevd |filename =/sbin/modprobe|19.[10371.993712]|pid:3313 |comm:myhotplug |filename =/bin/touch|20.[10371.993777]|pid: 3314 |comm: kworker/u:3 |filename =/sbin/myhotplug|21.[10371.994364]|pid: 3316 |comm: kworker/u:2 |filename =/sbin/myhotplug|22.[10371.994563]|pid:3317 |comm:myhotplug |filename =/bin/touch|23.[10371.994797]|pid: 3318 |comm: kworker/u:2 |filename =/sbin/myhotplug|24.[10371.994830] sd 11:0:0:0: Attached scsi generic sg3 type 025.[10371.994886]|pid: 3319 |comm: kworker/u:2 |filename =/sbin/myhotplug|26.[10371.995249]|pid:3320 |comm:myhotplug |filename =/bin/touch|27.[10371.995506]|pid:3321 |comm:myhotplug |filename =/bin/touch|28.[10371.995538]|pid:3322 |comm:myhotplug |filename =/bin/touch|29.[10371.995786]sd 11:0:0:0:[sdc]15654848 512-byte logical blocks:(8.01 GB/7.46 GiB)30.[10371.996281] sd 11:0:0:0:[sdc] Write Protect is off31.[10371.996282] sd 11:0:0:0:[sdc] Mode Sense: 65 44 09 3032.[10371.996788] sd 11:0:0:0:[sdc] No Caching mode page present33.[10371.996862] sd 11:0:0:0:[sdc] Assuming drive cache: writethrough34.[10371.996996]|pid: 3323 |comm: kworker/u:2 |filename =/sbin/myhotplug|35.[10371.997387]|pid:3324 |comm:myhotplug |filename =/bin/touch|36.[10371.999537] sd 11:0:0:0:[sdc] No Caching mode page present37.[10371.999609] sd 11:0:0:0:[sdc] Assuming drive cache: writethrough38.[10372.000283] sdc: sdc139.[10372.000358]|pid: 3325 |comm: kworker/u:2 |filename =/sbin/myhotplug|40.[10372.000458]|pid: 3326 |comm: kworker/u:2 |filename =/sbin/myhotplug|41.[10372.000711]|pid:3327 |comm:myhotplug |filename =/bin/touch|42.[10372.000820]|pid:3328 |comm:myhotplug |filename =/bin/touch|43.[10372.000865]|pid: 3329 |comm: udevd |filename =/lib/udev/usb_id|44.[10372.001676]|pid: 3330 |comm: udevd |filename =/lib/udev/path_id|45.[10372.002411] sd 11:0:0:0:[sdc] No Caching mode page present46.[10372.002459]|pid: 3331 |comm: udevd |filename =/sbin/blkid|47.[10372.002484] sd 11:0:0:0:[sdc] Assuming drive cache: writethrough48.[10372.002564] sd 11:0:0:0:[sdc] Attached SCSI removable disk49.[10372.066849]|pid: 3332 |comm: udevd |filename =/lib/udev/udisks-part-id|50.[10372.070023]|pid: 3333 |comm: udevd |filename =/lib/udev/hdparm|51.[10372.070633]|pid: 3334 |comm: hdparm |filename =/bin/grep|52.[10372.071212]|pid: 3335 |comm: hdparm |filename =/bin/egrep|53.[10372.071930]|pid: 3337 |comm: hdparm |filename =/bin/egrep|54.[10372.073162]|pid: 3339 |comm: udevd |filename =/sbin/blkid|55.[10372.127677]|pid: 3341 |comm: udevd |filename =/lib/udev/udisks-part-id|56.[10373.752620]|pid: 3342 |comm: bash |filename =/bin/dmesg|如果仔细分析上面的输出,会发现不少有趣的信息,比如udevd与mtp-probe,hdparm等等。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
Linux内核调试技术之Kprobes
郭海林
2012.11.17
Kprobe 简介
• kprobe是一个动态地收集调试和性能信息的工具 • 从Dprobe项目派生而来,是一种非破坏性工具 • Linux下的Systemtap依赖的基础是kprobe • 实现了三种类型的探测点: kprobes, jprobes和kretprobes
来实现探测处理的
• 当kprobe注册的notifier被执行时
– 首先,执行关联到探测点的pre_handler函数
• 把相应的kprobe struct和保存的寄存器作为该函数的参数
– 其次,kprobe单步执行被探测指令的备份 – 最后,kprobe执行post_handler
• 等所有这些运行完毕后,紧跟在被探测指令后的指令流将被正常执行
• Gaining insight into the Linux® kernel with Kprobes
– /magazine/005mar05/features/kprobes/
• kprobes tutorial
– /~boutcher/kprobes/
• An introduction to KProbes
– /Articles/132196/
• 《Debug Hacks中文版—深入调试的技术和工具》 • Linux内核中Kprobes调试技术的实现
– /2008/11/821.html
– grep do_fork /boot/System.map-xxx
• 使用 nm 命令
– nm /boot/vmlinuz-xxx | grep do_fork
• 从 /proc/kallsyms 文件获得地址
– cat /proc/kallsyms | grep do_fork
• 使用 kallsyms_lookup_name() 函数
• Linux kernel documentation, Documentation/kprobes.txt
Thank You for Listening!
Understanding the Linux Kernel Read the fucking source code!
– 探测内核函数、全局变量 – 探测函数的参数
kprobes 应用实例(3)
• 利用kprobes 探测内核内部任意位置的信息(见kprobe_anyaddr.c)
– 如何获得任意位置的地址
• 找到与函数的开始位置的偏移
参考资料
• Kernel debugging with Kprobes
– /developerworks/library/l-kprobes/index.html
• Linux下的一个全新的性能测量和调式诊断工具Systemtap,第1部分:kprobe
– https:///developerworks/cn/linux/l-cn-systemtap1/
• 通过kprobe跟踪do_execve函数的执行环境
– /forum.php?mod=viewthread&tid=586
• 错误处理函数
– int fault_handler(struct kprobe *p, struct pt_regs *regs, int trapnr);
• 探测点卸载
– void unregister_kprobe(struct kprobe *kp);
获得内核函数探测地址的方法
• 从 System.map 文件直接得到地址
– kprobes是可以被插入到内核的任何指令位置的探测点 – jprobes则只能被插入到一个内核函数的入口 – kretprobes则是在指定的内核函数返回时才被执行
下面介绍kprobes 的工作机制 / 实现 / 实例。
kprobes工作机制(1)
kprobes工作机制(2)
• 安装一个kprobes探测点时
– kallsyms_lookup_name("do_fork")
kprobes 应用实例(1)
• kprobes 示例程序(见kprobe_example.c)
– kprobes 探测程ห้องสมุดไป่ตู้框架 – kprobes 探测的原理
kprobes 应用实例(2)
• 利用kprobes 探测内核函数与变量(见kprobe_doexecve.c)
kprobes 实现——数据结构
kprobes 实现——接口函数
• 注册探测点
– int register_kprobe(struct kprobe *kp);
• 探测点处理函数
– int pre_handler(struct kprobe *p, struct pt_regs *regs); – void post_handler(struct kprobe *p, struct pt_regs *regs, unsigned long flags);
– kprobe首先备份被探测的指令 – 使用断点指令(int3指令)来取代被探测指令的头一个或几个字节
• CPU执行到探测点时
– 将因运行断点指令而执行trap操作
• 导致保存CPU的寄存器 • 调用相应的trap处理函数
– trap处理函数将调用相应的notifier_call_chain中注册的所有notifier函数 – kprobe正是通过向trap对应的notifier_call_chain注册关联到探测点的处理函数
相关文档
最新文档