zoukankan      html  css  js  c++  java
  • GDB的原理

    gdb调试不管是本地调试还是远程调试,都是基于ptrace系统调用来实现。

      ptrace系统调用提供了一种方法,让父进程可以观察和控制其它进程的执行,检查和改变其核心映像及寄存器。主要用来实现断点调试和系统调用跟踪
    可通过man手册查看具体使用:man ptrace 

    SYSCALL_DEFINE4(ptrace, long, request, long, pid, unsigned long, addr,
            unsigned long, data)
    {
        struct task_struct *child;
        long ret;
    
        if (request == PTRACE_TRACEME) {
            ret = ptrace_traceme();
            if (!ret)
                arch_ptrace_attach(current);
            goto out;
        }
    
        child = ptrace_get_task_struct(pid);
        if (IS_ERR(child)) {
            ret = PTR_ERR(child);
            goto out;
        }
    
        if (request == PTRACE_ATTACH || request == PTRACE_SEIZE) {
            ret = ptrace_attach(child, request, addr, data);
            /*
             * Some architectures need to do book-keeping after
             * a ptrace attach.
             */
            if (!ret)
                arch_ptrace_attach(child);
            goto out_put_task_struct;
        }
    
        ret = ptrace_check_attach(child, request == PTRACE_KILL ||
                      request == PTRACE_INTERRUPT);
        if (ret < 0)
            goto out_put_task_struct;
    
        ret = arch_ptrace(child, request, addr, data);
        if (ret || request != PTRACE_DETACH)
            ptrace_unfreeze_traced(child);
    
     out_put_task_struct:
        put_task_struct(child);
     out:
        return ret;
    }

    request参数的主要选项:
    PTRACE_TRACEME:由子进程调用,表示本进程将被其父进程跟踪,交付给这个进程的所有信号,即使信号是忽略处理的(除SIGKILL之外),都将使其停止,父进程将通过wait()获知这一情况。

    PTRACE_ATTACH: attach到一个指定的进程,使其成为当前进程跟踪的子进程,而子进程的行为等同于它进行了一次PTRACE_TRACEME操作。但是,需要注意的是,虽然当前进程成为被跟踪进程的父进程,但是子进程使用getppid()的到的仍将是其原始父进程的pid。

    1. D (TASK_UNINTERRUPTIBLE),不可中断的睡眠状态。
    2. R (TASK_RUNNING),进程执行中。
    3. S (TASK_INTERRUPTIBLE),可中断的睡眠状态。
    4. T (TASK_STOPPED),暂停状态。
    5. t (TASK_TRACED),进程被追踪。---------gdb的时候状态

      gdb调试的实现都是建立在信号的基础上的,在使用参数为PTRACE_TRACEME或PTRACE_ATTACH的ptrace系统调用建立调试关系后,交付给目标程序的任何信号首先都会被gdb截获。
      因此gdb可以先行对信号进行相应处理,并根据信号的属性决定是否要将信号交付给目标程序。
      
      1、设置断点:   
      信号是实现断点的基础,当用breakpoint 设置一个断点后,gdb会在=找到该位置对应的具体地址,然后向该地址写入断点指令INT3,即0xCC。
      目标程序运行到这条指令时,就会触发SIGTRAP信号,gdb会首先捕获到这个信号。然后根据目标程序当前停止的位置在gdb维护的断点链表中查询,若存在,则可判定为命中断点。 也就是在程序中设置断点,就是先将该位置的原来的指令保存,然后向该位置写入int 3。当执行到int 3的时候,发生软中断,内核会给子进程发出SIGTRAP信号,当然这个信号会被转发给父进程。然后用保存的指令替换int3,等待恢复运行。

      gdb暂停目标程序运行的方法是想起发送SIGSTOP信号。

    多线程、多进程

    info threads //显示所有线程
    thread id //切换到指定线程
    break filename:linenum thread all //在所有线程相应行设置断点,注意如果主线程不会执行到该行,并且启动all-stop模式,主线程执行n或s会切换过去
    set scheduler-locking off|on //在使用step或者continue命令调试当前被调试线程的时候,其他线程也是同时执行的,怎么只让被调试程序执行呢?通过这个命令就可以实现这个需求。off 不锁定任何线程,也就是所有线程都执行,这是默认值。 on 只有当前被调试程序会执行。
    show scheduler-locking //显示当前模式
    thread apply all command //每个线程执行同意命令,如bt。或者thread apply 1 3 bt,即线程1,3执行bt。

     info signals
    info handle
    查看有哪些信号在被GDB检测中

  • 相关阅读:
    用windows脚本实现文件下载
    pku1325 Machine Schedule
    中位数
    pku1468 Rectangles
    最小密度路径
    合并序列
    PowerDesigner(5)转载
    责任链模式
    PowerDesigner(3)转载
    解释器模式
  • 原文地址:https://www.cnblogs.com/codestack/p/12553791.html
Copyright © 2011-2022 走看看