当前位置:首页>Linux>Linux内核调试工具:kprobe使用与实现

Linux内核调试工具:kprobe使用与实现

  • 2026-02-24 18:12:40
Linux内核调试工具:kprobe使用与实现

在 Linux 系统的广袤世界里,内核调试就像是一位幕后英雄,默默支撑着整个系统的稳定运行与高效表现。无论是系统性能的优化,还是故障排查,内核调试都扮演着不可或缺的角色。想象一下,当你的服务器突然出现卡顿,或者某个关键服务莫名崩溃,这时候,精准的内核调试技术就如同黑暗中的明灯,帮助你快速定位问题,解决故障。而在众多的内核调试技术中,kprobe 无疑是一颗耀眼的明星。它是 Linux 内核提供的一种动态调试机制,允许开发者在不修改内核源码、不重启系统的情况下,对内核函数进行探测。

这就好比在不拆开精密仪器的前提下,能够直接观察其内部关键部件的运转情况,是不是很神奇?kprobe 的出现,极大地改变了内核调试的方式。在它诞生之前,开发者若要调试内核函数,往往需要在函数中添加大量的打印语句,然后重新编译内核,再重启系统才能生效。这个过程不仅繁琐耗时,还可能因为频繁重启影响到线上业务的正常运行。而 kprobe 则打破了这些限制,让内核调试变得更加灵活高效,随时随地都能对内核函数进行监测与分析 。

一、初相识 kprobe

1.1 kprobe 是什么

kprobe,即 Kernel Probes,是 Linux 内核精心打造的一种极为强大的动态跟踪技术 。它就像是一个灵活的 “观察者”,赋予开发者在不修改内核代码、不重启整个系统的前提下,于内核函数的特定位置巧妙插入探测点的神奇能力。这些探测点就如同一个个 “小哨兵”,实时监控着内核函数的一举一动。

当内核执行的流程运行到我们预先设置好的探测点时,kprobe 会迅速做出反应,执行我们提前定义好的处理函数。这个处理函数可以根据我们的需求,完成各种各样的任务,比如精准地记录下函数的参数值,实时监测函数的执行时间,甚至还能在必要时对函数的执行逻辑进行巧妙的干预。通过这种方式,开发者能够获取到丰富的内核执行信息,从而为深入理解内核的运行机制、高效排查系统故障以及精准优化系统性能提供了坚实有力的支持 。

1.2 kprobe 的类型

kprobe 主要包含三种类型,它们各自有着独特的功能和应用场景,就像一个团队里不同分工的成员,共同协作完成内核调试的任务。

  1. kprobes:作为 kprobe 家族中最基础、最通用的成员,kprobes 拥有令人惊叹的灵活性,它几乎可以被插入到内核的任意指令位置。想象一下,内核代码就像一条长长的生产线,kprobes 能够在这条生产线的任何一个环节设置 “观测点”。当内核执行到这个探测点时,就会如同触发了一个预设的机关,依次执行我们精心编写的 pre_handler 函数和 post_handler 函数。pre_handler 函数就像是在任务开始前的准备工作,它可以在指令执行前,对现场环境进行详细的记录,比如记录下当前寄存器的状态,获取函数的参数值等,为后续的分析提供第一手资料。而 post_handler 函数则像是任务结束后的总结汇报,它会在指令执行完毕后,对执行结果进行进一步的处理和分析,比如统计函数执行的时间,检查执行结果是否符合预期等。通过这两个函数的紧密配合,我们能够全方位地了解内核函数在执行过程中的各种细节信息 。
  2. jprobes:jprobes 相对来说比较 “专一”,它只能被插入到内核函数的入口处,就像是一个站在函数大门前的 “守卫”,专门负责迎接函数的启动。虽然它的插入位置相对固定,但它的作用却不可小觑。jprobes 的主要职责是帮助我们轻松获取函数的参数。当函数开始执行时,jprobes 会迅速行动,将函数的参数完整地 “收集” 起来,传递给我们的处理函数。这在很多场景下都非常有用,比如当我们需要分析某个函数在不同参数输入下的行为时,jprobes 就能为我们提供准确的参数信息,让我们的分析更加有的放矢 。需要注意的是,jprobes 处理函数的原型必须与被探测函数完全一致,就像是两个配合默契的搭档,只有这样,jprobes 才能准确无误地获取函数参数,并顺利完成后续的处理工作 。
  3. kretprobes:kretprobes 则专注于函数的返回阶段,就像是在函数执行结束后进行 “收尾工作” 的 “监督员”。它会在指定的内核函数返回时被触发执行,主要用于获取函数的返回值,以及精确计算函数的执行时间。当函数执行到返回指令时,kretprobes 会巧妙地捕获这个关键时刻,获取到函数的返回值,并根据之前记录的函数开始执行的时间点,精确计算出函数的执行耗时。这对于性能分析来说是非常关键的信息,通过分析不同函数的执行时间,我们可以快速定位到系统中的性能瓶颈,进而有针对性地进行优化 。在使用 kretprobes 时,我们需要注意设置合适的 maxactive 字段,它决定了被探测函数可以被同时探测的实例数,合理设置这个值可以避免因资源不足而导致的探测点执行丢失问题 。

二、kprobe 工作原理

2.1 基于 int3 的 kprobe 实现

