2

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

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

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

简而言之,当我移出堆栈而不触发一般保护故障时,如何检查(在一般情况下)?

(顺便说一句,我意识到我正在假设检查地址的页段是这里的理想方法——也许存在另一种更简单的方法来确定地址是否在当前进程的堆栈空间内)

4

2 回答 2

1

C 标准不提供任何可移植的方式来访问特定于操作系统或特定于硬件的信息或功能(可能除了 system())。如果您的 C 程序依赖于所述信息/功能,那么它的可移植性就很差。

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

于 2013-04-05T15:04:47.643 回答
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);
}
于 2013-04-05T21:21:13.340 回答