Gdb 使用ptrace时检测tracee是否在信号处理程序中

Gdb 使用ptrace时检测tracee是否在信号处理程序中,gdb,signals,ptrace,Gdb,Signals,Ptrace,我在Linux上对此进行了测试,似乎当tracee位于信号处理程序中时,跟踪器可以像往常一样使用ptrace()附加到它。但由于tracee位于信号处理程序中,由于asyn信号安全问题,某些函数可能无法正常调用。那么,在调用ptrace()之后,是否有任何方法可以检测这种情况呢?这可能会引起您的兴趣 简单的回答是,您可以通过展开信号处理程序的堆栈并查找条目来判断SUPER(tracee)是否在信号处理程序中 这是GDB打印为的条目 然而,问题是:你为什么在意 大概是为了防止调试器在最终用户要求您

我在Linux上对此进行了测试,似乎当tracee位于信号处理程序中时,跟踪器可以像往常一样使用ptrace()附加到它。但由于tracee位于信号处理程序中,由于asyn信号安全问题,某些函数可能无法正常调用。那么,在调用ptrace()之后,是否有任何方法可以检测这种情况呢?

这可能会引起您的兴趣

简单的回答是,您可以通过展开信号处理程序的堆栈并查找条目来判断SUPER(tracee)是否在信号处理程序中

这是GDB打印为
的条目

然而,问题是:你为什么在意

大概是为了防止调试器在最终用户要求您执行与调用malloc(10)相当的操作时调用tracee

