如何在Linux用户和内核空间中进行动态跟踪

如何在Linux用户和内核空间中进行动态跟踪,第1张

你不记得如何在代码中插入探针点了吗? 没问题!了解如何使用uprobe和kprobe来动态插入它们吧。 基本上,程序员需要在源代码汇编指令的不同位置插入动态探针点。

探针点

探针点是一个调试语句,有助于探索软件的执行特性(即,执行流程以及当探针语句执行时软件数据结构的状态)。printk是探针语句的最简单形式,也是黑客用于内核攻击的基础工具之一。

因为它需要重新编译源代码,所以printk插入是静态的探测方法。内核代码中重要位置上还有许多其他静态跟踪点可以动态启用或禁用。 Linux内核有一些框架可以帮助程序员探测内核或用户空间应用程序,而无需重新编译源代码。Kprobe是在内核代码中插入探针点的动态方法之一,并且uprobe在用户应用程序中执行此 *** 作。

使用uprobe跟踪用户空间

可以通过使用thesysfs接口或perf工具将uprobe跟踪点插入用户空间代码。

使用sysfs接口插入uprobe

考虑以下简单测试代码,没有打印语句,我们想在某个指令中插入探针:

[source,c\n.test.c

#include <stdio.h>\n#include <stdlib.h>\n#include <unistd.h>

编译代码并找到要探测的指令地址:

# gcc -o test test.\n# objdump -d test

假设我们在ARM64平台上有以下目标代码:

0000000000400620 <func_1>: 400620\t90000080\tadr\tx0, 410000 <__FRAME_END__+0xf6f8>

并且我们想在偏移量0x620和0x644之间插入探针。执行以下命令:

# echo 'p:func_2_entry test:0x620' >/sys/kernel/debug/tracing/uprobe_event\n# echo 'p:func_1_entry test:0x644' >>/sys/kernel/debug/tracing/uprobe_event\n# echo 1 >/sys/kernel/debug/tracing/events/uprobes/enable# ./test&

在上面的第一个和第二个echo语句中,p告诉我们这是一个简单的测试。(探测器可以是简单的或返回的。)func_n_entry是我们在跟踪输出中看到的名称,名称是可选字段,如果没有提供,我们应该期待像p_test_0x644这样的名字。test 是我们要插入探针的可执行二进制文件。如果test 不在当前目录中,则需要指定path_to_test / test。

0x620或0x640是从程序启动开始的指令偏移量。请注意>>在第二个echo语句中,因为我们要再添加一个探针。所以,当我们在前两个命令中插入探针点之后,我们启用uprobe跟踪,当我们写入events/ uprobes / enable时,它将启用所有的uprobe事件。程序员还可以通过写入在该事件目录中创建的特定事件文件来启用单个事件。一旦探针点被插入和启用,每当执行探测指令时,我们可以看到一个跟踪条目。

读取跟踪文件以查看输出:

# cat /sys/kernel/debug/tracing/trac\n# tracer: no\n\n# entries-in-buffer/entries-written: 8/8\n#P:\n\n# _-----=>irqs-of\n# / _----=>need-resche\n# | / _---=>hardirq/softir\n# || / _--=>preempt-dept\n# ||| / dela\n# TASK-PID CP\n# |||| TIMESTAMP FUNCTION# | | | |||| | |

我们可以看到哪个CPU完成了什么任务,什么时候执行了探测指令。

返回探针也可以插入指令。当返回该指令的函数时,将记录一个条目:

# echo 0 >/sys/kernel/debug/tracing/events/uprobes/enabl\n# echo 'r:func_2_exit test:0x620' >>/sys/kernel/debug/tracing/uprobe_event\n# echo 'r:func_1_exit test:0x644' >>/sys/kernel/debug/tracing/uprobe_event\n# echo 1 >/sys/kernel/debug/tracing/events/uprobes/enable

这里我们使用r而不是p,所有其他参数是相同的。请注意,如果要插入新的探测点,需要禁用uprobe事件:

test-3009 [002] .... 4813.852674: func_1_entry: (0x400644)

上面的日志表明,func_1返回到地址0x4006b0,时间戳为4813.852691。

# echo 0 >/sys/kernel/debug/tracing/events/uprobes/enabl\n# echo 'p:func_2_entry test:0x630' >/sys/kernel/debug/tracing/uprobe_events count=%x\n# echo 1 >/sys/kernel/debug/tracing/events/uprobes/enabl\n# echo >/sys/kernel/debug/tracing/trace# ./test&

当执行偏移量0x630的指令时,将打印ARM64 x1寄存器的值作为count =。

输出如下所示:

test-3095 [003] .... 7918.629728: func_2_entry: (0x400630) count=0x1

使用perf插入uprobe

找到需要插入探针的指令或功能的偏移量很麻烦,而且需要知道分配给局部变量的CPU寄存器的名称更为复杂。 perf是一个有用的工具,用于帮助引导探针插入源代码中。

除了perf,还有一些其他工具,如SystemTap,DTrace和LTTng,可用于内核和用户空间跟踪;然而,perf与内核配合完美,所以它受到内核程序员的青睐。

# gcc -g -o test test.c# perf probe -x ./test func_2_entry=func_\n# perf probe -x ./test func_2_exit=func_2%retur\n# perf probe -x ./test test_15=test.c:1\n# perf probe -x ./test test_25=test.c:25 numbe\n# perf record -e probe_test:func_2_entry -e\nprobe_test:func_2_exit -e probe_test:test_15\n-e probe_test:test_25 ./test

如上所示,程序员可以将探针点直接插入函数start和return,源文件的特定行号等。可以获取打印的局部变量,并拥有许多其他选项,例如调用函数的所有实例。 perf探针用于创建探针点事件,那么在执行./testexecutable时,可以使用perf记录来探测这些事件。当创建一个perf探测点时,可以使用其他录音选项,例如perf stat,可以拥有许多后期分析选项,如perf脚本或perf报告。

使用perf脚本,上面的例子输出如下:

# perf script

使用kprobe跟踪内核空间

与uprobe一样,可以使用sysfs接口或perf工具将kprobe跟踪点插入到内核代码中。

使用sysfs接口插入kprobe

程序员可以在/proc/kallsyms中的大多数符号中插入kprobe;其他符号已被列入内核的黑名单。还有一些与kprobe插入不兼容的符号,比如kprobe_events文件中的kprobe插入将导致写入错误。 也可以在符号基础的某个偏移处插入探针,像uprobe一样,可以使用kretprobe跟踪函数的返回,局部变量的值也可以打印在跟踪输出中。

以下是如何做:

disable all events, just to insure that we see only kprobe output in trace\n# echo 0 >/sys/kernel/debug/tracing/events/enabledisable kprobe events until probe points are inseted\n# echo 0 >/sys/kernel/debug/tracing/events/kprobes/enableclear out all the events from kprobe_events\n to insure that we see output foronly those for which we have enabled

[root@pratyush ~\n# more /sys/kernel/debug/tracing/trace# tracer: no\n\n# entries-in-buffer/entries-written: 9037/9037\n#P:8\n# _-----=>irqs-of\n# / _----=>need-resche\n# | / _---=>hardirq/softirq#\n|| / _--=>preempt-depth#\n ||| / delay# TASK-PID CPU#\n |||| TIMESTAMP FUNCTION#\n | | | |||| | |

使用perf插入kprobe

与uprobe一样,程序员可以使用perf在内核代码中插入一个kprobe,可以直接将探针点插入到函数start和return中,源文件的特定行号等。程序员可以向-k选项提供vmlinux,也可以为-s选项提供内核源代码路径:

# perf probe -k vmlinux kfree_entry=kfre\n# perf probe -k vmlinux kfree_exit=kfree%retur\n# perf probe -s ./ kfree_mid=mm/slub.c:3408 \n# perf record -e probe:kfree_entry -e probe:kfree_exit -e probe:kfree_mid sleep 10

使用perf脚本,以上示例的输出:

关于Linux命令的介绍,看看《linux就该这么学》,具体关于这一章地址3w(dot)linuxprobe/chapter-02(dot)html

tracer 是一个高级的性能分析和诊断工具,但是不要让这名词唬住你,如果你使用过 strace 和tcpdump,其实你就已经使用过 tracer 了。系统 tracer 可以获取更多的系统调用和数据包。它们通常能跟踪任意的内核和应用程序。

有太多的 linux tracer 可以选择。每一种都有其官方的(或非官方的)的卡通的独角兽吉祥物,足够撑起一台"儿童剧"了。

那么我们应该使用哪个 tracer 呢?

我会为两类读者回答这个问题,大部分人和性能/内核工程师。过一段时间这些可能会发生变化,我会持续跟进并补充,大概会一年更新一次。

多数人

多数人 (开发者,系统管理员,开发管理者,运维人员,评测人员,等等) 不关心系统追踪器的细节。下面是对于追踪器你应该知道和做的:

1. 使用perf_events分析CPU性能

使用 perf_events 做 CPU 性能分析。性能指标可以使用flame graph 等工具做可视化。

git clone --depth 1 https://github.com/brendangregg/FlameGraph

perf record -F 99 -a -g -- sleep 30

perf script | ./FlameGraph/stackcollapse-perf.pl | ./FlameGraph/flamegraph.pl >perf.svg

Linux perf_events (又称 "perf",同命令名) 是 Linux 用户的官方追踪器和性能分析器。内置于内核代码,有很好维护(近来获得快速增强),通常通过 linux 命令行工具包添加。

perf 有很多功能,如果只能推荐一个,我选择 CPU 性能分析。尽管这只是采样,而不是从技术上追踪事件。最难的部分是获取完整的栈和信息,我为 java 和 node.js 做的一个演讲 Linux Profiling at Netflix中已经说过这个问题

2.了解其他的Tracer

正如我一个朋友说的:“你不需要知道如何 *** 作 X 射线机器,但是一旦你吞了一枚硬币,你得知道这得去做 X 射线”,你应该了解各种 tracer 都能做什么,这样就能在你工作中真正需要 tracer 的时候,你既可以选择稍后学习使用,也可以雇相应的人来完成。

简短来说:几乎所有的东西都可以使用 tracer 来进行分析和跟踪。如,文件系统,网络处理器,硬件驱动器,全部的应用程序。可以看一下我的个人网站上关于 ftrace的文章,还有我写的关于perf_events 文档介绍,可以做为一个追踪(或者性能分析)的例子。

3. 寻求前端支持工具

如果你正想买一个能支持跟踪 Linux 的性能分析工具(有许多卖这类工具的公司)。想像一下,只需要直接点击一下界面就能“洞察”整个系统内核,包括隐藏的不同堆栈位置的热图,我在Monitorama talk 中介绍了一个这样带图形界面的工具。

我开源了一些我自己开发的前端工具,尽管只是 CLI (命令行界面)而不是(图形界面)。这些工具也会让人们更加快速容易的使用 tracer。比如下面的例子,用我的 perf_tool,跟踪一个新进程:

# ./execsnoopTracing exec()s. Ctrl-C to end.

PID PPID ARGS

22898 22004 man ls

22905 22898 preconv -e UTF-8

22908 22898 pager -s

22907 22898 nroff -mandoc -rLL=164n -rLT=164n -Tutf8

[...]

在 Netflix 上,我们创建了一个 Vector,一个分析工具的实例同时也是 Linux 上的 tracer 的最终前端。

致性能或内核工程师

我们的工作变的越来越困难,很多的人会问我们怎么样去追踪,哪种路径可以用!为了正确理解一个路径,你经常需要花上至少100个小时才能做到。理解所有的 linux 路径去做出理性的决定是一个浩大的工程。(我可能是唯一一个接近做到这件事情的人)

这里是我的建议,可以二选其一:

A) 选中一个全能的路径,并且使它标准化,这将涉及花费大量的时间去弄清楚它在测试环境中的细微差别和安全性。我现在推荐 SystemTap 的最新版本(ie,从源代码构建)。我知道有些公司已经选用 LTTng,而且他们用的很好,尽管它不是非常的强大(虽然它更安全)。Sysdig 可以成为另一个候选如果它可以增加追踪点或者 kprobes。

B) 遵循我上面提供的流程图,它将意味着尽可能更多的使用 ftrace 或者 perf_event, eBPF 会得到整合,之后其他的路径像 SystemTap/LTTng 会去填补这个空白。这就是我目前在 Netflix 做的工作。

