当前位置:首页>Linux>Linux故障诊断系列8.3-内核专题-Systemtap用户态探针

Linux故障诊断系列8.3-内核专题-Systemtap用户态探针

  • 2026-01-08 04:23:45
Linux故障诊断系列8.3-内核专题-Systemtap用户态探针

🛰️ SystemTap用户态探针 | 让应用也戴上"隐形黑匣子"

📖 写在开头:你是不是也这样?

痛点场景
内核插桩很爽,但问题有时藏在用户态:某进程偶发 CPU 飙高、函数调用栈诡异、JVM GC 触发频繁……strace 太吵、gdb 太重,线上动不动就不敢下手。

解决方案概述
SystemTap 其实不止能"盯内核",它还能在用户态插桩:函数进出、语句点、静态 mark、进程/线程生命周期、syscall 入口/返回,全都可用同一套脚本搞定,还能走用户态栈回溯。前提是:内核支持 uprobes、装好 debuginfo。本文拆开用户态探针的事件、变量访问、栈回溯和实战示例,让你把应用也装上"隐形黑匣子"。

5维度评分表

维度
评分
说明
难度等级
⭐⭐⭐⭐
需理解 uprobes 与调试信息
实用价值
⭐⭐⭐⭐⭐
线上排查用户态热点/栈信息利器
技术深度
⭐⭐⭐⭐
涉及符号、调试包、栈回溯
可操作性
⭐⭐⭐⭐
脚本+示例即可落地
风险提醒
⭐⭐⭐
控输出频率,尊重权限与性能

🎯 什么是用户态探针?为什么需要它?

在之前的文章中,我们学习了 SystemTap 如何在内核空间进行插桩和追踪。但现实中的很多问题其实发生在用户空间(user-space),也就是我们运行的各种应用程序中。

内核态 vs 用户态:两个不同的世界

Linux 系统将内存空间分为两个部分:

内核空间(Kernel Space):操作系统核心代码运行的地方,权限最高,可以直接访问硬件
用户空间(User Space):应用程序运行的地方,权限受限,需要通过系统调用才能访问硬件

SystemTap 最初专注于内核空间探测,但从 0.6 版本开始,它增加了对用户空间进程的探测能力。这意味着我们可以:

追踪应用程序内部的函数调用
监控特定进程的系统调用
观察 Java 虚拟机(JVM)的内部事件
分析用户态程序的调用栈
诊断应用层的性能瓶颈

为什么传统工具不够用?

你可能用过这些工具:

strace:追踪系统调用,但输出太"吵",难以过滤
gdb:功能强大,但需要停止程序,不适合生产环境
perf:性能分析工具,但配置复杂,学习曲线陡峭

SystemTap 的用户态探针提供了另一种选择:无需修改代码、无需重启程序、可以精确控制探测点,就像给应用程序装上了"隐形黑匣子"。


🧰 先决条件:内核得支持 uprobes

检查内核支持

用户态探针依赖于 Linux 内核的 uprobes(User-space Probes)功能。从 Linux 3.5 版本开始,uprobes 已经集成到内核中。

检查你的内核是否支持 uprobes:

grep CONFIG_UPROBES /boot/config-$(uname -r)

期望输出:

CONFIG_UPROBES=y

如果输出是 CONFIG_UPROBES=n 或没有输出,说明你的内核不支持 uprobes,需要重新编译内核或升级到支持版本。

安装调试信息包(debuginfo)

这是最关键的前提条件!用户态探针需要目标程序的调试信息才能:

解析函数名和符号
获取变量信息
生成调用栈回溯

为什么需要 debuginfo?

编译后的二进制文件通常不包含调试信息(为了减小体积)。调试信息存储在单独的 debuginfo 包中,包含:

函数名和地址的映射关系
变量名和内存地址的对应
源代码行号和机器码的对应关系
调用栈展开所需的信息

如何安装 debuginfo?

在 RHEL/CentOS 系统上:

# 启用 debuginfo 仓库
yum install yum-utils
debuginfo-install <package-name>
# 例如,为 ls 命令安装 debuginfo
debuginfo-install coreutils

在 Fedora 系统上:

dnf debuginfo-install <package-name>

验证 debuginfo 是否安装成功:

