当前位置:首页 > 公众号精选 > CPP开发者
[导读]在程序出现bug的时候,最好的解决办法就是通过 GDB 调试程序,然后找到程序出现问题的地方。比如程序出现 段错误(内存地址不合法)时,就可以通过 GDB 找到程序哪里访问了不合法的内存地址而导致的。本文不是介绍GDB的使用方式,而是大概介绍GDB的实现原理,当然GDB是一个庞大...

在程序出现bug的时候,最好的解决办法就是通过 GDB 调试程序,然后找到程序出现问题的地方。比如程序出现 段错误(内存地址不合法)时,就可以通过 GDB 找到程序哪里访问了不合法的内存地址而导致的。

本文不是介绍 GDB 的使用方式,而是大概介绍 GDB 的实现原理,当然 GDB 是一个庞大而复杂的项目,不可能只通过一篇文章就能解释清楚,所以本文主要是介绍 GDB 使用的核心的技术 - ptrace

ptrace系统调用

ptrace() 系统调用是 Linux 提供的一个调试进程的工具,ptrace() 系统调用非常强大,它提供非常多的调试方式让我们去调试某一个进程,下面是 ptrace() 系统调用的定义:

long ptrace(enum __ptrace_request request,  pid_t pid, void *addr,  void *data);
下面解释一下 ptrace() 各个参数的作用:

  • request:指定调试的指令,指令的类型很多,如:PTRACE_TRACEMEPTRACE_PEEKUSERPTRACE_CONTPTRACE_GETREGS等等,下面会介绍不同指令的作用。
  • pid:进程的ID(这个不用解释了)。
  • addr:进程的某个地址空间,可以通过这个参数对进程的某个地址进行读或写操作。
  • data:根据不同的指令,有不同的用途,下面会介绍。
ptrace() 系统调用详细的介绍可以参考以下链接:https://man7.org/linux/man-pages/man2/ptrace.2.html

ptrace使用示例

下面通过一个简单例子来说明 ptrace() 系统调用的使用,这个例子主要介绍怎么使用 ptrace() 系统调用获取当前被调试(追踪)进程的各个寄存器的值,代码如下(ptrace.c):

#include 
#include 
#include 
#include 
#include 
#include 

int main()
{   pid_t child;
    struct user_regs_struct regs;

    child = fork();  // 创建一个子进程
    if(child == 0) { // 子进程
        ptrace(PTRACE_TRACEME, 0NULLNULL); // 表示当前进程进入被追踪状态
        execl("/bin/ls""ls"NULL);          // 执行 `/bin/ls` 程序
    } 
    else { // 父进程
        wait(NULL); // 等待子进程发送一个 SIGCHLD 信号
        ptrace(PTRACE_GETREGS, child, NULL
本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
关闭
关闭