tracer 的评论:

1. ftrace

我喜欢用 ftrace,它是内核 hacker 的首选,内置于系统内核,可以使用跟踪点(静态检查点),能调用内核 kprobes 和 uprobes 调试工具。并且提供几个这样的功能:带可选过滤器和参数的事件追踪功能;在内核中进行统计的事件计数和定时功能;还有函数流程遍历的功能。可以看一下内核代码中 ftrace.txt 例子了解一下。ftrace 由 /sys 控制,仅支持单一的 root 用户使用(但是你可以通过缓冲区实例破解以支持多用户)。某些时候 Ftrace 的 *** 作界面非常繁琐,但是的确非常“hack”,而且它有前端界面。Steven Rostedt,ftace 的主要作者,创建了 trace-cmd 命令工具,而我创建了 perf 的工具集。我对这个工具最大的不满就是它不可编程。举例来说,你不能保存和获取时间戳,不能计算延迟,不能把这些计算结果保存成直方图的形式。你需要转储事件至用户级别,并且花一些时间去处理结果。ftrace 可以通过 eBPF 变成可编程的。

2.perf_events

perf_events 是 Linux 用户的主要跟踪工具,它内置在内核源码中,通常通过 linux-tools-commom 加入。也称“perf”,同前端工具名称,通常用来跟踪和转储信息到一个叫做 perf.data 的文件中,perf.data 文件相当于一个动态的缓冲区,用来保存之后需要处理的结果。ftrace 能做到的,perf_events 大都也可以做到,perf-events 不能做函数流程遍历,少了一点儿“hack”劲儿(但是对于安全/错误检查有更好的支持)。它可以进行 CPU 分析和性能统计,用户级堆栈解析,也可以使用对于跟踪每行局部变量产生的调试信息。它也支持多用户并发 *** 作。和 ftrace 一样也不支持可编程。如果要我只推荐一款 tracer,那一定是 perf 了。它能解决众多问题,并且它相对较安全。