在 x86 架构的系统中,CPU 提供了一条特殊的单字节指令 INT3,其机器码为 0xcc ,专门用于触发调试异常(#BP,向量号 3),这就像是一个预先设定好的 “警报器”。而 kprobe 正是巧妙地借用了这个 “警报器” 来实现对内核函数的探测。

当我们通过 register_kprobe()函数注册一个 kprobe 探测点时,一场精心策划的 “指令替换行动” 就开始了。kprobe 子系统会迅速行动,首先精准地查找我们指定符号对应的虚拟地址,这个地址就是我们想要探测的内核函数的关键位置。找到地址后,它会小心翼翼地将该地址处的第一个字节备份起来,这就好比是给原指令拍了一张 “照片”,以便后续恢复。然后,它会写入 0xcc,用这个断点指令替代原指令的第一个字节,就像是在原来的指令轨道上放置了一个特殊的 “路障” 。同时,kprobe 子系统还会建立异常处理关联,确保当 CPU 执行到这个被替换为 0xcc 的位置时,能够顺利进入 kprobe 的处理流程 。

一旦 CPU 执行到这个被设置了断点指令的位置,就如同触发了警报一样,会立即抛出 #BP 异常,然后转入 do_int3()异常处理函数。而此时,kprobe 早已通过 int3_handler 注册了自己的钩子。在这个钩子函数中,它会获取当前 CPU 寄存器的状态,这些寄存器就像是记录着内核执行过程的 “小账本”,里面包含了程序计数器(RIP)、栈指针(RSP)、标志寄存器(RFLAGS)等重要信息 。接着,kprobe 会根据这些寄存器的信息,准确地找到对应的 kprobe 结构体,这个结构体就像是一个 “任务清单”,记录了我们为这个探测点设置的各种信息,比如 pre_handler、post_handler 等处理函数的地址 。

在找到 kprobe 结构体后,kprobe 会先执行 pre_handler 函数,这个函数就像是一场演出前的 “预热表演”,它可以在指令执行前,对现场环境进行详细的记录和分析,比如记录下当前寄存器的状态,获取函数的参数值等 。执行完 pre_handler 函数后,kprobe 会恢复原始指令的一个副本,并设置 CPU 进入单步执行模式。在单步执行模式下,CPU 会一条一条地执行指令,这样 kprobe 就可以精确地监控指令的执行过程 。

当原始指令执行完毕后,kprobe 会执行 post_handler 函数,这个函数就像是演出结束后的 “总结发言”,它会对指令的执行结果进行进一步的处理和分析,比如统计函数执行的时间,检查执行结果是否符合预期等 。最后,kprobe 会恢复正常的指令执行流程,让内核继续按照原来的计划运行 。

2.2 kretprobe 的实现机制

kretprobe 的实现同样巧妙,它主要利用了 kprobes 在函数入口处设置探测点的能力 。当我们调用 register_kretprobe()函数来注册一个 kretprobe 时,实际上是在被探测函数的入口处建立了一个 kprobe 探测点 。

当内核执行到这个位于函数入口的探测点时,kprobe 会迅速行动,它会保存被探测函数的返回地址,这个返回地址就像是函数执行结束后要回到的 “家” 的地址。然后,kprobe 会将返回地址替换为一个预先定义好的 trampoline 地址 。这个 trampoline 就像是一个 “中转站”,当函数执行到返回指令时,控制流会被引导到这个 “中转站” 。

在 kprobe 初始化的时候,就已经为这个 trampoline 注册了一个 kprobe,并且关联了相应的处理函数 。当被探测函数执行到返回指令时,控制传递到 trampoline,此时 kprobe 注册的对应于 trampoline 的处理函数就会被执行 。这个处理函数会调用我们用户关联到该 kretprobe 上的处理函数,在这个处理函数中,我们可以获取函数的返回值,以及计算函数的执行时间等 。处理完毕后,kprobe 会设置指令寄存器指向已经备份的函数返回地址,就像是给函数指明了回家的路,让原来的函数返回能够正常执行 。

在这个过程中,被探测函数的返回地址会被保存在类型为 kretprobe_instance 的变量中,这个变量就像是一个 “包裹”,里面装着与被探测函数执行实例相关的重要信息 。kretprobe 结构体中的 maxactive 字段则指定了被探测函数可以被同时探测的实例数,这就像是一个 “容量限制器”,它决定了在同一时间内能够被 kretprobe 跟踪的函数执行实例的最大数量 。

当我们调用 register_kretprobe()函数时,会预先分配指定数量的 kretprobe_instance,以确保有足够的 “包裹” 来存放每个被探测函数执行实例的相关信息 。如果 maxactive 设置得太小,当被探测函数的调用非常频繁,同时有大量的执行实例需要被跟踪时,就可能会出现一些探测点的执行被丢失的情况 。不过,不用担心,kretprobe 结构体中的 nmissed 字段会忠实地记录下这些被丢失的探测点执行数,它就像是一个 “记录员”,在返回探测点被注册时,nmissed 会被设置为 0,每次当执行探测函数而没有可用的 kretprobe_instance 时,它就会加 1,通过查看这个字段的值,我们就可以知道是否存在探测点执行丢失的情况,以及丢失的数量 。

三、kprobe 使用指南:从基础到进阶

3.1 环境准备

在正式开启 kprobe 的探索之旅前,我们得先做好一系列的环境准备工作,就像是一场冒险前要准备好装备一样。首先,要确保你的内核已经开启了 CONFIG_KPROBE_EVENT 选项。这一步至关重要,它就像是打开 kprobe 大门的钥匙。你可以通过查看内核配置文件(通常位于/boot/config-版本号 )来确认这一点,如果文件中存在 CONFIG_KPROBE_EVENT=y,那就说明该选项已经开启。要是没有找到,你可能需要重新编译内核并开启此选项 。

另外,挂载 debugfs 也是必不可少的步骤。debugfs 是一个特殊的文件系统,专门用于调试,它就像是一个调试工具的 “仓库”。使用以下命令挂载 debugfs:

mount -t debugfs none /sys/kernel/debug

这行命令会将 debugfs 挂载到/sys/kernel/debug 目录下,为后续使用 kprobe 提供了必要的文件系统支持 。

3.2 使用 debugfs 创建 kprobe

(1)挂载与进入目录:在完成 debugfs 的挂载后,我们需要进入 kprobes 目录,这里是我们设置 kprobe 探测点的 “战场”。使用 cd 命令进入:

cd /sys/kernel/debug/kprobes

进入这个目录后,我们就可以开始进行各种与 kprobe 相关的操作了 。

(2)设置探测点:以追踪 do_fork 函数为例,这是一个在进程创建过程中非常关键的函数,追踪它可以让我们深入了解进程创建的细节。设置探测点的命令如下:

echo 『p:myprobe do_fork』 > events

在这个命令中,p 表示我们要创建的是一个普通的 kprobe 探测点;myprobe 是我们给这个探测点取的名字,就像是给一个士兵取个独特的代号,方便我们识别和管理;do_fork 则是我们要探测的目标函数 。通过执行这个命令,我们就在 do_fork 函数上成功设置了一个名为 myprobe 的探测点 。

(3)启用与查看结果:设置好探测点后,还需要启用它,让这个 “小哨兵” 开始工作。启用事件的命令很简单:

echo 1 > events/myprobe/enable

执行这个命令后,myprobe 探测点就正式开始生效,它会密切关注 do_fork 函数的一举一动 。

要查看追踪结果,我们可以查看 trace 文件,这个文件就像是一本 “记录册”,详细记录了 kprobe 探测到的信息:

cat /sys/kernel/debug/tracing/trace

执行这个命令后,你会看到类似下面这样的输出示例:

bash-3285[001] ....  1234.567890: myprobe: (do_fork+0x0/0x320)

在这个输出中,bash-3285 表示触发事件的进程名和进程 ID;[001]表示 CPU 编号;1234.567890 是时间戳,精确记录了事件发生的时间;myprobe 是我们设置的探测点名称;(do_fork+0x0/0x320)则表示是在 do_fork 函数处触发的事件,+0x0 表示在函数的起始位置,0x320 是函数的长度 。通过这些信息,我们可以清晰地了解到 do_fork 函数的调用情况 。

当我们不再需要这个探测点时,还可以禁用并删除它,让系统恢复到之前的状态。禁用探测点的命令是:

echo 0 > events/myprobe/enable

删除探测点的命令是:

echo『myprobe』 > events/unregister

这样,我们就完成了使用 debugfs 创建、启用、查看和删除 kprobe 探测点的整个过程 。

3.3 编写内核模块注册 kprobe

在编写内核模块注册 kprobe 时,struct kprobe 结构体是我们的核心工具,它就像是一个装满了各种调试信息的 “百宝箱”。这个结构体包含了多个重要字段 :

  • symbol_name:用于指定要探测的内核函数名,这是我们定位目标函数的关键信息,就像是给 “百宝箱” 贴上了一个明确的标签 。
  • pre_handler:是一个函数指针,指向在探测点指令执行前被调用的回调函数,这个回调函数就像是一个 “先锋”,在函数执行前进行一些预处理工作,比如记录寄存器状态、获取函数参数等 。
  • post_handler:同样是一个函数指针,指向在探测点指令执行后被调用的回调函数,它就像是一个 “收尾员”,在函数执行后对结果进行处理和分析 。
  • fault_handler:当执行 pre_handler、post_handler 或单步执行被探测指令时出现内存异常,就会调用这个回调函数,它是处理异常情况的 “救火队员” 。

除了 struct kprobe 结构体,register_kprobe 和 unregister_kprobe 函数也非常重要。register_kprobe 函数用于向内核注册一个 kprobe 探测点,就像是把一个新的 “士兵” 编入队伍;unregister_kprobe 函数则用于注销已经注册的 kprobe 探测点,让这个 “士兵” 离开队伍 。

下面是一个监视 do_fork 函数的内核模块代码示例,我们来逐行分析它的逻辑与功能 :

#include <Linux/module.h>#include <Linux/kprobes.h>// 定义 pre_handler 回调函数staticinthandler_pre(struct kprobe *p, struct pt_regs *regs){    printk(KERN_INFO 「Pre handler: %s called\n」, p->symbol_name);    return 0;}// 定义 post_handler 回调函数staticvoidhandler_post(struct kprobe *p, struct pt_regs *regs, unsignedlong flags){    printk(KERN_INFO 「Post handler: %s finished\n」, p->symbol_name);}// 定义 kprobe 结构static struct kprobe kp = {   .symbol_name = 「do_fork」,   .pre_handler = handler_pre,   .post_handler = handler_post,};// 模块初始化函数staticint __init kprobe_init(void){    int ret;    // 注册 kprobe    ret = register_kprobe(&kp);    if (ret < 0) {        printk(KERN_ERR 「Failed to register kprobe\n」);        return ret;    }    printk(KERN_INFO 「Kprobe registered successfully\n」);    return 0;}// 模块退出函数staticvoid __exit kprobe_exit(void){    // 注销 kprobe    unregister_kprobe(&kp);    printk(KERN_INFO 「Kprobe unregistered successfully\n」);}module_init(kprobe_init);module_exit(kprobe_exit);MODULE_LICENSE(「GPL」);

在这段代码中,首先包含了必要的头文件 Linux/module.h 和 Linux/kprobes.h,它们为我们提供了编写内核模块和使用 kprobe 的基本函数和数据结构 。

接着定义了 handler_pre 和 handler_post 两个回调函数。handler_pre 函数在 do_fork 函数执行前被调用,它使用 printk 函数打印一条信息,表明 do_fork 函数即将被调用;handler_post 函数在 do_fork 函数执行后被调用,同样使用 printk 函数打印一条信息,表明 do_fork 函数已经执行完毕 。

然后定义了 kp 这个 kprobe 结构体变量,并对其 symbol_name、pre_handler 和 post_handler 字段进行了初始化,指定要探测的函数是 do_fork,并关联了前面定义的两个回调函数 。

在 kprobe_init 函数中,通过调用 register_kprobe 函数注册 kp 这个 kprobe 探测点,如果注册成功,打印成功信息,否则打印错误信息并返回错误码 。

在 kprobe_exit 函数中,通过调用 unregister_kprobe 函数注销 kp 这个 kprobe 探测点,并打印注销成功的信息 。

最后,使用 module_init 和 module_exit 宏指定模块的初始化和退出函数,同时声明模块的许可证为 GPL 。

编写好内核模块代码后,我们需要编译它,将代码转换为可执行的模块文件。首先,创建一个 Makefile 文件,内容如下:

obj-m += kprobe_module.oall:    make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modulesclean:    make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean

这个 Makefile 文件定义了两个目标:all 和 clean。all 目标用于编译模块,它会调用 make 命令,进入内核源代码目录(通过/lib/modules/$(shell uname -r)/build 指定),并在当前目录($(PWD))下编译模块;clean 目标用于清理编译生成的文件 。

在终端中执行 make 命令,就可以开始编译内核模块。编译完成后,会生成一个名为 kprobe_module.ko 的文件,这就是我们的内核模块文件 。

接下来,使用 insmod 命令加载模块:

sudo insmod kprobe_module.ko

加载模块后,可以通过 dmesg 命令查看内核日志,来验证模块是否加载成功以及查看回调函数的输出信息:

dmesg | tail

如果一切正常,你应该能看到类似下面这样的输出:

[  1234.567890] Kprobe registered successfully[  1235.678901] Pre handler: do_fork called[  1235.678902] Post handler: do_fork finished

这些输出信息表明,我们的 kprobe 模块已经成功注册,并且在 do_fork 函数执行前后,分别调用了 pre_handler 和 post_handler 回调函数 。

当我们不再需要这个模块时,可以使用 rmmod 命令卸载它:

sudo rmmod kprobe_module

这样,我们就完成了编写内核模块注册 kprobe、编译模块、加载模块以及卸载模块的整个过程 。

3.4 结合 perf 和 ftrace 使用 kprobe

(1)perf 工具集成:perf 是 Linux 系统中一个强大的性能分析工具,它就像是一个专业的 “性能检测员”,可以帮助我们深入了解系统的性能状况。当 perf 与 kprobe 结合使用时,更是如虎添翼 。使用 perf probe 可以方便地添加探测点。例如,要在 do_fork 函数上添加探测点,可以执行以下命令:

perf probe -x /vmlinuz do_fork

在这个命令中,-x 参数指定了内核镜像文件/vmlinuz,do_fork 是我们要探测的函数 。执行这个命令后,perf 会在 do_fork 函数上添加一个探测点 。

添加探测点后,我们可以使用 perf record 命令记录事件。例如,记录 10 秒内的 do_fork 事件:

perf record -e 『probe:do_fork』 -a sleep 10

在这个命令中,-e 参数指定了要记录的事件为 probe:do_fork,表示我们要记录 do_fork 函数上的探测点事件;-a 参数表示记录所有 CPU 上的事件;sleep 10 表示记录时间为 10 秒 。

记录完成后,使用 perf script 命令查看结果:

perf script

执行这个命令后,会输出详细的事件记录信息,包括时间戳、CPU 编号、进程 ID、事件类型等,这些信息可以帮助我们分析 do_fork 函数的调用情况和性能表现 。

(2)ftrace 的联动:ftrace 是 Linux 内核中的一个功能强大的跟踪框架,它就像是一个全面的 “跟踪器”,可以跟踪内核的各种活动 。ftrace 可以通过/sys/kernel/debug/tracing/kprobe_events 动态添加事件,与 kprobe 配合使用 。例如,要在 do_fork 函数上添加一个 kprobe 事件,可以执行以下命令:

echo 『p:myprobe do_fork』 > /sys/kernel/debug/tracing/kprobe_events

这个命令的含义与前面使用 debugfs 设置探测点时类似,p 表示添加 kprobe 事件,myprobe 是事件名称,do_fork 是目标函数 。

添加事件后,需要启用 ftrace。首先,进入/sys/kernel/debug/tracing 目录:

cd /sys/kernel/debug/tracing

然后,启用事件:

echo 1 > events/kprobes/myprobe/enable

同时,启用 ftrace:

echo 1 > tracing_on

这样,ftrace 就会开始跟踪 do_fork 函数上的 kprobe 事件 。

要查看跟踪结果,可以查看 trace 文件:

cat trace

通过查看 trace 文件,我们可以获取到 do_fork 函数的调用时间、调用者等详细信息,这些信息对于分析内核行为和性能优化非常有帮助 。

通过结合 perf 和 ftrace 使用 kprobe,我们可以从不同角度对内核函数进行探测和分析,获取更全面、更深入的系统信息,为内核调试和性能优化提供有力支持 。

四、Kprobe 使用实例

4.1 编写简单的 Kprobes 探测模块

接下来,让我们通过一个具体的例子,来深入了解如何编写一个简单的 Kprobes 探测模块。假设我们要探测 do_sys_open 函数,这个函数负责处理系统的文件打开操作,在实际的系统调试中,了解文件打开的具体情况,如文件名、打开标志等信息,对于排查文件相关的问题非常有帮助。以下是详细的代码实现:

#include <Linux/module.h>#include <Linux/kprobes.h>#include <Linux/sched.h>// 定义一个计数器,用于统计函数被调用的次数static int count = 0;// pre_handler 回调函数,在被探测指令执行前被调用staticinthandler_pre(struct kprobe *p, struct pt_regs *regs){    // 从寄存器中获取文件名和标志信息    char *filename = (char *)regs->di;    int flags = (int)regs->si;    // 打印函数调用信息,包括文件名和标志    printk(KERN_INFO 「do_sys_open called with filename=%s, flags=%x\n」, filename, flags);    // 计数器加一    count++;    return 0;}// 定义 kprobe 结构,指定要探测的函数为 do_sys_open,并关联 pre_handler 回调函数static struct kprobe kp = {   .symbol_name = 「do_sys_open」,   .pre_handler = handler_pre,};// 模块初始化函数,用于注册 kprobestaticint __init mymodule_init(void){    int ret;    // 调用 register_kprobe 函数注册 kprobe    ret = register_kprobe(&kp);    if (ret < 0) {        // 如果注册失败,打印错误信息        printk(KERN_INFO 「register_kprobe failed\n」);        return ret;    }    // 如果注册成功,打印成功信息    printk(KERN_INFO 「kprobe registered\n」);    return 0;}// 模块退出函数,用于卸载 kprobestaticvoid __exit mymodule_exit(void){    // 调用 unregister_kprobe 函数卸载 kprobe    unregister_kprobe(&kp);    // 打印卸载信息,包括函数被调用的次数    printk(KERN_INFO 「kprobe unregistered\n」);    printk(KERN_INFO 「do_sys_open called %d times\n」, count);}// 声明模块初始化和退出函数module_init(mymodule_init);module_exit(mymodule_exit);// 指定模块许可证为 GPLMODULE_LICENSE(「GPL」);

在上述代码中,首先定义了一个 count 变量,用于统计 do_sys_open 函数被调用的次数。handler_pre 函数是 pre_handler 回调函数,它从寄存器中获取 do_sys_open 函数的参数 filename 和 flags,并通过 printk 函数打印出来,同时将 count 加一。

然后,创建了一个 struct kprobe 结构体实例 kp,指定要探测的函数为 do_sys_open,并将 handler_pre 函数关联到 kp 的 pre_handler 成员。

在 mymodule_init 函数中,通过 register_kprobe 函数将 kp 注册到内核中,如果注册失败,打印错误信息并返回错误码;如果注册成功,打印成功信息。

在 mymodule_exit 函数中,通过 unregister_kprobe 函数将 kp 从内核中卸载,并打印卸载信息和 do_sys_open 函数被调用的次数。

4.2 基于 ftrace 使用 kprobe

kprobe 和内核的 ftrac 结合使用,需要对内核进行配置,然后添加探测点、进行探测、查看结果。

(1)kprobe 配置:打开「General setup」->「Kprobes」,以及「Kernel hacking」->「Tracers」->「Enable kprobes-based dynamic events」。

CONFIG_KPROBES=yCONFIG_OPTPROBES=yCONFIG_KPROBES_ON_FTRACE=yCONFIG_UPROBES=yCONFIG_KRETPROBES=yCONFIG_HAVE_KPROBES=yCONFIG_HAVE_KRETPROBES=yCONFIG_HAVE_OPTPROBES=yCONFIG_HAVE_KPROBES_ON_FTRACE=yCONFIG_KPROBE_EVENT=y

(3)kprobe trace events 使用。kprobe 事件相关的节点有如下:

/sys/kernel/debug/tracing/kprobe_events-----------------------配置 kprobe 事件属性,增加事件之后会在 kprobes 下面生成对应目录/sys/kernel/debug/tracing/kprobe_profile----------------------kprobe 事件统计属性文件/sys/kernel/debug/tracing/kprobes/<GRP>/<EVENT>/enabled-------使能 kprobe 事件/sys/kernel/debug/tracing/kprobes/<GRP>/<EVENT>/filter--------过滤 kprobe 事件/sys/kernel/debug/tracing/kprobes/<GRP>/<EVENT>/format--------查询 kprobe 事件显示格式

下面就结合实例,看一下如何使用 kprobe 事件。

(3)kprobe 事件配置。新增一个 kprobe 事件,通过写 kprobe_events 来设置。

p[:[GRP/]EVENT] [MOD:]SYM[+offs]|MEMADDR [FETCHARGS]-------------------设置一个 probe 探测点r[:[GRP/]EVENT] [MOD:]SYM[+0] [FETCHARGS]------------------------------设置一个 return probe 探测点-:[GRP/]EVENT----------------------------------------------------------删除一个探测点

细节解释如下:

GRP        : Group name. If omitted, use 「kprobes」 for it.------------设置后会在 events/kprobes 下创建<GRP>目录。 EVENT        : Event name. If omitted, the event name is generated based on SYM+offs or MEMADDR.---指定后在 events/kprobes/<GRP>生成<EVENT>目录。MOD        : Module name which has given SYM.--------------------------模块名,一般不设 SYM[+offs]    : Symbol+offset where the probe is inserted.-------------被探测函数名和偏移 MEMADDR    : Address where the probe is inserted.----------------------指定被探测的内存绝对地址 FETCHARGS    : Arguments. Each probe can have up to 128 args.----------指定要获取的参数信息。%REG        : Fetch register REG---------------------------------------获取指定寄存器值 @ADDR        : Fetch memory at ADDR (ADDR should be in kernel)--------获取指定内存地址的值 @SYM[+|-offs]    : Fetch memory at SYM +|- offs (SYM should be a data symbol)---获取全局变量的值 $stackN    : Fetch Nth entry of stack (N >= 0)----------------------------------获取指定栈空间值,即 sp 寄存器+N 后的位置值 $stack    : Fetch stack address.-----------------------------------------------获取 sp 寄存器值 $retval    : Fetch return value.(*)--------------------------------------------获取返回值,用户 return kprobe $comm        : Fetch current task comm.----------------------------------------获取对应进程名称。 +|-offs(FETCHARG) : Fetch memory at FETCHARG +|- offs address.(**)------------- NAME=FETCHARG : Set NAME as the argument name of FETCHARG. FETCHARG:TYPE : Set TYPE as the type of FETCHARG. Currently, basic types (u8/u16/u32/u64/s8/s16/s32/s64), hexadecimal types          (x8/x16/x32/x64), 「string」 and bitfield are supported.----------------设置参数的类型,可以支持字符串和比特类型  (*only for return probe.  (**) this is useful for fetching a field of data structures.

执行如下两条命令就会生成目录/sys/kernel/debug/tracing/events/kprobes/myprobe;第三条命令则可以删除指定 kprobe 事件,如果要全部删除则 echo > /sys/kernel/debug/tracing/kprobe_events。

echo 『p:myprobe do_sys_open dfd=%ax filename=%dx flags=%cx mode=+4($stack)』 > /sys/kernel/debug/tracing/kprobe_eventsecho 『r:myretprobe do_sys_open ret=$retval』 >> /sys/kernel/debug/tracing/kprobe_events-----------------------------------------------------这里面一定要用「>>」,不然就会覆盖前面的设置。echo 『-:myprobe』 >> /sys/kernel/debug/tracing/kprobe_eventsecho 『-:myretprobe』 >> /sys/kernel/debug/tracing/kprobe_events

参数后面的寄存器是跟架构相关的,%ax、%dx、%cx 表示第 1/2/3 个参数,超出部分使用$stack 来存储参数。

函数返回值保存在$retval 中。

(4)kprobe 使能。对 kprobe 事件的是能通过往对应事件的 enable 写 1 开启探测;写 0 暂停探测。

echo > /sys/kernel/debug/tracing/traceecho p:myprobe do_sys_open dfd=%ax filename=%dx flags=%cx mode=+4($stack) > /sys/kernel/debug/tracing/kprobe_eventsecho r:myretprobe do_sys_open ret=$retval >> /sys/kernel/debug/tracing/kprobe_eventsecho 1 > /sys/kernel/debug/tracing/events/kprobes/myprobe/enableecho 1 > /sys/kernel/debug/tracing/events/kprobes/myretprobe/enablelsecho 0 > /sys/kernel/debug/tracing/events/kprobes/myprobe/enableecho 0 > /sys/kernel/debug/tracing/events/kprobes/myretprobe/enablecat /sys/kernel/debug/tracing/trace

然后在/sys/kernel/debug/tracing/trace 中可以看到结果。

sourceinsight4.-3356  [000] .... 3542865.754536: myprobe: (do_sys_open+0x0/0x290) dfd=0xffffffffbd6764a0 filename=0x8000 flags=0x1b6 mode=0xe3afff48ffffffffbash-26041 [001] .... 3542865.757014: myprobe: (do_sys_open+0x0/0x290) dfd=0xffffffffbd676460 filename=0x8241 flags=0x1b6 mode=0xe0c0ff48ffffffffls-18078 [005] .... 3542865.757950: myprobe: (do_sys_open+0x0/0x290) dfd=0xffffffffbd676460 filename=0x88000 flags=0x1 mode=0xc1b7bf48ffffffffls-18078 [005] d... 3542865.757953: myretprobe: (SyS_open+0x1e/0x20 <- do_sys_open) ret=0x3ls-18078 [005] .... 3542865.757966: myprobe: (do_sys_open+0x0/0x290) dfd=0xffffffffbd676460 filename=0x88000 flags=0x6168 mode=0xc1b7bf48ffffffffls-18078 [005] d... 3542865.757969: myretprobe: (SyS_open+0x1e/0x20 <- do_sys_open) ret=0x3ls-18078 [005] .... 3542865.758001: myprobe: (do_sys_open+0x0/0x290) dfd=0xffffffffbd676460 filename=0x88000 flags=0x6168 mode=0xc1b7bf48ffffffffls-18078 [005] d... 3542865.758004: myretprobe: (SyS_open+0x1e/0x20 <- do_sys_open) ret=0x3ls-18078 [005] .... 3542865.758030: myprobe: (do_sys_open+0x0/0x290) dfd=0xffffffffbd676460 filename=0x88000 flags=0x1000 mode=0xc1b7bf48ffffffffls-18078 [005] d... 3542865.758033: myretprobe: (SyS_open+0x1e/0x20 <- do_sys_open) ret=0x3ls-18078 [005] .... 3542865.758055: myprobe: (do_sys_open+0x0/0x290) dfd=0xffffffffbd676460 filename=0x88000 flags=0x1000 mode=0xc1b7bf48ffffffffls-18078 [005] d... 3542865.758057: myretprobe: (SyS_open+0x1e/0x20 <- do_sys_open) ret=0x3ls-18078 [005] .... 3542865.758080: myprobe: (do_sys_open+0x0/0x290) dfd=0xffffffffbd676460 filename=0x88000 flags=0x19d0 mode=0xc1b7bf48ffffffffls-18078 [005] d... 3542865.758082: myretprobe: (SyS_open+0x1e/0x20 <- do_sys_open) ret=0x3ls-18078 [005] .... 3542865.758289: myprobe: (do_sys_open+0x0/0x290) dfd=0xffffffffbd676460 filename=0x8000 flags=0x1b6 mode=0xc1b7bf48ffffffffls-18078 [005] d... 3542865.758297: myretprobe: (SyS_open+0x1e/0x20 <- do_sys_open) ret=0x3ls-18078 [005] .... 3542865.758339: myprobe: (do_sys_open+0x0/0x290) dfd=0xffffffffbd676460 filename=0x88000 flags=0x0 mode=0xc1b7bf48ffffffffls-18078 [005] d... 3542865.758343: myretprobe: (SyS_open+0x1e/0x20 <- do_sys_open) ret=0x3ls-18078 [005] .... 3542865.758444: myprobe: (do_sys_open+0x0/0x290) dfd=0xffffffffbd676460 filename=0x98800 flags=0x2 mode=0xc1b7bf48ffffffffls-18078 [005] d... 3542865.758446: myretprobe: (SyS_open+0x1e/0x20 <- do_sys_open) ret=0x3bash-26041 [001] .... 3542865.760416: myprobe: (do_sys_open+0x0/0x290) dfd=0xffffffffbd676460 filename=0x8241 flags=0x1b6 mode=0xe0c0ff48ffffffffbash-26041 [001] d... 3542865.760426: myretprobe: (SyS_open+0x1e/0x20 <- do_sys_open) ret=0x3bash-26041 [001] d... 3542865.793477: myretprobe: (SyS_open+0x1e/0x20 <- do_sys_open) ret=0x3

(5)kprobe 事件过滤。跟踪函数需要通过 filter 进行过滤,可以有效过滤掉冗余信息。filter 文件用于设置过滤条件,可以减少 trace 中输出的信息,它支持的格式和 C 语言的表达式类似,支持 ==,!=,>,<,>=,<=判断,并且支持与&&,或||,还有()。

echo 『filename==0x8241』 > /sys/kernel/debug/tracing/events/kprobes/myprobe/filter

(6)kprobe 和栈配合使用。如果要在显示函数的同时显示其栈信息,可以通过配置 trace_options 来达到。

echo stacktrace > /sys/kernel/debug/tracing/trace_options

(7)kprobe_profile 统计信息。获取一段 kprobe 时间之后,可以再 kprobe_profile 中查看统计信息。

后面两列分别表示命中和未命中的次数。

cat /sys/kernel/debug/tracing/kprobe_profile    myprobe

4.3 调试工具搭配使用

在使用 Kprobes 进行调试时,搭配其他工具可以更高效地分析和解决问题,就像一场精彩的交响乐,不同的乐器相互配合,才能演奏出美妙的旋律。

查看内核日志是一个非常重要的辅助手段。在前面的代码中,我们使用了 printk 函数来输出调试信息,这些信息会被记录到内核日志中。通过查看内核日志,我们可以了解 Kprobes 探测模块的运行情况,如探测点是否成功注册、回调函数是否被正确调用、函数的参数和执行结果等。在 Linux 系统中,可以使用 dmesg 命令来查看内核日志,例如:dmesg | grep 「do_sys_open」,这个命令会过滤出内核日志中与 do_sys_open 相关的信息,方便我们快速定位问题。

gdb 调试器也能与 Kprobes 配合使用,为调试工作提供更多便利。虽然 Kprobes 主要用于动态调试运行中的内核,但在某些情况下,结合 gdb 可以更深入地分析问题。比如,当 Kprobes 探测到某个函数出现异常,但通过 printk 输出的信息不足以定位问题时,可以使用 gdb 来调试内核模块。首先,需要在内核编译时开启调试信息,然后使用 gdb 加载内核和内核模块,通过设置断点、单步执行等操作,详细分析函数的执行过程,找出问题的根源。

4.4 常见问题与解决方法

在使用 Kprobes 的过程中,可能会遇到一些常见问题,这些问题就像是前进道路上的绊脚石,但只要我们掌握了解决方法,就能轻松跨越。

探测点无法注册是一个常见的问题。这可能是由于目标函数不存在、符号未导出或内核保护等原因导致的。当遇到这种情况时,首先要确认目标函数是否存在,可以通过查看内核源码或使用 nm 命令查看内核符号表来确认。如果函数存在,再检查符号是否导出,可以查看/proc/kallsyms 文件,看目标函数的符号是否在其中。如果是内核保护导致的问题,例如内核处于写保护状态,可能需要临时关闭相关保护机制,但这需要谨慎操作,因为关闭保护机制可能会影响系统的稳定性和安全性。

回调函数未按预期执行也是一个需要关注的问题。这可能是由于回调函数中存在错误,如内存访问越界、空指针引用等,导致回调函数执行异常。在编写回调函数时,要确保代码的正确性和健壮性,避免出现这些常见的错误。同时,要注意回调函数的执行环境,因为回调函数运行在中断上下文中,所以不能执行可能会导致阻塞的操作,如睡眠、等待信号量等。如果需要进行一些复杂的操作,可以将这些操作放到工作队列或内核线程中执行,以避免影响回调函数的正常执行。

最新文章

随机文章

基本 文件 流程 错误 SQL 调试
  1. 请求信息 : 2026-02-28 08:58:51 HTTP/2.0 GET : https://f.mffb.com.cn/a/476567.html
  2. 运行时间 : 0.128922s [ 吞吐率:7.76req/s ] 内存消耗:4,850.57kb 文件加载:140
  3. 缓存信息 : 0 reads,0 writes
  4. 会话信息 : SESSION_ID=00b8ee3a9a68de19e039905815d39fbb
  1. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/public/index.php ( 0.79 KB )
  2. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/autoload.php ( 0.17 KB )
  3. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/autoload_real.php ( 2.49 KB )
  4. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/platform_check.php ( 0.90 KB )
  5. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/ClassLoader.php ( 14.03 KB )
  6. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/autoload_static.php ( 4.90 KB )
  7. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/helper.php ( 8.34 KB )
  8. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-validate/src/helper.php ( 2.19 KB )
  9. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/helper.php ( 1.47 KB )
  10. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/stubs/load_stubs.php ( 0.16 KB )
  11. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Exception.php ( 1.69 KB )
  12. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-container/src/Facade.php ( 2.71 KB )
  13. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/deprecation-contracts/function.php ( 0.99 KB )
  14. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/polyfill-mbstring/bootstrap.php ( 8.26 KB )
  15. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/polyfill-mbstring/bootstrap80.php ( 9.78 KB )
  16. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/var-dumper/Resources/functions/dump.php ( 1.49 KB )
  17. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-dumper/src/helper.php ( 0.18 KB )
  18. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/var-dumper/VarDumper.php ( 4.30 KB )
  19. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/App.php ( 15.30 KB )
  20. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-container/src/Container.php ( 15.76 KB )
  21. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/container/src/ContainerInterface.php ( 1.02 KB )
  22. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/provider.php ( 0.19 KB )
  23. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Http.php ( 6.04 KB )
  24. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/helper/Str.php ( 7.29 KB )
  25. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Env.php ( 4.68 KB )
  26. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/common.php ( 0.03 KB )
  27. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/helper.php ( 18.78 KB )
  28. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Config.php ( 5.54 KB )
  29. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/app.php ( 0.95 KB )
  30. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/cache.php ( 0.78 KB )
  31. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/console.php ( 0.23 KB )
  32. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/cookie.php ( 0.56 KB )
  33. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/database.php ( 2.48 KB )
  34. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/facade/Env.php ( 1.67 KB )
  35. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/filesystem.php ( 0.61 KB )
  36. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/lang.php ( 0.91 KB )
  37. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/log.php ( 1.35 KB )
  38. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/middleware.php ( 0.19 KB )
  39. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/route.php ( 1.89 KB )
  40. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/session.php ( 0.57 KB )
  41. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/trace.php ( 0.34 KB )
  42. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/view.php ( 0.82 KB )
  43. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/event.php ( 0.25 KB )
  44. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Event.php ( 7.67 KB )
  45. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/service.php ( 0.13 KB )
  46. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/AppService.php ( 0.26 KB )
  47. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Service.php ( 1.64 KB )
  48. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Lang.php ( 7.35 KB )
  49. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/lang/zh-cn.php ( 13.70 KB )
  50. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/initializer/Error.php ( 3.31 KB )
  51. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/initializer/RegisterService.php ( 1.33 KB )
  52. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/services.php ( 0.14 KB )
  53. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/service/PaginatorService.php ( 1.52 KB )
  54. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/service/ValidateService.php ( 0.99 KB )
  55. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/service/ModelService.php ( 2.04 KB )
  56. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-trace/src/Service.php ( 0.77 KB )
  57. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Middleware.php ( 6.72 KB )
  58. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/initializer/BootService.php ( 0.77 KB )
  59. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/Paginator.php ( 11.86 KB )
  60. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-validate/src/Validate.php ( 63.20 KB )
  61. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/Model.php ( 23.55 KB )
  62. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/Attribute.php ( 21.05 KB )
  63. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/AutoWriteData.php ( 4.21 KB )
  64. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/Conversion.php ( 6.44 KB )
  65. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/DbConnect.php ( 5.16 KB )
  66. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/ModelEvent.php ( 2.33 KB )
  67. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/RelationShip.php ( 28.29 KB )
  68. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/contract/Arrayable.php ( 0.09 KB )
  69. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/contract/Jsonable.php ( 0.13 KB )
  70. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/contract/Modelable.php ( 0.09 KB )
  71. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Db.php ( 2.88 KB )
  72. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/DbManager.php ( 8.52 KB )
  73. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Log.php ( 6.28 KB )
  74. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Manager.php ( 3.92 KB )
  75. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/log/src/LoggerTrait.php ( 2.69 KB )
  76. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/log/src/LoggerInterface.php ( 2.71 KB )
  77. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Cache.php ( 4.92 KB )
  78. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/simple-cache/src/CacheInterface.php ( 4.71 KB )
  79. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/helper/Arr.php ( 16.63 KB )
  80. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/cache/driver/File.php ( 7.84 KB )
  81. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/cache/Driver.php ( 9.03 KB )
  82. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/CacheHandlerInterface.php ( 1.99 KB )
  83. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/Request.php ( 0.09 KB )
  84. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Request.php ( 55.78 KB )
  85. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/middleware.php ( 0.25 KB )
  86. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Pipeline.php ( 2.61 KB )
  87. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-trace/src/TraceDebug.php ( 3.40 KB )
  88. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/middleware/SessionInit.php ( 1.94 KB )
  89. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Session.php ( 1.80 KB )
  90. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/session/driver/File.php ( 6.27 KB )
  91. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/SessionHandlerInterface.php ( 0.87 KB )
  92. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/session/Store.php ( 7.12 KB )
  93. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Route.php ( 23.73 KB )
  94. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/RuleName.php ( 5.75 KB )
  95. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/Domain.php ( 2.53 KB )
  96. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/RuleGroup.php ( 22.43 KB )
  97. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/Rule.php ( 26.95 KB )
  98. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/RuleItem.php ( 9.78 KB )
  99. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/route/app.php ( 1.72 KB )
  100. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/facade/Route.php ( 4.70 KB )
  101. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/dispatch/Controller.php ( 4.74 KB )
  102. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/Dispatch.php ( 10.44 KB )
  103. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/controller/Index.php ( 4.81 KB )
  104. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/BaseController.php ( 2.05 KB )
  105. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/facade/Db.php ( 0.93 KB )
  106. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/connector/Mysql.php ( 5.44 KB )
  107. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/PDOConnection.php ( 52.47 KB )
  108. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/Connection.php ( 8.39 KB )
  109. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/ConnectionInterface.php ( 4.57 KB )
  110. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/builder/Mysql.php ( 16.58 KB )
  111. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/Builder.php ( 24.06 KB )
  112. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/BaseBuilder.php ( 27.50 KB )
  113. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/Query.php ( 15.71 KB )
  114. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/BaseQuery.php ( 45.13 KB )
  115. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/TimeFieldQuery.php ( 7.43 KB )
  116. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/AggregateQuery.php ( 3.26 KB )
  117. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/ModelRelationQuery.php ( 20.07 KB )
  118. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/ParamsBind.php ( 3.66 KB )
  119. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/ResultOperation.php ( 7.01 KB )
  120. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/WhereQuery.php ( 19.37 KB )
  121. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/JoinAndViewQuery.php ( 7.11 KB )
  122. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/TableFieldInfo.php ( 2.63 KB )
  123. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/Transaction.php ( 2.77 KB )
  124. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/log/driver/File.php ( 5.96 KB )
  125. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/LogHandlerInterface.php ( 0.86 KB )
  126. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/log/Channel.php ( 3.89 KB )
  127. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/event/LogRecord.php ( 1.02 KB )
  128. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/Collection.php ( 16.47 KB )
  129. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/facade/View.php ( 1.70 KB )
  130. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/View.php ( 4.39 KB )
  131. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Response.php ( 8.81 KB )
  132. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/response/View.php ( 3.29 KB )
  133. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Cookie.php ( 6.06 KB )
  134. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-view/src/Think.php ( 8.38 KB )
  135. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/TemplateHandlerInterface.php ( 1.60 KB )
  136. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-template/src/Template.php ( 46.61 KB )
  137. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-template/src/template/driver/File.php ( 2.41 KB )
  138. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-template/src/template/contract/DriverInterface.php ( 0.86 KB )
  139. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/runtime/temp/067d451b9a0c665040f3f1bdd3293d68.php ( 11.98 KB )
  140. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-trace/src/Html.php ( 4.42 KB )
  1. CONNECT:[ UseTime:0.000864s ] mysql:host=127.0.0.1;port=3306;dbname=f_mffb;charset=utf8mb4
  2. SHOW FULL COLUMNS FROM `fenlei` [ RunTime:0.001151s ]
  3. SELECT * FROM `fenlei` WHERE `fid` = 0 [ RunTime:0.000498s ]
  4. SELECT * FROM `fenlei` WHERE `fid` = 63 [ RunTime:0.000453s ]
  5. SHOW FULL COLUMNS FROM `set` [ RunTime:0.000738s ]
  6. SELECT * FROM `set` [ RunTime:0.000251s ]
  7. SHOW FULL COLUMNS FROM `article` [ RunTime:0.000740s ]
  8. SELECT * FROM `article` WHERE `id` = 476567 LIMIT 1 [ RunTime:0.000809s ]
  9. UPDATE `article` SET `lasttime` = 1772240331 WHERE `id` = 476567 [ RunTime:0.025759s ]
  10. SELECT * FROM `fenlei` WHERE `id` = 67 LIMIT 1 [ RunTime:0.000495s ]
  11. SELECT * FROM `article` WHERE `id` < 476567 ORDER BY `id` DESC LIMIT 1 [ RunTime:0.000824s ]
  12. SELECT * FROM `article` WHERE `id` > 476567 ORDER BY `id` ASC LIMIT 1 [ RunTime:0.000680s ]
  13. SELECT * FROM `article` WHERE `id` < 476567 ORDER BY `id` DESC LIMIT 10 [ RunTime:0.001635s ]
  14. SELECT * FROM `article` WHERE `id` < 476567 ORDER BY `id` DESC LIMIT 10,10 [ RunTime:0.002054s ]
  15. SELECT * FROM `article` WHERE `id` < 476567 ORDER BY `id` DESC LIMIT 20,10 [ RunTime:0.002222s ]
0.131853s