检查内存地址是否在当前进程的堆栈空间内

时间:2013-04-04 22:06:22

标签: assembly x86 segmentation-fault callstack ptrace

我正在为调试器添加一个功能(我使用Ptrace来操作跟踪进程以及libbfd / libopcodes)来展开堆栈并确定每个CALL分配的堆栈空间与静态派生的本地之间是否存在差异可变大小,沿途打印每个帧的地址和本地堆栈大小。

我的一般方法是获取基指针(EBP / RBP)中的地址,将指针增加到应包含存储的帧指针,取消引用该地址,用{{检查它1}}并重复,直到我取消引用占用堆栈外区域的地址。

我知道如何检查代码/数据段寄存器,但理想情况下我想要一种方法来检查我是否仍然在callstack中,即使W ^ X内存页或其他不可执行的堆栈已经更改了分段。

简而言之,如何在不触发一般保护错误的情况下移动到堆栈外时(一般情况下)检查?

(除此之外,我意识到我的运作假设在这里检查地址的页面段是理想的方法 - 可能还有另一种更简单的方法来确定地址是否在当前进程的堆栈空间内)

2 个答案:

答案 0 :(得分:1)

C标准不提供任何可移植的方式来访问特定于操作系统或特定于硬件的信息或功能(可能除了system()之外)。如果您的C程序依赖于所述信息/功能,则注定便于携带。

如果您坚持使用POSIX功能,可能会在一定程度上提高可移植性,但这种改进只会对POSIX兼容的操作系统有所改进。对于所有其他人来说,这将与改进相反。同样,您可能会在Linux(特定功能或工具或库)上使用某些东西。副手我不能指出你这样。您需要做进一步的研究或等待其他答案。

答案 1 :(得分:0)

我查看了pstack命令的代码,该命令正在打印正在运行的进程的堆栈内容。此代码从link_map结构获取基址,并将其存储在字段l_addr中。该字段设置在函数readLinkMap()

static void readLinkMap(int pid, ElfN_Addr base, struct link_map *lm, 
                        char *name, unsigned int namelen)
{
  /* base address */
  lm->l_addr = (ElfN_Addr) ptrace(PTRACE_PEEKDATA, pid,
                                  base + offsetof(struct link_map,l_addr), 0);
  /* next element of link map chain */
  if (-1 != (long) lm->l_addr || !errno)
    lm->l_next = (struct link_map *) ptrace(PTRACE_PEEKDATA, pid,
                                            base + offsetof(struct link_map, l_next), 0);
  if ((-1 == (long) lm->l_addr || -1 == (long) lm->l_next) && errno) {
    perror("ptrace");
    quit("can't read target.");
  }

  loadString(pid, base + offsetof(struct link_map, l_name), name, namelen);
}