3. eBPF

extended Berkeley Packet Filter(eBPF)是一个可以在事件上运行程序的高效内核虚拟机(JIT)。它可能最终会提供 ftrace 和 perf_events 的内核编程,并强化其他的 tracer。这是 Alexei Starovoitov 目前正在开发的,还没有完全集成,但是从4.1开始已经对一些优秀的工具有足够的内核支持了,如块设备I/O的延迟热图。可参考其主要作者 Alexei Starovoitov 的BPF slides和eBPF samples。

4. SystemTap

SystemTap 是最强大的tracer。它能做所有事情,如概要分析,跟踪点,探针,uprobes(来自SystemTap),USDT和内核编程等。它将程序编译为内核模块,然后加载,这是一种获取安全的巧妙做法。它也是从tree发展而来,在过去有很多问题(多的可怕)。很多不是 SystemTap 本身的错——它常常是第一个使用内核追踪功能,也是第一个碰到 bug 的。SystemTap 的最新版本好多了(必须由源代码编译),但是很多人仍然会被早期版本吓到。如果你想用它,可先在测试环境中使用,并与irc.freenode.net上 的 #systemtap 开发人员交流。(Netflix 有容错机制,我们已经使用了 SystemTap,但是可能我们考虑的安全方面的问题比你们少。)我最大的不满是,它似乎认为你有常常没有的内核 debug 信息。实际上没有它也能做很多事情,但是缺少文档和例子(我必须自己全靠自己开始学习)。