# 检查是否有对应的 debuginfo 文件
rpm -qa | grep debuginfo | grep <package-name>
# 或者使用 readelf 查看符号信息
readelf -/usr/bin/ls | grep debug

常见问题:

**Q:为什么我的脚本报错 "semantic error: no match"?**A:很可能是缺少 debuginfo 包,或者指定的路径/函数名不正确。
Q:debuginfo 包很大,必须全部安装吗?
A:只需要安装你实际要探测的程序和库的 debuginfo 包即可。

🛰️ 一、用户态事件家族(process.*)

所有用户态事件探针都以 process 开头。这是 SystemTap 识别用户态探针的统一前缀。

事件过滤:PID vs 路径(PATH)

在定义用户态探针时,你可以通过两种方式限制探测范围:

1
按进程 ID(PID)过滤:只探测特定进程
2
按可执行文件路径(PATH)过滤:只探测特定程序

为什么需要指定 PATH?

对于需要符号解析的探针(如函数探针、语句探针),SystemTap 必须使用调试信息进行静态分析来确定在哪里放置探针。如果只指定 PID,SystemTap 无法知道程序加载了哪些库、函数在哪里,所以必须指定可执行文件的路径。

PATH 的灵活性:

SystemTap 会使用 PATH 环境变量,所以你可以:

使用命令名:process("ls")
使用绝对路径:process("/bin/ls")
使用相对路径(如果 PATH 中包含)

1.1 函数入口/返回探针

语法:

process("PATH").function("function_name")
process("PATH").function("function_name").return

这是最常用的用户态探针类型,类似于内核态的 kernel.function()

功能:

在函数入口处触发(.function()
在函数返回处触发(.function().return
支持通配符匹配多个函数

实际例子:

# 探测 ls 命令的 main 函数入口
probe process("ls").function("main") {
    printf("ls main() called, pid=%d\n", pid())
}
# 探测所有以 "x" 开头的函数
probe process("ls").function("x*") {
    printf("Function %s called\n", probefunc())
}
# 探测函数返回,并打印返回值
probe process("myapp").function("calculate").return {
    printf("calculate() returned: %d\n", $return)
}

通配符示例:

# 匹配所有 malloc 相关函数
probe process("myapp").function("*malloc*") {
    printf("Memory allocation: %s\n", probefunc())
}

1.2 语句探针

语法:

process("PATH").statement("statement_location")

语句探针可以精确到源代码的某一行,在对应语句的最早指令处触发。

使用场景:

需要精确到某行代码的调试
追踪特定变量的赋值
分析条件分支的执行

实际例子:

# 探测 myapp.c 第 42 行的执行
probe process("myapp").statement("myapp.c:42") {
    printf("Line 42 executed\n")
}
# 探测特定函数内的某一行
probe process("myapp").statement("process_data@src/main.c:156") {
    printf("Processing data at line 156\n")
}

注意事项:

语句探针需要精确的源代码位置信息
如果代码被优化,行号可能不准确
建议在编译时保留调试信息(-g 选项)

1.3 静态标记探针(Static Markers)

语法:

process("PATH").mark("marker_name")

静态标记是程序代码中预定义的探测点,类似于"埋点"。程序开发者可以在代码中插入标记,SystemTap 可以在这些标记处触发探针。

为什么需要静态标记?

函数探针需要调试信息,但静态标记可以在没有完整调试信息的情况下工作
开发者可以在关键位置精确放置标记
标记可以携带参数信息

支持通配符:

# 匹配所有以 "gc__" 开头的标记
probe process("myapp").mark("gc__*") {
    printf("GC event: %s\n", $$name)
}

实际应用:Java HotSpot JVM

很多软件包(如 Java)提供了静态标记点。SystemTap 为这些标记提供了别名,使用更方便:

# HotSpot JVM 的 GC 开始标记
probe hotspot.gc_begin =
  process("/usr/lib/jvm/java-1.6.0-openjdk-1.6.0.0.x86_64/jre/lib/amd64/server/libjvm.so").mark("gc__begin")

使用别名:

# 直接使用别名,更简洁
probe hotspot.gc_begin {
    printf("GC started at %s\n", ctime(gettimeofday_s()))
}
probe hotspot.gc_end {
    printf("GC finished\n")
}

1.4 进程/线程生命周期探针

语法:

process.begin          # 进程创建
process.end            # 进程结束
process.thread.begin   # 线程创建
process.thread.end     # 线程结束

这些探针可以监控进程和线程的创建和销毁。

实际例子:

# 监控所有新进程的创建
probe process.begin {
    printf("New process: %s (PID: %d, PPID: %d)\n",
           execname(), pid(), ppid())
}
# 监控特定程序的进程结束
probe process("myapp").end {
    printf("Process %d exited\n", pid())
}
# 监控线程创建
probe process.thread.begin {
    printf("New thread in process %s (PID: %d, TID: %d)\n",
           execname(), pid(), tid())
}

使用场景:

追踪进程泄漏(进程创建但未正常退出)
分析多线程程序的线程生命周期
监控特定程序的启动和关闭

1.5 系统调用探针

语法:

process.syscall
process.syscall.return

监控用户态进程的系统调用,类似于 strace,但更灵活。

可用的上下文变量:

$syscall:系统调用号
$arg1 到 $arg6:系统调用的前 6 个参数
$return:系统调用的返回值(仅在 .return 探针中可用)

实际例子:

# 监控 ls 命令的所有系统调用
probe process("ls").syscall {
    printf("PID %d: syscall %d (%s)\n",
           pid(), $syscall, syscall_name($syscall))
}
# 监控文件打开操作
probe process("myapp").syscall.open {
    printf("Opening file: %s\n", user_string($arg1))
}
# 监控系统调用返回值和耗时
probe process("myapp").syscall.read.return {
    printf("read() returned %d bytes\n", $return)
}

过滤特定系统调用:

# 只监控 open 系统调用
probe process("myapp").syscall.open {
    printf("Opening: %s (flags: %d, mode: %d)\n",
           user_string($arg1), $arg2, $arg3)
}

与 strace 的对比:

特性
SystemTap
strace
过滤能力
强大,可精确过滤
有限
性能开销
可控,可采样
较高
输出格式
自定义
固定
脚本化
支持复杂逻辑
简单

🔍 二、访问用户态变量:与内核态类似但地址空间不同

在用户态探针中访问变量,语法与内核态类似,但有一个重要区别:用户空间和内核空间使用不同的地址空间

2.1 直接访问变量

语法:

$variable_name

在函数探针中,可以直接访问函数的参数和局部变量(需要 debuginfo)。

实际例子:

# 假设有函数 int process_data(int id, char *name)
probe process("myapp").function("process_data") {
    printf("Processing data: id=%d, name=%s\n",
           $id, user_string($name))
}

注意事项:

变量名必须与源代码中的名称完全匹配
需要安装对应的 debuginfo 包
如果变量被编译器优化掉,可能无法访问

2.2 用户态指针读取函数

当需要读取用户态指针指向的数据时,不能直接解引用(因为地址空间不同),需要使用专门的函数:

函数
说明
示例
user_char(address)
读取字符
user_char($ptr)
user_short(address)
读取短整型
user_short($ptr)
user_int(address)
读取整型
user_int($ptr)
user_long(address)
读取长整型
user_long($ptr)
user_string(address)
读取字符串
user_string($buf)
user_string_n(address, n)
读取指定长度的字符串
user_string_n($buf, 100)

为什么需要这些函数?

在 Linux 中,用户空间和内核空间使用不同的地址空间映射。直接在内核态访问用户态指针会导致:

访问错误的内存位置
系统崩溃或数据损坏

这些函数会:

1
验证指针的有效性
2
从用户空间复制数据到内核空间
3
处理页错误和边界检查

实际例子:

# 读取字符串参数
probe process("myapp").function("process_file") {
    filename = user_string($path)
    printf("Processing file: %s\n", filename)
}
# 读取整型数组
probe process("myapp").function("sum_array") {
    sum = 0
    for (= 0; i < $count; i++) {
        sum += user_int($array + i * 4)  # 假设 int 是 4 字节
    }
    printf("Sum: %d\n", sum)
}
# 安全读取字符串(限制长度)
probe process("myapp").function("log_message") {
    msg = user_string_n($message, 256)  # 最多读取 256 字节
    printf("Log: %s\n", msg)
}

2.3 结构体访问

语法:

$struct_variable->field

SystemTap 会自动识别地址空间,使用 -> 操作符访问结构体字段。

实际例子:

# 假设有结构体 struct user { int id; char name[64]; }
probe process("myapp").function("create_user") {
    printf("User ID: %d, Name: %s\n",
           $user->id, user_string($user->name))
}

2.4 一键打印上下文信息

SystemTap 提供了便捷的变量打印功能:

变量
说明
$$parms
打印函数的所有参数
$$locals
打印函数的所有局部变量
$$vars
打印函数的所有可见变量(参数+局部变量)

展开级别:

$$:单层展开
$$:深度展开(递归展开结构体字段)

实际例子:

# 打印所有参数
probe process("myapp").function("process_data") {
    printf("Parameters: %s\n", $$parms)
}
# 打印所有局部变量
probe process("myapp").function("calculate") {
    printf("Local variables: %s\n", $$locals)
}
# 深度展开结构体
probe process("myapp").function("handle_request") {
    printf("All variables: %s\n", $$vars$$)  # 深度展开
}

输出示例:

Parameters: id=42 name=0x7fff12345678 count=10
Local variables: temp=100 result=0x7fff12345690

注意事项:

输出可能很长,注意控制输出频率
指针值会显示为地址,需要配合 user_string() 等函数读取内容
深度展开可能导致输出非常长

🧭 三、用户态栈回溯:找出"谁"调了这个点

3.1 为什么需要栈回溯?

当你探测到一个函数被调用时,往往需要知道:

谁调用了这个函数?
调用链是什么?
问题是从哪里开始的?

栈回溯(Stack Backtrace)就是追踪函数调用链的工具。

3.2 用户态栈回溯的挑战

用户态栈回溯比内核态更复杂,因为:

1
编译器优化:现代编译器会优化代码,可能消除栈帧指针(frame pointer),使得传统的栈回溯方法失效。
2
调试信息依赖:必须依赖调试信息(debuginfo)中的 DWARF 信息来展开调用栈。
3
架构限制:目前 SystemTap 的用户态栈回溯主要支持 x86(32位和64位)架构,其他架构(如 ARM)的支持有限。

3.3 栈回溯函数

核心函数:

ubacktrace():获取用户态调用栈的地址数组
print_usyms():将地址数组转换为可读的函数名和地址信息

语法:

print_usyms(ubacktrace())

3.4 确保调试信息可用

为了生成准确的栈回溯,必须:

1

为可执行文件指定调试信息:使用 -d 选项

stap -/path/to/executable script.stp
2

为共享库加载符号:使用 --ldd 选项

stap -/path/to/executable --ldd script.stp

--ldd 选项会:

自动检测可执行文件依赖的所有共享库
加载这些库的调试信息
确保栈回溯中包含库函数的名称

3.5 实战案例:追踪 ls 命令的内存分配

让我们看一个完整的例子,追踪 ls 命令调用 xmalloc 函数时的调用栈:

stap -/bin/ls --ldd \
  -'probe process("ls").function("xmalloc") {
        printf("= xmalloc called =\n")
        print_usyms(ubacktrace())
        printf("\n")
      }' \
  -c "ls /"

输出示例:

bin	dev   lib	  media  net	     proc	sbin	 sys  var
boot etc   lib64  misc op_session  profilerc selinux  tmp
cgroup home  lost+found  mnt opt     root srv usr
= xmalloc called =
 0x4116c0 : xmalloc+0x0/0x20 [/bin/ls]
 0x4116fc : xmemdup+0x1c/0x40 [/bin/ls]
 0x40e68b : clone_quoting_options+0x3b/0x50 [/bin/ls]
 0x4087e4 : main+0x3b4/0x1900 [/bin/ls]
 0x3fa441ec5d : __libc_start_main+0xfd/0x1d0 [/lib64/libc-2.12.so]
 0x402799 : _start+0x29/0x2c [/bin/ls]
= xmalloc called =
 0x4116c0 : xmalloc+0x0/0x20 [/bin/ls]
 0x4116fc : xmemdup+0x1c/0x40 [/bin/ls]
 0x40e68b : clone_quoting_options+0x3b/0x50 [/bin/ls]
 0x40884a : main+0x41a/0x1900 [/bin/ls]
 0x3fa441ec5d : __libc_start_main+0xfd/0x1d0 [/lib64/libc-2.12.so]
 0x402799 : _start+0x29/0x2c [/bin/ls]
...

输出解读:

每一行显示:

地址:函数在内存中的地址
函数名+偏移函数名+偏移量/函数大小
所属模块[可执行文件或库名]

调用栈从下往上读:

1
_start:程序的入口点
2
__libc_start_main:C 库的启动函数
3
main:程序的 main 函数
4
clone_quoting_options:main 调用的函数
5
xmemdup:clone_quoting_options 调用的函数
6
xmalloc:我们探测的函数

3.6 更高级的栈回溯用法

只打印调用者:

probe process("myapp").function("error_handler") {
    bt = ubacktrace()
    # 跳过当前函数(索引0),打印调用者
    if (length(bt) > 1) {
        printf("Called from:\n")
        for (= 1; i < length(bt) && i < 10; i++) {
            printf("  %s\n", usymname(bt[i]))
        }
    }
}

统计调用栈模式:

global callers
probe process("myapp").function("slow_function") {
    bt = ubacktrace()
    # 使用调用栈的前3层作为键
    key = sprintf("%s->%s->%s",
                  usymname(bt[2]),
                  usymname(bt[1]),
                  usymname(bt[0]))
    callers[key]++
}
probe end {
    printf("\n= Top 10 call paths =\n")
    foreach (path in callers- limit 10) {
        printf("%d times: %s\n", callers[path], path)
    }
}

3.7 栈回溯相关的 Tapset

SystemTap 提供了两个专门的 tapset 用于用户态栈回溯:

ucontext-symbols.stp:符号相关函数
ucontext-unwind.stp:栈展开相关函数

更多详细信息可以参考 SystemTap Tapset Reference Manual


💡 四、实战案例集锦

案例 1:追踪 Java 应用的 GC 事件

场景: 你的 Java 应用偶尔出现卡顿,怀疑是 GC 导致的。

解决方案:

# 需要先安装 java-1.8.0-openjdk-debuginfo
probe hotspot.gc_begin {
    printf("[%s] GC started (PID: %d)\n",
           ctime(gettimeofday_s()), pid())
    print_usyms(ubacktrace())
}
probe hotspot.gc_end {
    printf("[%s] GC finished (PID: %d)\n",
           ctime(gettimeofday_s()), pid())
}
probe timer.s(60) {
    exit()
}

运行:

stap -/usr/lib/jvm/java-1.8.0-openjdk/jre/lib/amd64/server/libjvm.so \
     --ldd gc_monitor.stp -"java MyApp"

案例 2:分析应用程序的文件 I/O 模式

场景: 应用性能下降,怀疑是文件 I/O 瓶颈。

解决方案:

global read_stats, write_stats
probe process("myapp").syscall.read {
    read_stats[pid()] <<< $arg2  # $arg2 是读取的字节数
}
probe process("myapp").syscall.write {
    write_stats[pid()] <<< $arg2  # $arg2 是写入的字节数
}
probe timer.s(10) {
    printf("\n= Read Statistics =\n")
    foreach (in read_stats-) {
        printf("PID %d: count=%d, total=%d bytes, avg=%d bytes\n",
               p, @count(read_stats[p]),
               @sum(read_stats[p]),
               @avg(read_stats[p]))
    }

    printf("\n= Write Statistics =\n")
    foreach (in write_stats-) {
        printf("PID %d: count=%d, total=%d bytes, avg=%d bytes\n",
               p, @count(write_stats[p]),
               @sum(write_stats[p]),
               @avg(write_stats[p]))
    }
}
probe end {
    printf("\n= Final Statistics =\n")
    # 打印最终统计
}

案例 3:追踪内存泄漏

场景: 应用内存持续增长,怀疑有内存泄漏。

解决方案:

global malloc_count, free_count
probe process("myapp").function("malloc").return {
    malloc_count[pid(), $return]++
}
probe process("myapp").function("free") {
    ptr = $arg1
    if (ptr in malloc_count[pid()]) {
        delete malloc_count[pid(), ptr]
        free_count[pid()]++
    }
}
probe timer.s(30) {
    printf("\n= Memory Leak Detection =\n")
    printf("Active allocations: %d\n",
           @count(malloc_count[pid()]) - free_count[pid()])

    # 显示未释放的内存分配
    printf("\nUnfreed allocations (top 10):\n")
    foreach ([p, ptr] in malloc_count- limit 10) {
        printf("  PID %d, ptr=0x%x, count=%d\n",
               p, ptr, malloc_count[p, ptr])
    }
}

案例 4:分析函数执行时间

场景: 某个函数执行很慢,需要找出瓶颈。

解决方案:

global start_times, call_count, total_time
probe process("myapp").function("slow_function") {
    start_times[pid(), tid()] = gettimeofday_us()
}
probe process("myapp").function("slow_function").return {
    if ([pid(), tid()] in start_times) {
        elapsed = gettimeofday_us() - start_times[pid(), tid()]
        call_count[pid()]++
        total_time[pid()] += elapsed
        delete start_times[pid(), tid()]

        if (elapsed > 1000) {  # 超过 1ms
            printf("Slow call detected: %d us\n", elapsed)
            print_usyms(ubacktrace())
        }
    }
}
probe end {
    printf("\n= Function Statistics =\n")
    foreach (in call_count-) {
        printf("PID %d: calls=%d, total=%d us, avg=%d us\n",
               p, call_count[p],
               total_time[p],
               total_time[p] / call_count[p])
    }
}

案例 5:监控特定进程的系统调用

场景: 需要监控某个进程的所有系统调用,但 strace 输出太乱。

解决方案:

probe process("myapp").syscall {
    syscall_num = $syscall
    syscall_name = syscall_name(syscall_num)

    # 只关注文件相关系统调用
    if (syscall_name  "open" ||
        syscall_name  "openat" ||
        syscall_name  "read" ||
        syscall_name  "write") {
        printf("[%s] %s(", ctime(gettimeofday_s()), syscall_name)

        if (syscall_name  "open" || syscall_name  "openat") {
            printf("%s", user_string($arg1))
        } else if (syscall_name  "read" || syscall_name  "write") {
            printf("fd=%d, size=%d", $arg1, $arg2)
        }
        printf(")\n")
    }
}
probe process("myapp").syscall.return {
    syscall_name = syscall_name($syscall)
    if (syscall_name  "read" || syscall_name  "write") {
        printf("  -> returned %d bytes\n", $return)
    }
}

⚙️ 五、性能与安全最佳实践

5.1 控制输出频率

用户态探针可能触发非常频繁,如果不加控制,会产生大量输出,影响性能。

策略 1:采样

global counter = 0
probe process("myapp").function("hot_function") {
    counter++
    if (counter % 1000 == 0) {  # 每 1000 次打印一次
        printf("Called %d times\n", counter)
    }
}

策略 2:限流输出

global callers
probe process("myapp").function("error_handler") {
    bt = ubacktrace()
    key = sprintf("%s", usymname(bt[1]))  # 使用调用者作为键
    callers[key]++
}
probe timer.s(5) {
    printf("\n= Top 10 callers (last 5s) =\n")
    foreach (caller in callers- limit 10) {
        printf("%s: %d times\n", caller, callers[caller])
    }
    delete callers  # 清空,准备下一轮统计
}

策略 3:条件过滤

# 只记录执行时间超过阈值的调用
probe process("myapp").function("process_data").return {
    if ($return > 100) {  # 只关注返回值大于 100 的情况
        printf("Large result: %d\n", $return)
    }
}

5.2 权限管理

默认要求:

SystemTap 需要 root 权限或 stapdev 组权限

生产环境安全实践:

1

预编译脚本

# 在开发环境编译
stap -p4 -m mymonitor script.stp
# 生成 mymonitor.ko
# 在生产环境运行(只需要 stapusr 组)
staprun mymonitor.ko
2

使用 stapusr 组

# 将用户添加到 stapusr 组
usermod --G stapusr username
3

限制探测范围

# 只探测特定用户运行的进程
probe process("myapp") {
    if (uid() != 1000) next  # 只监控 UID 1000
}

5.3 版本匹配问题

问题: debuginfo 包必须与实际的二进制文件完全匹配,否则:

符号解析失败
栈回溯不准确
变量访问错误

检查方法:

# 检查二进制文件的构建 ID
readelf -/usr/bin/myapp | grep Build ID
# 检查 debuginfo 包的构建 ID
readelf -/usr/lib/debug/usr/bin/myapp.debug | grep Build ID
# 两者必须完全一致

解决方案:

确保 debuginfo 包与二进制文件来自同一个构建
在生产环境使用与开发环境相同版本的程序
如果程序是自行编译的,保留对应的调试信息

5.4 防止脚本长时间运行

添加超时退出:

probe timer.s(300) {  # 5 分钟后自动退出
    printf("\n= Script timeout, exiting =\n")
    exit()
}

基于事件数量退出:

global event_count = 0
global max_events = 10000
probe process("myapp").function("target_function") {
    event_count++
    if (event_count >= max_events) {
        printf("Reached max events, exiting\n")
        exit()
    }
}

5.5 性能开销评估

影响性能的因素:

1
探针频率:触发越频繁,开销越大
2
处理逻辑复杂度:复杂的计算和字符串操作会增加开销
3
输出量:大量 printf 会影响性能
4
栈回溯:生成栈回溯有一定开销

优化建议:

使用采样而非全量记录
在探针中做最小化处理,复杂逻辑放到定时器探针
使用聚合统计而非每次打印
谨慎使用栈回溯,只在必要时启用

❓ 六、常见问题与解答

Q1: 为什么我的函数探针报错 "semantic error: no match"?

可能原因:

1
函数名拼写错误
2
缺少 debuginfo 包
3
函数不在指定的可执行文件中(可能在共享库中)
4
函数被内联优化掉了

解决方法:

1. 检查函数是否存在
nm -/path/to/binary | grep function_name
2. 检查 debuginfo
readelf -/path/to/binary | grep debug
3. 尝试使用通配符
probe process("myapp").function("*function*")
4. 检查共享库
ldd /path/to/binary
stap -/path/to/binary --ldd script.stp

Q2: 栈回溯显示的是地址而不是函数名?

原因: 缺少调试信息或 -d / --ldd 选项未正确使用。

解决方法:

# 确保使用 -d 和 --ldd
stap -/path/to/executable --ldd script.stp
# 验证调试信息
objdump -/path/to/executable | head

Q3: 如何探测动态加载的共享库?

方法:

# 使用通配符或完整路径
probe process("myapp").function("function_in_so") {
    # 需要指定库的路径
}
# 或者使用 process("PATH").library("LIBNAME").function()
probe process("myapp").library("libmylib.so").function("myfunc")

Q4: 用户态探针会影响程序性能吗?

影响程度取决于:

探针触发频率
探针处理逻辑复杂度
是否启用栈回溯

建议:

在测试环境先评估性能影响
使用采样减少开销
避免在热点路径上放置复杂探针

Q5: 可以同时探测多个进程吗?

可以:

# 探测多个进程
probe process("app1").function("func"),
      process("app2").function("func") {
    printf("Function called in %s (PID: %d)\n", execname(), pid())
}
# 或者使用通配符
probe process("*myapp*").function("func") {
    # 匹配所有包含 "myapp" 的进程
}

Q6: 如何调试 SystemTap 脚本本身?

方法:

1. 使用 -v 选项查看详细输出
stap -v script.stp
2. 使用 -p4 只编译不运行,检查语法
stap -p4 script.stp
3. 使用 -L 列出可用的探针
stap -'process("myapp").function("*")'
4. 使用 -D 添加调试信息
stap -DDEBUG_UNWIND script.stp

📌 七、快速参考手册

检查环境

# 检查 uprobes 支持
grep CONFIG_UPROBES /boot/config-$(uname -r)
# 检查 SystemTap 版本
stap -V
# 列出可用的用户态探针
stap -'process("myapp").function("*")'

常用探针模式

# 函数入口
probe process("PATH").function("func")
# 函数返回
probe process("PATH").function("func").return
# 系统调用
probe process("PATH").syscall.open
# 系统调用返回
probe process("PATH").syscall.open.return
# 静态标记
probe process("PATH").mark("marker")
# 进程生命周期
probe process("PATH").begin
probe process("PATH").end

常用变量和函数

# 进程信息
pid()          # 进程 ID
tid()          # 线程 ID
execname()     # 可执行文件名
ppid()         # 父进程 ID
uid()          # 用户 ID
# 系统调用相关
$syscall       # 系统调用号
$arg1-$arg6    # 系统调用参数
$return        # 系统调用返回值
syscall_name() # 系统调用名称
# 用户态数据读取
user_string($ptr)
user_int($ptr)
user_long($ptr)
# 栈回溯
ubacktrace()
print_usyms(ubacktrace())
# 上下文变量
$$parms        # 函数参数
$$locals       # 局部变量
$$vars         # 所有变量

常用命令行选项

# 指定可执行文件的调试信息
stap -/path/to/executable script.stp
# 自动加载共享库符号
stap -/path/to/executable --ldd script.stp
# 运行命令并探测
stap script.stp -"command args"
# 附加到运行中的进程
stap script.stp -x PID
# 详细输出
stap -v script.stp
# 只编译不运行
stap -p4 script.stp
# 列出可用探针
stap -'probe_pattern'

🏁 总结

SystemTap 的用户态探针功能让我们能够深入应用程序内部,无需修改代码、无需重启程序,就能获得详细的运行时信息。通过本文的学习,你应该掌握了:

1

基础知识

用户态探针的先决条件(uprobes、debuginfo)
各种用户态事件类型及其用法
2

核心技能

如何访问用户态变量和指针
如何生成和分析调用栈回溯
如何编写实用的探测脚本
3

最佳实践

性能优化技巧
安全使用建议
常见问题解决方法
4

实战能力

能够针对具体问题设计探测方案
能够分析 GC、I/O、内存等常见问题
能够安全地在生产环境使用

记住三个关键点:

✅ 内核要有 uprobes:检查内核配置
✅ 目标要有调试符号:安装 debuginfo 包
✅ 输出要控频控量:避免性能影响

用户态探针让 SystemTap 的"隐形摄像头"从内核一路拍到应用层:函数、mark、syscall、栈回溯一网打尽。用好这些技巧,线上定位"诡异用户态问题"就不再盲人摸象。

现在,挑一个你正在运行的程序,挂上第一颗用户态探针,开始你的调试之旅吧!🚀


相关文章推荐:

SystemTap 入门指南
SystemTap 运作原理解析
SystemTap 实用脚本分享

最新文章

随机文章

基本 文件 流程 错误 SQL 调试
  1. 请求信息 : 2026-02-10 11:56:32 HTTP/2.0 GET : https://f.mffb.com.cn/a/458959.html
  2. 运行时间 : 0.139647s [ 吞吐率:7.16req/s ] 内存消耗:5,478.45kb 文件加载:140
  3. 缓存信息 : 0 reads,0 writes
  4. 会话信息 : SESSION_ID=3ee57c41aaee5b8bebad484fafe38c3e
  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.000803s ] mysql:host=127.0.0.1;port=3306;dbname=f_mffb;charset=utf8mb4
  2. SHOW FULL COLUMNS FROM `fenlei` [ RunTime:0.001436s ]
  3. SELECT * FROM `fenlei` WHERE `fid` = 0 [ RunTime:0.000601s ]
  4. SELECT * FROM `fenlei` WHERE `fid` = 63 [ RunTime:0.019113s ]
  5. SHOW FULL COLUMNS FROM `set` [ RunTime:0.001486s ]
  6. SELECT * FROM `set` [ RunTime:0.002195s ]
  7. SHOW FULL COLUMNS FROM `article` [ RunTime:0.001567s ]
  8. SELECT * FROM `article` WHERE `id` = 458959 LIMIT 1 [ RunTime:0.001506s ]
  9. UPDATE `article` SET `lasttime` = 1770695792 WHERE `id` = 458959 [ RunTime:0.020574s ]
  10. SELECT * FROM `fenlei` WHERE `id` = 67 LIMIT 1 [ RunTime:0.000786s ]
  11. SELECT * FROM `article` WHERE `id` < 458959 ORDER BY `id` DESC LIMIT 1 [ RunTime:0.001207s ]
  12. SELECT * FROM `article` WHERE `id` > 458959 ORDER BY `id` ASC LIMIT 1 [ RunTime:0.001129s ]
  13. SELECT * FROM `article` WHERE `id` < 458959 ORDER BY `id` DESC LIMIT 10 [ RunTime:0.005273s ]
  14. SELECT * FROM `article` WHERE `id` < 458959 ORDER BY `id` DESC LIMIT 10,10 [ RunTime:0.003029s ]
  15. SELECT * FROM `article` WHERE `id` < 458959 ORDER BY `id` DESC LIMIT 20,10 [ RunTime:0.002547s ]
0.141167s