请注意:

  • GDB不会阻止最终用户这样做。如果进程破坏了它的堆或死锁,那么这是最终用户的问题,而不是GDB的问题

  • 调试器不可能知道应该允许或不允许哪些函数,这一确定取决于信号是否同步以及信号的来源。例如:

    void handler(int signo)
    {
       while (1)
       {
         char *p = malloc(20);  // perfectly safe (but only in this program)
         free(p);
       }
    }
    
    int main()
    {
      signal(SIGINT, handler);
      kill(getpid(), SIGINT);
      return 0; // control never reaches here
    }
    
  • 这可能会引起你的兴趣

    简单的回答是,您可以通过展开信号处理程序的堆栈并查找条目来判断SUPER(tracee)是否在信号处理程序中

    这是GDB打印为
    的条目

    然而,问题是:你为什么在意

    大概是为了防止调试器在最终用户要求您执行与调用malloc(10)相当的操作时调用tracee

    请注意:

  • GDB不会阻止最终用户这样做。如果进程破坏了它的堆或死锁,那么这是最终用户的问题,而不是GDB的问题

  • 调试器不可能知道应该允许或不允许哪些函数,这一确定取决于信号是否同步以及信号的来源。例如:

    void handler(int signo)
    {
       while (1)
       {
         char *p = malloc(20);  // perfectly safe (but only in this program)
         free(p);
       }
    }
    
    int main()
    {
      signal(SIGINT, handler);
      kill(getpid(), SIGINT);
      return 0; // control never reaches here
    }
    

  • 事实证明,使用libunwind确定您当前是否在信号处理程序中非常简单:

    假设您已正确构建libunwind:

    #include <pthread.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <signal.h>
    #include <errno.h>
    #include <string.h>
    
    /* assume that you have build libunwind properly */
    #include "./libunwindout/include/libunwind.h"
    
    /* Simple error handling functions */
    #define handle_error_en(en, msg) \
            do { errno = en; perror(msg); exit(EXIT_FAILURE); } while (0)
    
    void show_backtrace(void) {
        unw_cursor_t cursor; unw_context_t uc;
        unw_word_t ip, sp;
    
        unw_getcontext(&uc);
        unw_init_local(&cursor, &uc);
        while(unw_step(&cursor) > 0) {
            unw_get_reg(&cursor, UNW_REG_IP, &ip);
            unw_get_reg(&cursor, UNW_REG_SP, &sp);
    
            /* Upon unwinding to a signal handler, you get a "1" */
            printf("Is in a signal handler [%d]\n",
                              unw_is_signal_frame(&cursor));
    
            printf("ip = %lx, sp = %lx \n", (long)ip, (long)sp);
        }
    }  
    
    struct sigaction act;
    
    /* Upon receiving a SIGQUIT, this signal handler will be invoked */
    void sighandler(int signum, siginfo_t *info, void *ptr) {
        printf("Received signal: %d\n", signum);
        printf("signal originate from pid[%d]\n", info->si_pid);
        printf("Inside a signal handler...\n");
        show_backtrace();
        while(1)
            ;
        printf("[FATAL] quiting the signal handler\n");
    }
    
    int main(int argc, char *argv[]) {
    {
        printf("Pid of the current process: %d\n", getpid());
    
        memset(&act, 0, sizeof(act));
    
        act.sa_sigaction = sighandler;
        act.sa_flags = SA_SIGINFO;
    
        sigaction(SIGQUIT, &act, NULL);
    
        while(1)
           ;
    
        return 0;
    }
    
    #包括
    #包括
    #包括
    #包括
    #包括
    #包括
    #包括
    /*假设您已经正确构建libunnd*/
    #include“/libundout/include/libund.h”
    /*简单的错误处理函数*/
    #定义句柄\u错误\u en(en,msg)\
    do{errno=en;perror(msg);exit(exit_FAILURE);}while(0)
    void show_backtrace(void){
    unw_光标;unw_上下文光标;
    联合国世界知识产权组织;
    unw_getcontext(&uc);
    unw_init_local(&cursor,&uc);
    while(卸载步骤和光标)>0){
    unw_get_reg(&cursor,unw_reg_IP,&IP);
    unw_get_reg(&cursor,unw_reg_SP,&SP);
    /*退绕到信号处理器时,您会得到一个“1”*/
    printf(“位于信号处理程序[%d]\n]中”,
    unw_是信号_帧(&光标));
    printf(“ip=%lx,sp=%lx\n”,(长)ip,(长)sp);
    }
    }  
    结构动作法;
    /*收到SIGQUIT后,将调用此信号处理程序*/
    无效信号处理器(内部信号、信号信息\u t*info、无效*ptr){
    printf(“收到的信号:%d\n”,信号);
    printf(“信号源于pid[%d]\n”,信息->si_pid);
    printf(“信号处理器内部…\n”);
    show_backtrace();
    而(1)
    ;
    printf(“[FATAL]退出信号处理程序\n”);
    }
    int main(int argc,char*argv[]){
    {
    printf(“当前进程的Pid:%d\n”,getpid());
    memset(&act,0,sizeof(act));
    act.sa_sigaction=sighandler;
    act.sa_flags=sa_SIGINFO;
    sigaction(SIGQUIT,&act,NULL);
    而(1)
    ;
    返回0;
    }
    
    因此,您应该运行此程序,然后在收到 SIGQUIT时,将调用信号处理程序并调用show_backtrace()函数 将被调用,这将展开堆栈并最终找到信号 处理程序框架,报告1

    更有趣的是,libunwind允许您使用其 libunwindptrace模块。通过“远程”,它只是意味着您可以使用 ptrace(2)连接到进程,然后可以使用libunwind ptrace 检测远程进程是否在信号处理程序中运行


    有关更多信息,请参阅libunwind的

    。事实证明,使用libunwind确定您当前是否在信号处理程序中并不重要:

    假设您已正确构建libunwind:

    #include <pthread.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <signal.h>
    #include <errno.h>
    #include <string.h>
    
    /* assume that you have build libunwind properly */
    #include "./libunwindout/include/libunwind.h"
    
    /* Simple error handling functions */
    #define handle_error_en(en, msg) \
            do { errno = en; perror(msg); exit(EXIT_FAILURE); } while (0)
    
    void show_backtrace(void) {
        unw_cursor_t cursor; unw_context_t uc;
        unw_word_t ip, sp;
    
        unw_getcontext(&uc);
        unw_init_local(&cursor, &uc);
        while(unw_step(&cursor) > 0) {
            unw_get_reg(&cursor, UNW_REG_IP, &ip);
            unw_get_reg(&cursor, UNW_REG_SP, &sp);
    
            /* Upon unwinding to a signal handler, you get a "1" */
            printf("Is in a signal handler [%d]\n",
                              unw_is_signal_frame(&cursor));
    
            printf("ip = %lx, sp = %lx \n", (long)ip, (long)sp);
        }
    }  
    
    struct sigaction act;
    
    /* Upon receiving a SIGQUIT, this signal handler will be invoked */
    void sighandler(int signum, siginfo_t *info, void *ptr) {
        printf("Received signal: %d\n", signum);
        printf("signal originate from pid[%d]\n", info->si_pid);
        printf("Inside a signal handler...\n");
        show_backtrace();
        while(1)
            ;
        printf("[FATAL] quiting the signal handler\n");
    }
    
    int main(int argc, char *argv[]) {
    {
        printf("Pid of the current process: %d\n", getpid());
    
        memset(&act, 0, sizeof(act));
    
        act.sa_sigaction = sighandler;
        act.sa_flags = SA_SIGINFO;
    
        sigaction(SIGQUIT, &act, NULL);
    
        while(1)
           ;
    
        return 0;
    }
    
    #包括
    #包括
    #包括
    #包括
    #包括
    #包括
    #包括
    /*假设您已正确构建libunwind*/
    #include“/libundout/include/libund.h”
    /*简单的错误处理函数*/
    #定义句柄\u错误\u en(en,msg)\
    do{errno=en;perror(msg);exit(exit_FAILURE);}while(0)
    void show_backtrace(void){
    unw_光标;unw_上下文光标;
    联合国世界知识产权组织;
    unw_getcontext(&uc);
    unw_init_local(&cursor,&uc);
    while(卸载步骤和光标)>0){
    unw_get_reg(&cursor,unw_reg_IP,&IP);
    unw_get_reg(&cursor,unw_reg_SP,&SP);
    /*退绕到信号处理器时,您会得到一个“1”*/
    printf(“位于信号处理程序[%d]\n]中”,
    unw_是信号_帧(&光标));
    printf(“ip=%lx,sp=%lx\n”,(长)ip,(长)sp);
    }
    }  
    结构动作法;
    /*收到SIGQUIT后,将调用此信号处理程序*/
    无效信号处理器(内部信号、信号信息\u t*info、无效*ptr){
    printf(“收到的信号:%d\n”,信号);
    printf(“信号源于pid[%d]\n”,信息->si_pid);
    printf(“信号处理器内部…\n”);
    show_backtrace();
    而(1)
    ;
    printf(“[FATAL]退出信号处理程序\n”);
    }
    int main(int argc,char*argv[]){
    {
    printf(“当前进程的Pid:%d\n”,getpid());
    memset(&act,0,sizeof(act));
    act.sa_sigaction=sighandler;
    act.sa_flags=sa_SIGINFO;
    sigaction(SIGQUIT,&act,NULL)