5. LTTng

LTTng 优化了事件采集,这比其他 tracers 做得好。它从 tree 发展而来,它的核心很简单:通过一组小规模的固定指令集将事件写入追踪缓冲区,这种方式使它安全、快速,缺点是它没有内核编码的简单途径。我一直听说这不是一个大问题,因为尽管需要后期处理,它也已经优化到可以充分的度量。此外,它还首创了一个不同的分析技术,更多对所有关注事件的黑盒记录将稍后以 GUI 的方式进行研究。我关心的是前期没有考虑到要录制的事件缺失问题如何解决,但我真正要做的是花更多时间来看它在实践中用的怎么样。这是我花的时间最少的一个 tracer(没有什么特殊原因)。

6. Ktap

ktap 在过去是一款前景很好的 tracer,它使用内核中的 lua 虚拟机处理,在没有调试信息的情况下在嵌入式设备上运行的很好。它分为几个步骤,并在有一段时间似乎超过了 Linux 上所有的追踪器。然后 eBPF 开始进行内核集成,而 ktap 的集成在它可以使用 eBPF 替代它自己的虚拟机后才开始。因为 eBPF 仍将持续集成几个月,ktap 开发者要继续等上一段时间。我希??今年晚些时候它能重新开发。

7. dtrace4linux

dtrace4linux 主要是 Paul Fox 一个人在业余时间完成的,它是 Sun DTrace 的 Linux 版本。它引入瞩目,还有一些 provider 可以运行,但是从某种程度上来说还不完整,更多的是一种实验性的工具(不安全)。我认为,顾忌到许可问题,人们会小心翼翼的为 dtrace4linux 贡献代码:由于当年 Sun 开源DTrace 使用的是 CDDL 协议,而 dtrace4linux 也不大可能最终进入 Linux kernel。Paul 的方法很可能会使其成为一个 add-on。我很乐意看到 Linux 平台上的 DTrace 和这个项目的完成,我认为当我加入 Netflix 后将会花些时间来协助完成这个项目。然而,我还是要继续使用内置的 tracers,如 ftrace 和 perf_events。

8.OL DTrace

