如何使用 /proc/ 找到子任务(线程)的堆栈/地图?

如何使用 /proc/ 找到子任务(线程)的堆栈/地图?

目的:

我正在理论如何在 Linux 环境中创建指针扫描器。

免责声明:

我的发现已经在 Debian Bookworm(当前稳定版)和具有自定义内核的 Gentoo 系统上进行了测试。没有观察到差异。

问题:

在不将调试器附加到目标进程的情况下,我希望能够识别每个线程/子任务堆栈的 VMA。这应该可以使用以下方法实现进程伪文件系统

讨论:

在 Linux 4.5 之前,将在路径名字段中/proc/[parent_tid]/maps标记父任务的堆栈区域,并使用 标记每个子任务的堆栈区域。[STACK][STACK:child_tid]

在 Linux 4.5 之后,只有父任务的堆栈区域保留其[STACK]标签。子任务堆栈区域现在没有标签。在此更改的提交消息中(请参阅链接 1),Johannes Weiner 指出,仍然可以通过观察子任务堆栈 VMA 的流程图来查看它们/proc/[parent_tid]/task/[child_tid]/maps

事实证明这对我来说是无效的。父任务和子任务之间的内存区域映射是相同的。/proc/[parent_tid]/maps== /proc/[parent_tid]/task/[child_tid*]/maps。这最终意味着[STACK]标签贴在同一区域。

/proc/[tid]/stat可用于查找给定任务的堆栈底部的 VMA。这是第 28 个值(参见 man 5 proc)。再次,/proc/[parent_tid]/stat/proc/[parent_tid]/task/[child_tid*]/stat显然,子任务不与进程中的所有其他任务共享堆栈的开头。

clone(2),用于创建新子任务的系统调用,采用堆栈指针作为参数。获取堆栈内存的最明显方法是通过匿名mmap(2)。匿名内存映射在/proc/[tid]/maps.通过观察一些单线程和多线程进程,匿名内存映射的数量和程序的线程数之间存在直接的相关性。虽然此类映射不仅仅用于线程堆栈,但我非常希望线程堆栈能够以这种方式分配。每个内存映射在 中都有自己的条目/proc/[tid]/maps。当然有一种方法可以确定其中哪些充当子任务堆栈?

我在这里犯了什么错?


相关链接:

  1. [STACK:tid]承诺从以下位置删除标签/proc/[tid]/maps
    https://lists.ubuntu.com/archives/kernel-team/2016-March/074681.html

答案1

第 28 个字段适用于我,在 Linux 6.1.0 上。请注意,任务不会有自己的堆栈,除非它们需要它。

这是一个要运行的简单脚本,它应该返回不同的底部堆栈值一些的任务。您可能需要下载/安装 Firefox。

#!/bin/bash

# create a temporary profile
test -d /tmp/temporary_profile || mkdir /tmp/temporary_profile

# run Firefox on that profile
firefox --profile /tmp/temporary_profile &

# Give it some time to create the tasks
sleep 10

# Get the PID
FFPID=$!

# Print field 28 of the stat files
awk '{print FILENAME" "$28}' /proc/$FFPID/stat /proc/$FFPID/task/*/stat

如果您运行的是 Firefox,则可以运行以下行并键入其当前进程 ID:

read a;awk '{print FILENAME" "$28}' /proc/$a/stat /proc/$a/task/*/stat

它可以与其他多线程程序一起使用,但我知道 Firefox 几乎会立即创建一些具有自己的堆栈的任务,这可能会帮助您检查代码是否正常工作。

相关内容