#include <sys/ptrace.h>
#include <signal.h>
#include <sys/user.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <error.h>
#include <time.h>
// source : http://eli.thegreenplace.net/2011/01/23/how-debuggers-work-part-1/
int start = 79860;
int RUN = 0, FAULT = 0, ZONE = 0, SEGMENT = 0;
int count = 0;
void run( char *path, char* cmd, char *arg)
{
int status = 0, pid;

if ((pid=fork())==0) {
        ptrace(PTRACE_TRACEME, 0, 0, 0);
        execl( path, cmd, arg, (char  *) NULL );
        printf("execl error...\n");
} else {

         wait( &status );
         while ( WIFSTOPPED( status ) )   {
         count++;
          if ( ptrace(PTRACE_SINGLESTEP, pid, 0, 0) < 0){
             perror("single step");
             exit(0);
          }
          wait( &status ); 
    }
}
printf("\ninstructions :%d %d", count, count-start);
}
void fault( char *path, char* cmd, char *arg)
{
int status = 0, pid;
int cpt = 0;
int pos   ;
int value = 13;
struct user_regs_struct uregs;
pos = ((count-start) / ZONE) * SEGMENT;
pos =  random() % ZONE;
value = random();
if ((pid=fork())==0) {
        ptrace(PTRACE_TRACEME, 0, 0, 0);
        execl( path, cmd, arg, (char  *) NULL  );
        printf("execl error...\n");
	perror("execl");
} else {
         printf("\n fault at :%d", pos );
         pos += start;
         wait( &status );
         while ( WIFSTOPPED( status ) )   {
          cpt++;
          if ( cpt == pos ) {
                ptrace(PTRACE_GETREGS, pid, 0, &uregs);
                printf(" rax = %Ld", uregs.rax);
		uregs.rax = value;
          	ptrace(PTRACE_SETREGS, pid, 0, &uregs);
          	ptrace(PTRACE_CONT, pid, 0, 0);
		wait( &status );
		break;
	  } 
          if ( ptrace(PTRACE_SINGLESTEP, pid, 0, 0) < 0){
             perror("single step");
             exit(0);
          }
          wait( &status ); 
    }
}

}

int main( int argc, char* argv[] )
{
int opt;
char *args = NULL, *cmd=NULL, *path=NULL;
srandom( time(NULL) );
while ((opt = getopt (argc, argv, "p:c:a:rf:s:z:")) != -1) {
    switch ( opt ) {
	case 'r':
	  RUN = 1;
	  break;
        case 'f':
	  FAULT = atoi( optarg );
	  break;
        case 's':
	    SEGMENT = atoi(optarg);
	    break;
        case 'z':
	     ZONE   = atoi(optarg);
	    break;
        case 'a':
	  args = strdup( optarg );
	  break;
        case 'c':
	   cmd = strdup( optarg );
	  break;
        case 'p':
	  path = strdup( optarg );
	  break;
	default:
	  fprintf (stderr, "bad options");
	  exit (EXIT_FAILURE);
	}
   }
if ( RUN || FAULT ) 
   run( path, cmd, args); 
if ( ZONE == 0 ) 
   ZONE = count - start;
while ( FAULT--)
   fault(path, cmd, args); 
return 0;
}


