Linker 用于在Perf中确定库加载地址的机制

Linker 用于在Perf中确定库加载地址的机制,linker,shared-libraries,ip-address,trace,perf,Linker,Shared Libraries,Ip Address,Trace,Perf,在后处理期间,perf如何确定每个加载映像(例如,共享库)的加载地址。例如,perf report使用此信息使每个符号地址相对于每个加载图像的开头。如下图所示(展开:\u int\u malloc…): 它是否存储在elf二进制输出或分析输出(即perf.data)的某个位置?仅通过查看elf可执行文件和库是无法找到它的。每次跑步都会有所不同;即使ASLR像GDB一样被perf禁用,程序也可能在使用某些只在稍后加载的可选库的dlopen之前使用mmap(MAP\u FIXED),因此dlope

在后处理期间,
perf
如何确定每个加载映像(例如,共享库)的加载地址。例如,
perf report
使用此信息使每个符号地址相对于每个加载图像的开头。如下图所示(
展开:\u int\u malloc…
):


它是否存储在
elf
二进制输出或分析输出(即
perf.data
)的某个位置?

仅通过查看elf可执行文件和库是无法找到它的。每次跑步都会有所不同;即使ASLR像GDB一样被perf禁用,程序也可能在使用某些只在稍后加载的可选库的
dlopen
之前使用
mmap(MAP\u FIXED)
,因此dlopen必须选择一个与通常不同的地址来映射库。(正常的动态链接发生在运行
main
之前,不是通过dlopen,但大概
perf
希望能够记录任何文件备份映射的地址->文件映射。)


perf可能会将每个ELF对象的运行时基址保存在
perf.data

中。共享库加载地址存储在
perf record
命令期间记录的perf.data文件中。您可以使用
perf script-D
命令以部分解码的格式转储perf.data中的数据。当您的程序由
ld linux*.so.2
加载时(或dlopen需要时),加载程序将使用
mmap
syscall搜索库并加载其段。这些mmap事件由内核记录,其类型为PERF_RECORD_mmap或PERF.data文件。和
perf report
(和
perf script
)将重建内存偏移量以解码符号名称

$ perf record  echo 1
$ perf script -D|grep MMAP -c
7
$ perf script -D|less
PERF_RECORD_MMAP2 ... r-xp /bin/echo
...
PERF_RECORD_MMAP2 ... r-xp /lib/x86_64-linux-gnu/libc-2.27.so
文件中描述了
perf
的基本思想。要开始分析,有一个参数具有
perf\u event\u attr*attr
参数。描述属性的mmap相关字段:

   The perf_event_attr structure provides detailed configuration
   information for the event being created.

                 mmap           : 1,   /* include mmap data */
                 mmap_data      : 1,   /* non-exec mmap data */
                 mmap2          :  1,  /* include mmap with inode data */
Linux内核在其
perf_events
子系统(内核/事件)中将记录所分析的进程所需的事件,并将带有fd和mmap的数据导出到分析程序
perf record
通常将此数据从内核转储到perf.data文件中,而无需进行大量处理(检查
perf record
输出的“唤醒1次以写入数据”打印)。内核中的Mmap事件由called from记录,called from从中调用。
mm/mmap.c
中的mmap syscall实现有一些对的无条件调用

perf的design.txt提到了munmap,但当前的实现没有munmap字段或事件,事件代码2被重用为。有人认为,munmap可以通过与和的链接提供帮助

perf tool是linux内核源代码的一部分,可以通过LXR/elixir网站在线查看: mmap/mmap2事件的处理代码位于perf/util/machine.c和中;在进程(pid/tid)的
map\uuuu new
thread\uuuu insert\u map
的帮助下,记录的mmap参数、返回地址、偏移量和文件名,稍后用于将样本事件地址转换为符号名


PS:您的性能数据大小为300+MB,这是巨大的,处理速度可能会很慢。对于长时间运行的程序,您可能希望使用
perf record
-F freq
选项
perf record-F40
-c
选项来降低perf record事件采样频率。

在极少数情况下,可以添加、删除库并再次将其添加到地址空间(可能位于与旧库不同的地址)。因此,
perf
也应该能够处理这些情况,以便正确工作。我说得对吗?我的意思是,它应该考虑时间问题。@艾哈迈德:好问题,我不知道。如果
perf
像strace那样钩住mmap/munmap,它可以跟踪变化。但是,
perf
可能会做一些更简单的事情,可能会因为取消一个库的映射,然后将另一个库映射到一个重叠的地址范围而混淆。perf不钩住mmap,内核中的perf_事件子系统可以将mmap(理论上是munmap)事件直接记录到缓冲区中,缓冲区在
perf record
处转储到perf.data。检查性能记录MMAP2和手册页(标记mmap:1和MMAP2:1)的性能脚本-D的输出。没有munmap事件,但在2017年和2018年的LKML中建议了它。munmap在perf/design.txt中声明,但在当前版本中未实施;性能代码2用于。用于添加munmap的线程:;链接到和。通过linux内核(perf tools)的
tools/perf/util/machine.c
中的
machine\uuu process\u Mmap\u事件处理的Mmap记录,借助
map\uu new
thread\uu insert\u map
@osgx:这些注释可能是一个很好的单独答案。谢谢你解释这个机制;内核有助于识别哪个地址与哪个文件相匹配,而不仅仅是用它们的虚拟地址记录事件。因此,您可以说只跟踪
mmap()
(而不是
munmap()
)。是的,在perf.data文件中只记录mmap。但没有显式munmap跟踪性能报告的事件可能会处理mmap/munmap/mmap序列,因为第二个mmap将被完全记录。