Re: Clarification: LD_PRELOAD issue

From: Daniel Brown (dbrownat_private)
Date: Tue May 18 1999 - 07:40:38 PDT

  • Next message: Morrill, Ralph: "Research question"

    Here's a similar snippet for Solaris using the procfs interface...
    
    Dan.
    
    --
    
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <sys/param.h>
    #include <sys/syscall.h>
    #include <sys/uio.h>
    
    #include <fcntl.h>
    #include <procfs.h>
    #include <stdio.h>
    #include <unistd.h>
    
    /* Faking of the time() system call via procfs.
     *
     * Daniel Brown, dbrownat_private
     *
     * Compiled and tested under Solaris 2.6/sparc and 2.6/x86
     */
    
    int
    read_status(pid_t pid, pstatus_t *status)
    {
    	char buf[MAXPATHLEN];
    	int fd;
    	
    	sprintf(buf, "/proc/%d/status", (int) pid);
    	
    	if ((fd = open(buf, O_RDONLY)) == -1) {
    		perror("read_status(open)");
    		return 1;
    	}
    	
    	if (read(fd, (void *) status, sizeof(pstatus_t)) != sizeof(pstatus_t))
    	{
    		perror("read_status(read)");
    		return 1;
    	}
    	close(fd);
    	
    	return 0;
    }
    
    int
    write_ctl(pid_t pid, long syscall, void *arg, size_t arglen)
    {
    	int fd;
    	char buf[MAXPATHLEN];
    	struct iovec vec[2];
    	
    	sprintf(buf, "/proc/%d/ctl", (int) pid);
    	
    	if ((fd = open(buf, O_WRONLY)) == -1) {
    		perror("write_ctl(open)");
    		return 1;
    	}
    	
    	vec[0].iov_base = (void *) &syscall;
    	vec[0].iov_len = sizeof(long);
    
    	if (arg != NULL) {
    		vec[1].iov_base = arg;
    		vec[1].iov_len = arglen;
    		
    		if (writev(fd, vec, 2) != (vec[0].iov_len + vec[1].iov_len)) {
    			perror("write_ctl(write2)");
    			close(fd);
    			return 1;
    		}
    	} else {
    		if (writev(fd, vec, 1) != vec[0].iov_len) {
    			perror("write_ctl(write1)");
    			return 1;
    		}
    	}
    	
    	close(fd);
    	
    	return 0;
    }
    	
    int
    main(int argc, char **argv)
    {
    	pid_t pid, ppid;
    	pstatus_t pstatus;
    	sysset_t sysset;
    	long val;
    	
    	setvbuf(stdout, (char *) NULL, _IONBF, (size_t) 0);
    	
    	ppid = getpid();
    	
    	if (read_status(ppid, &pstatus))
    		exit(1);
    
    	printf("Parent PID is %d\n", (int) ppid);
    	
    	printf("Setting PCSEXIT for time() : stop on exit from time().\n");
    	
    	premptyset(&sysset);
    	praddset(&sysset, SYS_time);
    
    	if (write_ctl(ppid, PCSEXIT, (void *) &sysset, sizeof(sysset_t)))
    		exit(1);
    		
    	printf("Setting PR_FORK, so that the child inherits these traps.\n");
    
    	val = PR_FORK;
    	
    	if (write_ctl(ppid, PCSET, (void *) &val, sizeof(long)))
    		exit(1);
    
    	printf("Finally, setting PCSENTRY for exit() "
    	       ": stop on entry to exit().\n");
    	
    	premptyset(&sysset);
    	praddset(&sysset, SYS_exit);
    
    	if (write_ctl(ppid, PCSENTRY, (void *) &sysset, sizeof(sysset_t)))
    		exit(1);
    	
    	if ((pid = fork()) < 0) {
    		perror("fork");
    		exit(1);
    	} else if (pid > 0) { /* Parent */
    		
    		printf("Clearing exit() trap for the parent...\n");
    		
    		premptyset(&sysset);
    		if (write_ctl(ppid, PCSENTRY, (void *) &sysset,
    		sizeof(sysset_t)))
    			exit(1);	/* Good luck! */
    		
    		if (read_status(pid, &pstatus))
    			exit(1);
    		
    		printf("Child PID is %d and %s have a trap set on time().\n",
    			(int) pstatus.pr_pid,
    			(prismember(&pstatus.pr_sysexit,
    			SYS_time)) ? "does" : "doesn't");
    		
    		while (1) {
    		
    		printf("Waiting for child to call time() or exit().\n");
    
    		if (write_ctl(pid, PCWSTOP, (void *) 0, 0))
    			exit(1);
    			
    		printf("Write PCWSTOP returned. Reading status.\n");
    		
    		if (read_status(pid, &pstatus))
    			exit(1);
    		
    		if (pstatus.pr_lwp.pr_syscall == SYS_exit) {
    			printf("Child has called exit(). Bye!\n");
    			exit(0);
    		} else if (pstatus.pr_lwp.pr_syscall != SYS_time) {
    			printf("We've caught syscall %d! Eeeek!\n",
    				(int) pstatus.pr_lwp.pr_syscall);
    			exit(1);
    		}
    		
    		printf("Child has called time().\n");
    				
    		printf("LWP register R_R0 is %d.\n",
    			(int) pstatus.pr_lwp.pr_reg[R_R0]);
    		
    		printf("Setting LWP register R_R0 to 123.\n");
    		
    		pstatus.pr_lwp.pr_reg[R_R0] = 123;
    		if (write_ctl(pid, PCSREG, (void *) &pstatus.pr_lwp.pr_reg,
    				sizeof(prgregset_t)))
    			exit(1);
    				
    		printf("Restarting the child.\n");
    		
    		val = 0L;
    		
    		if (write_ctl(pid, PCRUN, (void *) &val, sizeof(long)))
    			exit(1);
    		
    		printf("Restarted.\n");
    		
    		}	/* while (1) */
    
    		/* NOT REACHED */
    	}
    	
    	/* Child */
    
    	sleep(5);
    	
    	execl("/usr/bin/date", "/usr/bin/date", (char *) NULL);
    		
    	perror("execl failed");
    	
    	return 99;
    }
    



    This archive was generated by hypermail 2b30 : Fri Apr 13 2001 - 14:46:10 PDT