Is it possible to set a gdb watchpoint programmatically?

后端 未结 5 1750

I want to set a watchpoint (break on hardware write) temporarily in my C++ program to find memory corruption.

I\'ve seen all the ways to do it manually through gdb,

5条回答
  •  不知归路
    2020-12-04 20:51

    Based on user512106's great answer, I coded up a little "library" that someone might find useful:

    It's on github at https://github.com/whh8b/hwbp_lib. I wish I could have commented directly on his answer, but I don't have enough rep yet.

    Based on feedback from the community, I am going to copy/paste the relevant code here:

    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    
    extern int errno;
    
    enum {
        BREAK_EXEC = 0x0,
        BREAK_WRITE = 0x1,
        BREAK_READWRITE = 0x3,
    };
    
    enum {
        BREAK_ONE = 0x0,
        BREAK_TWO = 0x1,
        BREAK_FOUR = 0x3,
        BREAK_EIGHT = 0x2,
    };
    
    #define ENABLE_BREAKPOINT(x) (0x1<<(x*2))
    #define ENABLE_BREAK_EXEC(x) (BREAK_EXEC<<(16+(x*4)))
    #define ENABLE_BREAK_WRITE(x) (BREAK_WRITE<<(16+(x*4)))
    #define ENABLE_BREAK_READWRITE(x) (BREAK_READWRITE<<(16+(x*4)))
    
    /*
     * This function fork()s a child that will use
     * ptrace to set a hardware breakpoint for 
     * memory r/w at _addr_. When the breakpoint is
     * hit, then _handler_ is invoked in a signal-
     * handling context.
     */
    bool install_breakpoint(void *addr, int bpno, void (*handler)(int)) {
        pid_t child = 0;
        uint32_t enable_breakpoint = ENABLE_BREAKPOINT(bpno);
        uint32_t enable_breakwrite = ENABLE_BREAK_WRITE(bpno);
        pid_t parent = getpid();
        int child_status = 0;
    
        if (!(child = fork()))
        {
            int parent_status = 0;
            if (ptrace(PTRACE_ATTACH, parent, NULL, NULL))
                _exit(1);
    
            while (!WIFSTOPPED(parent_status))
                waitpid(parent, &parent_status, 0);
    
            /*
             * set the breakpoint address.
             */
            if (ptrace(PTRACE_POKEUSER,
                       parent,
                       offsetof(struct user, u_debugreg[bpno]),
                       addr))
                _exit(1);
    
            /*
             * set parameters for when the breakpoint should be triggered.
             */
            if (ptrace(PTRACE_POKEUSER,
                       parent,
                       offsetof(struct user, u_debugreg[7]),
                       enable_breakwrite | enable_breakpoint))
                _exit(1);
    
            if (ptrace(PTRACE_DETACH, parent, NULL, NULL))
                _exit(1);
    
            _exit(0);
        }
    
        waitpid(child, &child_status, 0);
    
        signal(SIGTRAP, handler);
    
        if (WIFEXITED(child_status) && !WEXITSTATUS(child_status))
            return true;
        return false;
    }
    
    /*
     * This function will disable a breakpoint by
     * invoking install_breakpoint is a 0x0 _addr_
     * and no handler function. See comments above
     * for implementation details.
     */
    bool disable_breakpoint(int bpno) 
    {
        return install_breakpoint(0x0, bpno, NULL);
    }
    
    /*
     * Example of how to use this /library/.
     */
    int handled = 0;
    
    void handle(int s) {
        handled = 1;
        return;
    }
    
    int main(int argc, char **argv) {
        int a = 0;
    
        if (!install_breakpoint(&a, 0, handle))
            printf("failed to set the breakpoint!\n");
    
        a = 1;
        printf("handled: %d\n", handled);
    
        if (!disable_breakpoint(0))
            printf("failed to disable the breakpoint!\n");
    
        return 1;
    }
    

    I hope that this helps someone!

    Will

提交回复
热议问题