Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to set a gdb watchpoint programmatically?

Tags:

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, but I would like to actually set the watchpoint via some method in my code so I don't have to break into gdb, find out the address, set the watchpoint and then continue.

Something like:

#define SET_WATCHPOINT(addr) asm ("set break on hardware write %addr") 
like image 310
Neil Avatar asked Jan 20 '12 12:01

Neil


People also ask

How do you set a watchpoint on a variable in GDB?

5.1 How do I set a write watchpoint for a variable? [top] [toc] Use the watch command. The argument to the watch command is an expression that is evaluated. This implies that the variabel you want to set a watchpoint on must be in the current scope.

What is watchpoint in GDB?

Setting watchpoints. You can use a watchpoint to stop execution whenever the value of an expression changes, without having to predict a particular place where this may happen. Depending on your system, watchpoints may be implemented in software or hardware.

How do I set a breakpoint in GDB?

Setting breakpoints A breakpoint is like a stop sign in your code -- whenever gdb gets to a breakpoint it halts execution of your program and allows you to examine it. To set breakpoints, type "break [filename]:[linenumber]".


2 Answers

Set hardware watchpoint from child process.

#include <signal.h> #include <syscall.h> #include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <stddef.h> #include <sys/ptrace.h> #include <sys/types.h> #include <sys/wait.h> #include <linux/user.h>  enum {     DR7_BREAK_ON_EXEC  = 0,     DR7_BREAK_ON_WRITE = 1,     DR7_BREAK_ON_RW    = 3, };  enum {     DR7_LEN_1 = 0,     DR7_LEN_2 = 1,     DR7_LEN_4 = 3, };  typedef struct {     char l0:1;     char g0:1;     char l1:1;     char g1:1;     char l2:1;     char g2:1;     char l3:1;     char g3:1;     char le:1;     char ge:1;     char pad1:3;     char gd:1;     char pad2:2;     char rw0:2;     char len0:2;     char rw1:2;     char len1:2;     char rw2:2;     char len2:2;     char rw3:2;     char len3:2; } dr7_t;  typedef void sighandler_t(int, siginfo_t*, void*);  int watchpoint(void* addr, sighandler_t handler) {     pid_t child;     pid_t parent = getpid();     struct sigaction trap_action;     int child_stat = 0;      sigaction(SIGTRAP, NULL, &trap_action);     trap_action.sa_sigaction = handler;     trap_action.sa_flags = SA_SIGINFO | SA_RESTART | SA_NODEFER;     sigaction(SIGTRAP, &trap_action, NULL);      if ((child = fork()) == 0)     {         int retval = EXIT_SUCCESS;          dr7_t dr7 = {0};         dr7.l0 = 1;         dr7.rw0 = DR7_BREAK_ON_WRITE;         dr7.len0 = DR7_LEN_4;          if (ptrace(PTRACE_ATTACH, parent, NULL, NULL))         {             exit(EXIT_FAILURE);         }          sleep(1);          if (ptrace(PTRACE_POKEUSER, parent, offsetof(struct user, u_debugreg[0]), addr))         {             retval = EXIT_FAILURE;         }          if (ptrace(PTRACE_POKEUSER, parent, offsetof(struct user, u_debugreg[7]), dr7))         {             retval = EXIT_FAILURE;         }          if (ptrace(PTRACE_DETACH, parent, NULL, NULL))         {             retval = EXIT_FAILURE;         }          exit(retval);     }      waitpid(child, &child_stat, 0);     if (WEXITSTATUS(child_stat))     {         printf("child exit !0\n");         return 1;     }      return 0; }  int var;  void trap(int sig, siginfo_t* info, void* context) {     printf("new value: %d\n", var); }  int main(int argc, char * argv[]) {     int i;      printf("init value: %d\n", var);      watchpoint(&var, trap);      for (i = 0; i < 100; i++) {         var++;         sleep(1);     }      return 0; } 
like image 65
tinytaro Avatar answered Sep 20 '22 18:09

tinytaro


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 <stdio.h> #include <stddef.h> #include <signal.h> #include <unistd.h> #include <sys/types.h> #include <sys/wait.h> #include <sys/ptrace.h> #include <sys/user.h> #include <sys/prctl.h> #include <stdint.h> #include <errno.h> #include <stdbool.h>  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

like image 29
Will Hawkins Avatar answered Sep 18 '22 18:09

Will Hawkins