在当前进程中添加观察点不在gdb中,不用于调试

问题描述

我想知道是否有可能在当前进程中添加观察点,以便在读取或写入内存(取决于标志)时将调用回调。

有一些相关的问题,但都与使用gdb或其他调试器进行调试有关。这不是为了调试,也不是在跟踪另一个进程时。我希望进程本身在其自己的地址空间的内存位置中设置监视点。通常,对于这种事情,我会使用ptrace,但是据我从手册页了解到的那样(“ ptrace()系统调用提供了一种方法,通过该方法,一个进程(“ tracer”)可以观察并控制...的执行) 另一个过程 (“跟踪”),...”(重点是我的),它不能用于在当前过程中添加观察点。

有没有一种方法可以不使用ptrace?还是可以在当前进程中使用ptrace做到这一点?

解决方法

观察点通常通过配置嵌入在CPU本身中的调试功能(即 hardware 观察点)来工作。 本质上,您加载地址范围以监视特殊寄存器。

每种CPU架构都需要专门的代码。 以下是gdbserver在ARM CPU上设置观察点的操作: https://github.com/facebookarchive/binutils/blob/a535268b59862077d95f34f1572ac0bce0b428c7/gdb/gdbserver/linux-arm-low.c#L552

请注意对update_registers_callback()的调用-gdbserver必须使用ptrace功能来在跟踪的上下文中更新寄存器。如果您希望进程自己监视,则可以直接访问这些寄存器。

以下是您的流程如何注意到自己的观察点被击中的方法: 它接收到SIGTRAP信号,其中的详细信息指示观察点。 https://github.com/facebookarchive/binutils/blob/a535268b59862077d95f34f1572ac0bce0b428c7/gdb/gdbserver/linux-arm-low.c#L632 在gdbserver上下文中,该通知必须再次通过ptrace传递。在您自己的过程中,您可以直接在SIGTRAP的处理程序中检查信号信息。代码摘录(适用于ARM):

  /* This must be a hardware breakpoint.  */
  if (siginfo.si_signo != SIGTRAP
      || (siginfo.si_code & 0xffff) != 0x0004 /* TRAP_HWBKPT */)
    return 0;

  /* If we are in a positive slot then we're looking at a breakpoint and not
     a watchpoint.  */
  if (siginfo.si_errno >= 0)
    return 0;

  /* Cache stopped data address for use by arm_stopped_data_address.  */
  lwp->arch_private->stopped_data_address
    = (CORE_ADDR) (uintptr_t) siginfo.si_addr;

进一步阅读后发现,跟踪器通过ptrace访问的硬件断点“寄存器”不是直接的真实内容,而是在Linux内核中实现的抽象。

涉及一个“硬件断点”框架,该框架从CPU细节中抽象出来。找到此概述: https://www.kernel.org/doc/ols/2009/ols2009-pages-149-158.pdf

尽管这使人们希望实际上可以使用由进程自身应用的ptrace() syscall以相当可移植的方式安装硬件观察点,但无法实现-参见下文

您将需要以下ptrace()请求代码(通常的手册页中没有记录):

PTRACE_SETHBPREGS

进一步的实验:

  • 一个进程本身不能ptrace()(权限被拒绝)
  • 一个进程可以调用clone(),然后一个线程可以成功ptrace(PTRACE_SEIZE)另一个线程
  • 在这一点上,您还可以fork(),并使用跟踪器exec() gdb进行监视
  • x86和x86_64似乎都没有实现PTRACE_SETHBPREGS(从内核4.15开始)
  • aarch64可以,但是到目前为止,我只设法引起了一些总线错误

因此,我认为可以排除使用ptrace()作为以任何可移植方式设置硬件观察点的选项。

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...