home *** CD-ROM | disk | FTP | other *** search
/ The C Users' Group Library 1994 August / wc-cdrom-cusersgrouplibrary-1994-08.iso / listings / v_08_10 / 8n10075a < prev    next >
Text File  |  1990-08-16  |  7KB  |  212 lines

  1.  
  2.  
  3. /*      debug.c - Demonstration of UNIX debugging interface, 
  4.         including Hardware Breakpointing.
  5.         Copyright (C) 1990 Computer Innovations Inc.
  6.         Jon Chappell 8/90, In C++ 
  7. */
  8. #include <stdio.h>
  9. #include <osfcn.h>
  10. #include <string.h>
  11. #include <signal.h>
  12. #include <sys/types.h>
  13. #include <sys/mount.h>
  14. #include <sys/dirent.h>
  15. #include <sys/param.h>
  16. #include <sys/immu.h>
  17. #include <sys/region.h>
  18. #include <sys/proc.h>
  19. #include <sys/user.h>
  20. #include <sys/reg.h>
  21. #include <sys/debugreg.h>
  22.  
  23. // simplified debugger class
  24. class debug {
  25. private:
  26.    char *name;                  /* program name */
  27.    char **argv;                 /* command line args */
  28.    int pid;                             /* process id */
  29.    int read_register(int r);    /* read process register r */
  30. public: 
  31.    debug(char *n, char **a);            /* constructor */
  32.    void startup(void);                          /* start debugging */
  33.    int wait_process(void);                      /* wait for "debuggee" */
  34.    void set_hardware_bkpt(int address); /* set hardware bkpt */
  35.    void single_step(void);                      /* single step (trace) */
  36.    void go(void);                                       /* run "debuggee" */
  37.    void display_status(void);           /* tell user where we stopped */
  38. };
  39.  
  40. /*   There is a lot that could be done here, but let's just
  41.      set a data breakpoint on a variable in the program,
  42.      do a Go (run the program),
  43.      then come back and print out where we are (EIP value)
  44. */
  45. main()
  46. {
  47. int address;
  48.  
  49.    prog.startup();         /* start program */
  50.    if(prog.wait_process()){ 
  51.       /* must single-step one instruction when you first come in */
  52.       prog.single_step();       
  53.       prog.wait_process();      
  54.       /* Ask user where to place it: */
  55.       printf("Enter address (in hex): ");
  56.       scanf("%x",&address);
  57.       prog.set_hardware_bkpt(address);  /* set data breakpoint */
  58.       prog.go();                                /* run the program */
  59.       if(prog.wait_process()){  /* wait for program */
  60.                 prog.display_status();  /* tell where we are */
  61.       }
  62.       printf("Done\n");
  63.    }
  64. }
  65.  
  66. // sample program 
  67. class debug prog("sample",NULL);
  68.  
  69. // constructor for debug class. 
  70. // Set up the name and argv of the program to debug
  71. debug::debug(char *n, char **a)
  72. {
  73.    memset((char *)this,0,sizeof(debug));
  74.    name=n;
  75.    argv=a;
  76. }
  77.  
  78. /* load the program being debugged
  79. */
  80. void debug::startup(void)
  81. {
  82.    /* Create a copy of this process. Basically, the program to be debugged
  83.       is loaded as follows: First, fork() creates a copy of the process.
  84.           fork() is a UNIX system call, which returns 0 to the child, and the
  85.       process id to the parent. Then (in case 0: below), the child turns
  86.       around and calls ptrace(0,...) to give the parent permission to debug
  87.       it, then proceeds to transform itself into the real process to
  88.       be debugged via execvp(), which is another UNIX system call, which
  89.           performs program chaining. 
  90.    */
  91.    pid = fork();        
  92.    switch(pid){
  93.      case -1: // error in forking
  94.                 perror("error in forking"); 
  95.                 exit(1);
  96.      case 0:            /* child process */
  97.                 ptrace(0,0,0,0);        // tell parent it's ok to debug me
  98.                 if(execvp(name,argv)!=0){           /* execute process to be debugged */
  99.                   perror("execvp failed"); 
  100.                   exit(1);
  101.                 }
  102.                 break;
  103.      default:   /* parent process (continue) */
  104.                 break;
  105.    }    
  106. }
  107.  
  108. /*      Wait for process to get back to you, then check to see
  109.         if the process has terminated, etc.
  110. */
  111. int debug::wait_process(void)
  112. {
  113. int status;
  114.  
  115.         if(wait(&status)== -1){
  116.           printf("wait() returned -1");
  117.           return 0;
  118.         }       
  119.         // status is tested here, to see if a signal was
  120.         // received, if the program was terminated, etc.
  121.         // see ptrace(2) and signal(2) for details
  122.         if((status&0xff)==0177){
  123.           if(((status>>8)&0xff)!=SIGTRAP){
  124.              printf("program stopped on signal");
  125.              // process signal here
  126.              return 0;
  127.           }
  128.         }
  129.         // program terminated via exit ?
  130.         else if((status&0xff)==0){
  131.            printf("Program terminated via exit().");
  132.            return 0;
  133.         }
  134.         // program terminated via signal() ?
  135.         else if(((status>>8)&0xff)==0){
  136.            printf("Program terminated via signal().");
  137.            return 0;
  138.         }
  139.     return 1;
  140. }
  141.  
  142. // structure member offset
  143. #ifndef offsetof
  144. #define offsetof(s,m) ((int) ((char *)&((s *)0)->m - (char *)0))
  145. #endif
  146.  
  147. /* set a hardware data breakpoint, 4 bytes wide, 
  148.    read/write on the word at this address in the user space.
  149. */
  150. void debug::set_hardware_bkpt(int address)
  151. {
  152. int type=3;                             /* read/write */
  153. int len=3;                              /* 4 bytes (one word) */
  154. int hardware_reg_off;   /* hardware register offset */
  155. int control_reg_off;    /* control register offset */
  156. int control_word;               /* control word to write */
  157.  
  158.     /* Let's use the first hardware register only */
  159.     control_word 
  160.                 = ((type + (len<<2)) << DR_CONTROL_SHIFT) | 1
  161.                    | DR_CONTROL_RESERVED | DR_LOCAL_SLOWDOWN;
  162.  
  163.     /* write the address into the hardware debug register */    
  164.     hardware_reg_off = offsetof(struct user, u_debugreg);
  165.     ptrace(6,pid,hardware_reg_off,address);
  166.  
  167.     /* write the control word */
  168.     control_reg_off = offsetof(struct user, u_debugreg)
  169.                 + (DR_CONTROL*sizeof(int));
  170.     ptrace(6,pid,control_reg_off,control_word);
  171. }
  172.  
  173. /*      read register 'r' (where r is a #define from debugreg.h)
  174. */
  175. int debug::read_register(int r)
  176. {
  177. unsigned off;
  178.  
  179.    /* read the base of the register area */
  180.    off = ptrace(3,pid,offsetof(struct user, u_ar0),0);
  181.  
  182.    /* read the individual register */
  183.    return ptrace(3,pid,off+(r * sizeof(int)),0);
  184. }
  185.  
  186. /* return control to the program being debugged and Go
  187. */
  188. void debug::go(void)
  189. {
  190.    ptrace(7,pid,1,0);   /* UNIX process trace service call */
  191. }
  192.  
  193. /* trace a single machine instruction
  194. */
  195. void debug::single_step(void)
  196. {
  197.    ptrace(9,pid,1,0);
  198. }
  199.  
  200. /* tell where we are
  201. */
  202. void debug::display_status(void)
  203. {
  204. int eip;
  205.  
  206.    /* read and print EIP */
  207.    eip = read_register(EIP);
  208.    printf("Stopped at %xh\n",eip);
  209. }
  210. /* end debug.c */
  211.  
  212.