Oracle Linux DTrace为了将 DTrace 引入 Linux,特别是 Oracle Linux,做出了很大的努力。这些年来发布的多个版本表明了它的稳定进展。开发者们以一种对这个项目的前景看好的态度谈论着改进 DTrace 测试套件。很多有用的 provider 已经完成了,如:syscall, profile, sdt, proc, sched 以及 USDT。我很期待 fbt(function boundary tracing, 用于内核动态跟踪)的完成,它是 Linux 内核上非常棒的 provider。OL DTrace 最终的成功将取决于人们对运行 Oracle Linux(为技术支持付费)有多大兴趣,另一方面取决于它是否完全开源:它的内核元件是开源的,而我没有看到它的用户级别代码。

9. sysdig

sysdig是一个使用类tcpdump语法来 *** 作系统事件的新tracer,它使用lua提交进程。它很优秀,它见证了系统跟踪领域的变革。它的局限性在于它只在当前进行系统调用,在提交进行时将所有事件转储为用户级别。你可以使用系统调用做很多事情,然而我还是很希望它能支持跟踪点、kprobe和uprobe。我还期待它能支持eBPF做内核摘要。目前,sysdig开发者正在增加容器支持。留意这些内容。

延伸阅读

我关于 tracer 的工作包括:

ftrace:我的 perf-tools工具集(参考实例目录);我在 lwn.net 上的 关于ftrace的文章;LISA14的发言;还有帖子:函数计数, iosnoop,opensnoop,execsnoop,TCP转发, uprobes 以及USDT。

perf_evenets:我的网页 perf_events实例;SCALE上的发言Netflix的Linux性能分析;还有帖子CPU采样,静态追踪点,热点图,计数,内核行追踪,off-CPU时间图。

eBPF:帖子eBPF:迈出一小步,和一些BPF工具(我需要发布更多)。

SystemTap:我很久以前写了一篇有点过期的帖子使用SystemTap。最近,我发布了一些工具systemtap-lwtools来演示如何在没有内核诊断信息的情况下使用SystemTap。

LTTng:我只花了一点时间,还不足以发表任何内容。

ktap:我的网页ktap实例包含一些早期版本的单行小程序和脚本。

dtrace4linux:我在系统性能一书中给出了一些实例,并曾经开发了一些小的修复程序,如timestamps。

OL DTrace:由于它直接由DTrace转变而来,很多我早期关于DTrace的工作都有相关性(如果在这里给出链接的话就太多了,可以在我的主页上搜索)。当它更完善时,我会开发一些特殊工具。

sysdig:我向 fileslower 和 subsecond offset spectrogram 贡献了代码。

其他:我写了关于strace 的注意事项。

请不要有更多的 tracer!如果你想知道为什么 Linux 不仅仅只有一个 tracer,或者只用本身的DTrace,你可以在我的演讲稿从DTrace到Linux中找到答案,从28张幻灯片开始。

感谢Deirdré Straughan的编辑,以及与 General Zoi 的小马宝莉创作者一起创作的 tracing 小马。

1、定义上:

su为switch user,即切换用户的简写。su是最简单的身份切换名,用su我们能够进行不论什么用户的切换,一般都是su - username,然后输入password就ok了,可是root用su切换到其它身份的时候是不须要输入password的。

sudo是一种权限管理机制e79fa5e98193e4b893e5b19e31333366306434,依赖于/etc/sudoers,其定义了授权给哪个用户可以以管理员的身份能够执行什么样的管理命令。

2、格式上:

su格式为两种:su -l USERNAME(-l为login,即登陆的简写)、su USERNAME。

sudo格式:sudo -u USERNAME COMMAND。

3、默认情况下:

su默认情况下如果不指定USERNAME(用户名),默认即为root,所以切换到root的身份的命令即为:su -root或su -,su root 或su。

sudo默认情况下,系统只有root用户可以执行sudo命令。需要root用户通过使用visudo命令编辑sudo的配置文件/etc/sudoers,才可以授权其他普通用户执行sudo命令。

4、密码上:

两个命令的最大区别是:sudo 命令需要输入当前用户的密码,su 命令需要输入 root 用户的密码。

5、日志记录上:

尽管 sudo 命令是以目标用户(默认情况下是 root 用户)的身份执行命令,但是它们会使用 sudoer所配置的用户名来记录是谁执行命令。而 su 命令是无法直接跟踪记录用户切换到 root 用户之后执行了什么 *** 作。

6、灵活性

sudo 命令比 su 命令灵活很多,因为甚至可以限制 sudo 用户可以访问哪些命令。换句话说,用户通过 sudo 命令只能访问他们工作需要的命令。而 su 命令让用户有权限做任何事情。


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/yw/7323383.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-04-04
下一篇 2023-04-04

发表评论

登录后才能评论

评论列表(0条)

保存