如何在较新的Linux内核中查找堆栈内存段

szqfcxe2  于 5个月前  发布在  Linux
关注(0)|答案(2)|浏览(63)

我有一个小库,它写了一个“瘦核心”,其中只包含堆栈信息(以及有效核心所需的其他位),但不包括任何堆。这并不总是有用的,但核心比完整的核心小得多,有时人们不想提供堆的内容。
这个库通过阅读/proc/<PID>/maps并定位[stack][stack:<tid>]段来工作(这个过程有很多线程)。例如,我会看到这样的输出:

...
7fe848000000-7fe848021000 rw-p 00000000 00:00 0 
7fe848021000-7fe84c000000 ---p 00000000 00:00 0 
7fe84c1ff000-7fe84c200000 ---p 00000000 00:00 0 
7fe84c200000-7fe84ca00000 rw-p 00000000 00:00 0    [stack:25672]
7fe84ca00000-7fe84cc00000 rw-p 00000000 00:00 0 
7fe84cdff000-7fe84ce00000 ---p 00000000 00:00 0 
7fe84ce00000-7fe84d600000 rw-p 00000000 00:00 0    [stack:25534]
7fe84d600000-7fe84d800000 rw-p 00000000 00:00 0 
7fe84d9ff000-7fe84da00000 ---p 00000000 00:00 0 
7fe84da00000-7fe84e200000 rw-p 00000000 00:00 0    [stack:25532]
7fe84e200000-7fe84e600000 rw-p 00000000 00:00 0 
7fe84e7fd000-7fe84e7fe000 ---p 00000000 00:00 0 
7fe84e7fe000-7fe84effe000 rw-p 00000000 00:00 0    [stack:25531]
7fe84effe000-7fe84efff000 ---p 00000000 00:00 0 
7fe84efff000-7fe84f7ff000 rw-p 00000000 00:00 0    [stack:25530]
7fe84f7ff000-7fe84f800000 ---p 00000000 00:00 0 
7fe84f800000-7fe850000000 rw-p 00000000 00:00 0    [stack:25529]
7fe850000000-7fe850021000 rw-p 00000000 00:00 0 
7fe850021000-7fe854000000 ---p 00000000 00:00 0 
7fe854000000-7fe854400000 rw-p 00000000 00:00 0 
7fe8545ff000-7fe854600000 ---p 00000000 00:00 0
  ...
7fff5ce1d000-7fff5ce3e000 rw-p 00000000 00:00 0    [stack]
  ...

字符串
这在旧的Linux内核上工作得很好,比如3.5(Ubuntu 12.04)和3.13(Ubuntu 14.04)。
然而,对于更新的内核(例如Ubuntu 16.04的4.4),/proc/<PID>/maps文件似乎不再包含每个线程堆栈段的任何条目。我只看到主堆栈[stack];所有看起来像堆栈段的内存段都有一个空的路径名部分。
这意味着我的“瘦核心”太薄,只提供主线程的堆栈。
我试过在较新的内核中检查/proc/<PID>/smaps,但在新的更有限的格式中,我找不到一种方法来确定哪些段与线程堆栈相关联,哪些不与线程堆栈相关联。
我也检查了procfs(5)手册页,它仍然列出了[stack:<tid>]作为我应该看到的东西,但我没有看到它。
有人知道这些信息去了哪里吗?我是否可以从其他可用的信息中推断出来?

mec1mxoz

mec1mxoz1#

我还没有找到解决这个问题的真实的方案,为了方便后人,我将描述一下我在短期内所做的事情:我使用pthread_attr_getstacksize()获取线程堆栈的大小,然后当我查看未命名的内存段以决定向“瘦核心”写入什么时,我保留了具有该大小的内存段,并忽略了其余部分。
这是一个相当狡猾的启发式方法,但这是我能想到的所有方法,而且从我有限的测试来看,它似乎很有效。
我仍然希望有人能提供一个更可靠/更强大的替代方案。

r1zk6ea1

r1zk6ea12#

查看这本proc手册,它解释说,从Linux版本4.4以上不再提供堆栈标识:
[stack:tid](从Linux 3.4到Linux 4.4)
一个线程的堆栈(其中tid是一个线程ID)。它对应于/proc/pid/task/tid/路径。这个字段在Linux 4.5中被删除了,因为为一个有大量线程的进程提供这个信息是昂贵的。
要检索smaps procfs文件中的堆栈,可以隔离前面有4 KB页的内存段,但没有读/写/执行权限(所谓的红区或用于捕获堆栈溢出的保护页)。但它并不是在所有情况下都有效,因为某些应用程序可能会使用pthread调用来分配专用堆栈(例如,通过pthread_attr_setstackaddr()),并且可以不定义保护区(例如,通过pthread_attr_setguardsize())。
在你的smaps代码段中,所有的堆栈都在guard页面之前:

7fe84c1ff000-7fe84c200000 ---p 00000000 00:00 0  <---- 4KB guard page
7fe84c200000-7fe84ca00000 rw-p 00000000 00:00 0    [stack:25672]
[...]
7fe84cdff000-7fe84ce00000 ---p 00000000 00:00 0  <---- 4KB guard page
7fe84ce00000-7fe84d600000 rw-p 00000000 00:00 0    [stack:25534]

字符串

相关问题