【问题标题】:How to get bottom of user stack under multi threads on Linux如何在 Linux 上的多线程下获取用户堆栈的底部
【发布时间】:2017-06-06 14:19:04
【问题描述】:

我想获取 64 位 Linux 上的用户堆栈信息。 我知道 mm->start_stack 表示用户堆栈的初始堆栈指针的位置。

但是,在像 pthread 这样的多线程应用程序中,mm->start_stack 是所有线程的相同值,因为使用了相同的 struct task_struct。

而且,我知道使用 mm->mmap->vm_start 和 mm->mmap->vm_end 的内存布局方式,但是我不知道这些 mmap 区域是否是堆栈。

我用 pmap 进程 id 和 strace 确认了这些下的内存布局。

您能告诉我如何获取所有线程的用户堆栈位置,如 mm->start_stack?。

sudo pmap 24074
24074:   ./a.out
0000000000400000      4K r-x-- a.out
0000000000600000      4K r---- a.out
0000000000601000      4K rw--- a.out
0000000000602000    132K rw---   [ anon ]
00007ffff5fee000      4K -----   [ anon ]
00007ffff5fef000   8192K rw---   [ anon ]   <==== Thread Stack
00007ffff67ef000      4K -----   [ anon ]
00007ffff67f0000   8192K rw---   [ anon ]   <==== Thread Stack
00007ffff6ff0000      4K -----   [ anon ]
00007ffff6ff1000   8192K rw---   [ anon ]   <==== Thread Stack
00007ffff77f1000   1792K r-x-- libc-2.23.so
00007ffff79b1000   2044K ----- libc-2.23.so
00007ffff7bb0000     16K r---- libc-2.23.so
00007ffff7bb4000      8K rw--- libc-2.23.so
00007ffff7bb6000     16K rw---   [ anon ]
00007ffff7bba000     96K r-x-- libpthread-2.23.so
00007ffff7bd2000   2044K ----- libpthread-2.23.so
00007ffff7dd1000      4K r---- libpthread-2.23.so
00007ffff7dd2000      4K rw--- libpthread-2.23.so
00007ffff7dd3000     16K rw---   [ anon ]
00007ffff7dd7000    152K r-x-- ld-2.23.so
00007ffff7fda000     12K rw---   [ anon ]
00007ffff7ff6000      8K rw---   [ anon ]
00007ffff7ff8000      8K r----   [ anon ]
00007ffff7ffa000      8K r-x--   [ anon ]
00007ffff7ffc000      4K r---- ld-2.23.so
00007ffff7ffd000      4K rw--- ld-2.23.so
00007ffff7ffe000      4K rw---   [ anon ]
00007ffffffde000    132K rw---   [ stack ]
ffffffffff600000      4K r-x--   [ anon ]
 total            31108K

跟踪结果

clone(child_stack=0x7ffff77efff0,flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID, parent_tidptr=0x7ffff77f09d0, tls=0x7ffff77f0700, child_tidptr=0x7ffff77f09d0) = 24075

clone(pid: 24074 child_stack=0x7ffff6feeff0, flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID, parent_tidptr=0x7ffff6fef9d0, tls=0x7ffff6fef700, child_tidptr=0x7ffff6fef9d0) = 24076

clone(child_stack=0x7ffff67edff0, flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID, parent_tidptr=0x7ffff67ee9d0, tls=0x7ffff67ee700, child_tidptr=0x7ffff67ee9d0) = 24077

【问题讨论】:

  • mm-&gt;start_stack is the same values all threads because of using same struct task_struct. - 部分错误:在 Linux 上,每个线程都使用 它自己的 task_struct。但mm 可能在同一进程的线程之间共享。
  • 谢谢。你是绝对正确的......

标签: c linux-kernel stack


【解决方案1】:

您的问题没有完全明确。从技术上讲,用户可以使用pthread 创建一个线程,然后将新线程sp 切换到另一个线程。因此pthread_create 创建的堆栈并不总是进程使用的堆栈。该死,这个过程甚至可能munmap它......

但是,您可以通过以下方式在特定时刻(例如系统调用)访问用户的堆栈:

task_pt_regs(task)->sp

但是,请务必验证它,因为它可能并不总是在用户空间中。用户可以完全控制它。

【讨论】:

    【解决方案2】:

    大多数系统都提供pthread_getattr_np (Linux) 或pthread_attr_get_np (NetBSD) 或类似方法来从正在运行的线程初始化pthread_attr_t 结构。

    完成此操作后,您可以使用例如pthread_attr_getstackaddrpthread_attr_getstacksize 获取最低地址和大小。堆栈的“底部”要么是前者,要么是两者之和,具体取决于堆栈增长的方向。

    小提示:虽然许多系统提供此功能,但它可能适用于程序的初始/主线程,也可能不适用。您已经找到了一种特定于 Linux 的方法来处理这个问题。

    【讨论】:

      猜你喜欢
      • 2014-09-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-11-27
      相关资源
      最近更新 更多