示例#1
1
bool handle_wait(pid_t pid, int status, int count, int *continued, int *terminated)
{
	unsigned int alarm_remaining_sec = waitproc_flags_test(WAITPROC_FLAG_ALARMSET) ? alarm(0) : 0;

	if (pid != -1) {
		struct flagged_int *p = get_flagged_int(&waitproc_options.pids, pid);
		assert(p);

		if (WIFSTOPPED(status)) {
			long r = WSTOPSIG(status);
			assert(p->valid);
			switch (r) {
				case SIGSTOP:
					if (p->state == STATE_ATTACHED) {
						p->state = STATE_CONTINUED;
						r = 0;
						assert(*continued < count);
						if (++(*continued) == count)
							set_alarm();
					} else {
						r = SIGCONT;
					}
					break;

				case SIGTSTP:
					r = SIGCONT;
					break;

				default:
					// forward the signal
					break;
			}
			if (r >= 0) {
				assert(p->state >= STATE_ATTACHED);
				r = ptrace(PTRACE_CONT, pid, 0, r);
				assert(r == 0);
			}
		} else if (WIFEXITED(status) || WIFSIGNALED(status)) {
			assert(p->valid && p->state < STATE_TERMINATED);
			p->state = STATE_TERMINATED;
			p->valid = false;
			print_terminated_process(pid);
			if (++(*terminated) == count)
				return false;
		}
	} else switch (errno) {
		case EINTR:
			if (waitproc_options.last_signal == SIGALRM) {
				waitproc_options.last_signal = SIGINVALID;
				if (DEBUG || !alarm_remaining_sec)
					return false;
			} else {
				fputs("Interrupted by unexpected signal\n", stderr);
				UNEXPECTED_STATE();
			}
			break;

		case ECHILD:
			*terminated = count;
			return false;

		default:
			UNEXPECTED_STATE();
			break;
	}

	assert(*terminated < count);

	if (alarm_remaining_sec)
		alarm(alarm_remaining_sec);

	return true;
}
int
main(int argc, char **argv)
{
	int sig, status, exit_code;
	struct child son;

	/* Parse arguments */
	if (argc < 2) {
		fprintf(stderr, "Usage: %s program [argument...]\n", argv[0]);
		return EXIT_FAILURE;
	}

	/* Fork */
	if ((son.pid = fork()) < 0) {
		perror("fork");
		return EXIT_FAILURE;
	}
	else if (!son.pid) { /* child */
		/* Set up for tracing */
		if (!pink_trace_me()) {
			perror("pink_trace_me");
			_exit(EXIT_FAILURE);
		}
		/* Stop and let the parent continue the execution. */
		kill(getpid(), SIGSTOP);

		++argv;
		execvp(argv[0], argv);
		perror("execvp");
		_exit(-1);
	}
	else {
		waitpid(son.pid, &status, 0);
		assert(WIFSTOPPED(status));
		assert(WSTOPSIG(status) == SIGSTOP);

		/* Figure out the bitness of the traced child. */
		son.bitness = pink_bitness_get(son.pid);
		if (son.bitness == PINK_BITNESS_UNKNOWN)
			err(1, "pink_bitness_get");
		printf("Child %i runs in %s mode\n", son.pid, pink_bitness_name(son.bitness));

		son.inexecve = son.insyscall = false;
		son.printret = true;
		sig = exit_code = 0;
		for (;;) {
			/* At this point the traced child is stopped and needs
			 * to be resumed.
			 */
			if (!pink_trace_syscall(son.pid, sig)) {
				perror("pink_trace_syscall");
				return (errno == ESRCH) ? 0 : 1;
			}
			sig = 0;

			/* Wait for the child */
			if ((son.pid = waitpid(son.pid, &status, 0)) < 0) {
				perror("waitpid");
				return (errno == ECHILD) ? 0 : 1;
			}

			/* Check the event */
			if (WIFSTOPPED(status)) {
				if (WSTOPSIG(status) == SIGTRAP)
					handle_sigtrap(&son);
				else {
					/* Child received a genuine signal.
					 * Send it to the child. */
					sig = WSTOPSIG(status);
				}
			}
			else if (WIFEXITED(status)) {
				exit_code = WEXITSTATUS(status);
				printf("Child %i exited normally with return code %d\n",
						son.pid, exit_code);
				break;
			}
			else if (WIFSIGNALED(status)) {
				exit_code = 128 + WTERMSIG(status);
				printf("Child %i exited with signal %d\n",
						son.pid, WTERMSIG(status));
				break;
			}
		}

		return exit_code;
	}
}
示例#3
0
/* Handle breakpoints - we expect to see breakpoints in the dynamic linker
 * (which we set ourselves) as well as profiler marks (embedded in the
 * profiled application's code).
 */
static int ProcessBreakpoint( pid_t pid, u_long ip )
{
    static int  ld_state = RT_CONSISTENT;   // This ought to be per-pid
    int         ptrace_sig = 0;

#if defined( MD_x86 )
    user_regs_struct    regs;

    // on x86, when breakpoint was hit the EIP points to the next
    // instruction, so we must be careful
    ptrace( PTRACE_GETREGS, pid, NULL, &regs );

    if( ip == Rdebug.r_brk + sizeof( opcode_type ) ) {
#elif defined( MD_ppc )
    if( ip == Rdebug.r_brk ) {
#endif
        opcode_type         brk_opcode = BRKPOINT;
        int                 status;
        int                 ret;

        /* The dynamic linker breakpoint was hit, meaning that
         * libraries are being loaded or unloaded. This gets a bit
         * tricky because we must restore the original code that was
         * at the breakpoint and execute it, but we still want to
         * keep the breakpoint.
         */
        if( WriteMem( pid, &saved_opcode, Rdebug.r_brk, sizeof( saved_opcode ) ) != sizeof( saved_opcode ) )
            printf( "WriteMem() #1 failed\n" );
        ReadMem( pid, &Rdebug, (addr_off)DbgRdebug, sizeof( Rdebug ) );
        dbg_printf( "ld breakpoint hit, state is " );
        switch( Rdebug.r_state ) {
        case RT_ADD:
            dbg_printf( "RT_ADD\n" );
            AddLibrary( pid, Rdebug.r_map );
            ld_state = RT_ADD;
            break;
        case RT_DELETE:
            dbg_printf( "RT_DELETE\n" );
            ld_state = RT_DELETE;
            break;
        case RT_CONSISTENT:
            dbg_printf( "RT_CONSISTENT\n" );
            if( ld_state == RT_DELETE )
                RemoveLibrary( pid, Rdebug.r_map );
            ld_state = RT_CONSISTENT;
            break;
        default:
            dbg_printf( "error!\n" );
            break;
        }
#if defined( MD_x86 )
        regs.eip--;
        ptrace( PTRACE_SETREGS, pid, NULL, &regs );
#endif
        // unset breakpoint, single step, re-set breakpoint
        if( ptrace( PTRACE_SINGLESTEP, pid, NULL, (void *)ptrace_sig ) < 0 )
            perror( "ptrace()" );
        do {    // have to loop since SIGALRM can interrupt us here
            ret = waitpid( pid, &status, 0 );
        } while( (ret < 0) && (errno == EINTR) );
        if( ret == -1)
            perror( "waitpid()" );
        if( WriteMem( pid, &brk_opcode, Rdebug.r_brk, sizeof( brk_opcode ) ) != sizeof( brk_opcode ) )
            dbg_printf( "WriteMem() #2 failed with errno %d for pid %d, %d bytes (at %p)!\n", errno, pid, sizeof( brk_opcode ), Rdebug.r_brk );
        return( TRUE ); // indicate this was our breakpoint
    } else {
        dbg_printf( "Not an ld breakpoint, assuming mark\n" );
#if defined( MD_x86 )
        if( ProcessMark( pid, &regs ) )
            return( TRUE );
#endif
    }
    return( FALSE );
}


/*
 * Real time signal (SIGALRM) handler. All we really need to do is wake up
 * periodically to interrupt waitpid(), the signal handler need not do much
 * at all.
 */
static void alarm_handler( int signo )
{
    TimerTicked = TRUE;
}


/* Install periodic real time alarm signal */
static void InstSigHandler( int msec_period )
{
    struct sigaction    sigalrm;
    struct itimerval    timer;

    sigalrm.sa_handler = (void *)alarm_handler;
    sigemptyset( &sigalrm.sa_mask );
    sigalrm.sa_flags = 0;

    sigaction( SIGALRM, &sigalrm, NULL );

    timer.it_interval.tv_sec = 0;
    timer.it_interval.tv_usec = msec_period * 1000;
    timer.it_value.tv_sec = 0;
    timer.it_value.tv_usec = msec_period * 1000;

    if( setitimer( ITIMER_REAL, &timer, NULL ) ) {
        InternalError( MsgArray[MSG_SAMPLE_6 - ERR_FIRST_MESSAGE] );
    }
}


/*
 * Main sampler loop. We run the profiled application under the control of
 * ptrace(). The sampler installs a SIGALRM handler which ticks at the desired
 * rate. Whenever the SIGALRM interrupts our own waitpid(), we send a SIGSTOP
 * to the profiled app and when the child app notifies us of the SIGSTOP, we
 * remember the current execution point and continue the profiled app. Note
 * that we may miss some ticks but this is not a problem - the ticks don't
 * even need to be regular to provide usable results.
 */
static void SampleLoop( pid_t pid )
{
    static int          ptrace_sig = 0;
    static int          do_cont = TRUE;
    int                 status;
    user_regs_struct    regs;
    bool                sample_continue = TRUE;
    int                 ret;
    opcode_type         brk_opcode = BRKPOINT;

    TimerTicked = FALSE;
    InstSigHandler( SleepTime );

    do {
        if( do_cont && ptrace( PTRACE_CONT, pid, NULL, (void *)ptrace_sig ) == -1)
            perror( "ptrace()" );
        ret = waitpid( pid, &status, 0 );
        if( (ret < 0) && (errno == EINTR) ) {
            /* did we get woken up by SIGALRM? */
            if( TimerTicked ) {
                TimerTicked = FALSE;
                /* interrupt child process - next waitpid() will see this */
                kill( pid, SIGSTOP );
            } else {
                dbg_printf( "who the hell interrupted waitpid()?\n" );
            }
            do_cont = FALSE;
            continue;
        }
        if( ret < 0 )
            perror( "waitpid()" );
        do_cont = TRUE;

        /* record current execution point */
#if defined( MD_x86 )
        ptrace( PTRACE_GETREGS, pid, NULL, &regs );
#elif defined( MD_ppc )
        regs.eip = ptrace( PTRACE_PEEKUSER, pid, REGSIZE * PT_NIP, NULL );
#endif
        if( WIFSTOPPED( status ) ) {
            /* If debuggee has dynamic section, try getting the r_debug struct
             * every time the child process stops. The r_debug data may not be
             * available immediately after the child process first loads.
             */
            if( !HaveRdebug && (DbgDyn != NULL) ) {
                if( Get_ld_info( pid, DbgDyn, &Rdebug, &DbgRdebug ) ) {

                    AddLibrary( pid, Rdebug.r_map );
                    HaveRdebug = TRUE;

                    /* Set a breakpoint in dynamic linker. That way we can be
                     * informed on dynamic library load/unload events.
                     */
                    ReadMem( pid, &saved_opcode, Rdebug.r_brk, sizeof( saved_opcode ) );
                    dbg_printf( "setting ld breakpoint at %p, old opcode was %X\n", Rdebug.r_brk, saved_opcode );
                    WriteMem( pid, &brk_opcode, Rdebug.r_brk, sizeof( brk_opcode ) );
                }
            }

            sample_continue = FALSE;
            switch( (ptrace_sig = WSTOPSIG( status )) ) {
            case SIGSEGV:
                dbg_printf( "SIGSEGV at %p\n", regs.eip );
                sample_continue = TRUE;
                break;
            case SIGILL:
                dbg_printf( "SIGILL at %p\n", regs.eip );
                sample_continue = TRUE;
                break;
            case SIGABRT:
                dbg_printf( "SIGABRT at %p\n", regs.eip );
                sample_continue = TRUE;
                break;
            case SIGINT:
                dbg_printf( "SIGINT at %p\n", regs.eip );
                sample_continue = TRUE;
                break;
            case SIGTRAP:
                dbg_printf( "SIGTRAP at %p\n", regs.eip );
                if( ProcessBreakpoint( pid, regs.eip ) ) {
                    // don't pass on SIGTRAP if we expected this breakpoint
                    ptrace_sig = 0;
                }
                sample_continue = TRUE;
                break;
            case SIGSTOP:
                /* presumably we were behind this SIGSTOP */
                RecordSample( regs.eip, 1 );
                ptrace_sig = 0;
                sample_continue = TRUE;
                break;
            default:
                /* all other signals get passed down to the child and we let
                 * the child handle them (or not handle and die)
                 */
                sample_continue = TRUE;
                break;
            }
        } else if( WIFEXITED( status ) ) {
            dbg_printf( "WIFEXITED pid %d\n", pid );
            report();
            sample_continue = FALSE;
        } else if( WIFSIGNALED( status ) ) {
            dbg_printf( "WIFSIGNALED pid %d\n", pid );
            report();
            sample_continue = FALSE;
        }
    } while( sample_continue );
}


static int GetExeNameFromPid( pid_t pid, char *buffer, int max_len )
{
    char        procfile[24];
    int         len;

    sprintf( procfile, "/proc/%d/exe", pid );
    len = readlink( procfile, buffer, max_len );
    if( len < 0 )
        len = 0;
    buffer[len] = '\0';
    return( len );
}
示例#4
0
文件: xargs.c 项目: Johnwei386/Minix3
void run(char **argv)
{
	register char **p;
	pid_t pid;
	int noinvoke;
	int status;
	int pfd[2];

	if (tflag) {
		(void)fprintf(stderr, "%s", *argv);
		for (p = argv + 1; *p; ++p)
			(void)fprintf(stderr, " %s", *p);
		(void)fprintf(stderr, "\n");
		(void)fflush(stderr);
	}
	if (pipe(pfd) < 0) err("pipe: %s", strerror(errno));

	switch(pid = fork()) {
	case -1:
		err("fork: %s", strerror(errno));
	case 0:
		close(pfd[0]);
		fcntl(pfd[1], F_SETFD, fcntl(pfd[1], F_GETFD) | FD_CLOEXEC);

		execvp(argv[0], argv);
		noinvoke = (errno == ENOENT) ? 127 : 126;
		(void)fprintf(stderr,
		    "xargs: %s: %s.\n", argv[0], strerror(errno));

		/* Modern way of returning noinvoke instead of a dirty vfork()
		 * trick:					(kjb)
		 */
		write(pfd[1], &noinvoke, sizeof(noinvoke));
		_exit(-1);
	}
	close(pfd[1]);
	if (read(pfd[0], &noinvoke, sizeof(noinvoke)) < sizeof(noinvoke))
		noinvoke = 0;
	close(pfd[0]);

	pid = waitpid(pid, &status, 0);
	if (pid == -1)
		err("waitpid: %s", strerror(errno));

	/*
	 * If we couldn't invoke the utility or the utility didn't exit
	 * properly, quit with 127 or 126 respectively.
	 */
	if (noinvoke)
		exit(noinvoke);

	/*
	 * According to POSIX, we have to exit if the utility exits with
	 * a 255 status, or is interrupted by a signal.   xargs is allowed
	 * to return any exit status between 1 and 125 in these cases, but
	 * we'll use 124 and 125, the same values used by GNU xargs.
	 */
	if (WIFEXITED(status)) {
		if (WEXITSTATUS (status) == 255) {
			fprintf (stderr, "xargs: %s exited with status 255\n",
				 argv[0]);
			exit(124);
		} else if (WEXITSTATUS (status) != 0) {
			exit_status = 123;
		}
	} else if (WIFSTOPPED (status)) {
		fprintf (stderr, "xargs: %s terminated by signal %d\n",
			 argv[0], WSTOPSIG (status));
		exit(125);
	} else if (WIFSIGNALED (status)) {
		fprintf (stderr, "xargs: %s terminated by signal %d\n",
			 argv[0], WTERMSIG (status));
		exit(125);
	}
}
示例#5
0
#include<sys/wait.h>
#include "ourhdr.h"

void pr_exit(int status)
{
	if(WIFEXITED(status))
		printf("normal termination, exit staus =%d\n",WEXITSTATUS(status));
	else if(WIFSIGNALED(status))
		printf("Abnormal termination, signal number =%d%s\n",WTERMSIG(status),
	#ifdef WCOREDUMP
				WCOREDUMP(status) ? "(core file generated)":"");
#else
	"");
#endif
	else if(WIFSTOPPED(status))
		printf("Child stopped, signal number = %d\n",WSTOPSIG(status));
}

示例#6
0
/*
 * get_child_exit: This looks for dead child processes of the client.
 * There are two main sources of dead children:  Either an /exec'd process
 * has exited, or the client has attempted to fork() off a helper process
 * (such as wserv or gzip) and that process has choked on itself.
 *
 * When SIGCHLD is recieved, the global variable 'dead_children_processes'
 * is incremented.  When this function is called, we go through and call
 * waitpid() on all of the outstanding zombies, conditionally stopping when
 * we reach a specific wanted sub-process.
 *
 * If you want to stop reaping children when a specific subprocess is 
 * reached, specify the process in 'wanted'.  If all youre doing is cleaning
 * up after zombies and /exec's, then 'wanted' should be -1.
 */
int 		get_child_exit (pid_t wanted)
{
	Process	*proc;
	pid_t	pid;
	int	status, i;

	/*
	 * Iterate until we've reaped all of the dead processes
	 * or we've found the one asked for.
	 */
	if (dead_children_processes)
	{
	    block_signal(SIGCHLD);
	    while ((pid = waitpid(wanted, &status, WNOHANG)) > 0)
	    {
		/*
		 * First thing we do is look to see if the process we're
		 * working on is the one that was asked for.  If it is,
		 * then we get its exit status information and return it.
		 */
		if (wanted != -1 && pid == wanted)
		{
		        unblock_signal(SIGCHLD);

			if (WIFEXITED(status))
				return WEXITSTATUS(status);
			if (WIFSTOPPED(status))
				return -(WSTOPSIG(status));
			if (WIFSIGNALED(status)) 
				return -(WTERMSIG(status));
		}

		/*
		 * If it wasnt the process asked for, then we've probably
		 * stumbled across a dead /exec'd process.  Look for the
		 * corresponding child process, and mark it as being dead.
		 */
		else
		{
			for (i = 0; i < process_list_size; i++)
			{
				proc = process_list[i];
				if (proc && proc->pid == pid)
				{
					proc->exited = 1;
					proc->termsig = WTERMSIG(status);
					proc->retcode = WEXITSTATUS(status);
					break;
				}
			}
		}
	    }
	    dead_children_processes = 0;
	    unblock_signal(SIGCHLD);
	}

	/*
	 * Now we may have reaped some /exec'd processes that were previously
	 * dumb and have now exited.  So we call cleanup_dead_processes() to 
	 * find and delete any such processes.
	 */
	cleanup_dead_processes();

	/*
	 * If 'wanted' is not -1, then we didnt find that process, and
	 * if 'wanted' is -1, then you should ignore the retval anyhow. ;-)
	 */
	return -1;
}
示例#7
0
文件: sandbox.c 项目: LiuCihang/OJ
static void *
__sandbox_tracer(sandbox_t * psbox)
{
    FUNC_BEGIN("sandbox_tracer(%p)", psbox);

    assert(psbox);

    #define UPDATE_RESULT(psbox,res) \
    {{{ \
        if (((psbox)->result) != (result_t)(res)) \
        { \
            ((psbox)->result) = (result_t)(res); \
        } \
        DBG("result: %s", s_result_name((result_t)(res))); \
    }}} /* UPDATE_RESULT */

    #define UPDATE_STATUS(psbox,sta) \
    {{{ \
        P(&((psbox)->mutex)); \
        if (((psbox)->status) != (status_t)(sta)) \
        { \
            ((psbox)->status) = (status_t)(sta); \
            pthread_cond_broadcast(&((psbox)->update)); \
        } \
        V(&((psbox)->mutex)); \
        DBG("status: %s", s_status_name((status_t)(sta))); \
    }}} /* UPDATE_STATUS */

    #define SIGMLE SIGUSR1

    #define TIMEVAL_INPLACE_SUBTRACT(x,y) \
    {{{ \
        if ((x).tv_usec < (y).tv_usec) \
        { \
            int nsec = ((y).tv_usec - (x).tv_usec) / 1000000 + 1; \
            (x).tv_sec -= nsec; \
            (x).tv_usec += 1000000 * nsec; \
        } \
        if ((x).tv_usec - (y).tv_usec >= 1000000) \
        { \
            int nsec = ((y).tv_usec - (x).tv_usec) / 1000000; \
            (x).tv_usec -= 1000000 * nsec; \
            (x).tv_sec += nsec; \
        } \
        (x).tv_sec -= (y).tv_sec; \
        (x).tv_usec -= (y).tv_usec; \
    }}} /* TIMEVAL_INPLACE_SUBTRACT */

    #define CLEAR_EVENT(pctrl) \
    {{{ \
        P(&((pctrl)->mutex)); \
        ((pctrl)->idle) = true; \
        pthread_cond_broadcast(&((pctrl)->sched)); \
        V(&((pctrl)->mutex)); \
    }}} /* CLEAR_EVENT */

    #define POST_EVENT(pctrl,type,x...) \
    {{{ \
        P(&((pctrl)->mutex)); \
        ((pctrl)->event) = (event_t){(S_EVENT ## type), {{x}}}; \
        ((pctrl)->idle) = false; \
        pthread_cond_broadcast(&((pctrl)->sched)); \
        V(&((pctrl)->mutex)); \
    }}} /* POST_EVENT */

#ifdef WITH_CUSTOM_MONITOR
    #define SINK_EVENT(pctrl) \
    {{{ \
        P(&((pctrl)->mutex)); \
        while (!IS_IDLE(pctrl)) \
        { \
            pthread_cond_wait(&((pctrl)->sched), &((pctrl)->mutex)); \
        } \
        V(&((pctrl)->mutex)); \
    }}} /* SINK_EVENT */
#endif /* WITH_CUSTOM_MONITOR */

#ifdef WITH_NATIVE_MONITOR
    #define SINK_EVENT(pctrl) \
    {{{ \
        P(&((pctrl)->mutex)); \
        if (IS_IDLE(pctrl)) \
        { \
            DBG("no event detected"); \
            V(&((pctrl)->mutex)); \
            goto cont; \
        } \
        V(&((pctrl)->mutex)); \
        \
        DBG("detected event: %s {%lu %lu %lu %lu %lu %lu %lu}", \
            s_event_type_name((pctrl)->event.type), \
            (pctrl)->event.data.__bitmap__.A, \
            (pctrl)->event.data.__bitmap__.B, \
            (pctrl)->event.data.__bitmap__.C, \
            (pctrl)->event.data.__bitmap__.D, \
            (pctrl)->event.data.__bitmap__.E, \
            (pctrl)->event.data.__bitmap__.F, \
            (pctrl)->event.data.__bitmap__.G); \
        \
        ((policy_entry_t)(pctrl)->policy.entry)(&(pctrl)->policy, \
                                                &(pctrl)->event, \
                                                &(pctrl)->action); \
        \
        DBG("decided action: %s {%lu %lu}", \
            s_action_type_name((pctrl)->action.type), \
            (pctrl)->action.data.__bitmap__.A, \
            (pctrl)->action.data.__bitmap__.B); \
        \
        P(&((pctrl)->mutex)); \
        ((pctrl)->idle) = true; \
        pthread_cond_broadcast(&((pctrl)->sched)); \
        V(&((pctrl)->mutex)); \
    }}} /* SINK_EVENT */
#endif /* WITH_NATIVE_MONITOR */

    DBG("entering: the tracing thread");

    /* The controller should contain pid of the prisoner process */
    pid_t pid = psbox->ctrl.pid;

    /* Check if the prisoner process was correctly forked */
    if (pid < 0)
    {
        WARNING("error forking the prisoner process");
        UPDATE_RESULT(psbox, S_RESULT_IE);
        UPDATE_STATUS(psbox, S_STATUS_FIN);
        FUNC_RET((void *)&psbox->result, "sandbox_tracer()");
    }

    /* Have signals kill the prisoner but not self (if possible).  */
    sighandler_t terminate_signal;
    sighandler_t interrupt_signal;
    sighandler_t quit_signal;

    terminate_signal = signal(SIGTERM, SIG_IGN);
    interrupt_signal = signal(SIGINT, SIG_IGN);
    quit_signal = signal(SIGQUIT, SIG_IGN);

    /* Get wallclock start time */
    gettimeofday(&psbox->stat.started, NULL);

    UPDATE_RESULT(psbox, S_RESULT_PD);
    UPDATE_STATUS(psbox, S_STATUS_EXE);

    /* Resume the control logic */
    CLEAR_EVENT(&psbox->ctrl);

    /* Temporary variables. */
    struct rusage initru;
    int waitstatus = 0;
    pid_t waitresult = 0;
    proc_t proc = {0};

    /* System call stack. The prisoner process initially stops at *SYSRET* mode
     * after making the first call to SYS_execve. Therefore, we initialize the
     * stack as it is. */
    int sc_stack[16] = {0, SYS_execve};
    int sc_top = 1;

    /* Make an initial wait to verify the first system call as well as to
     * collect resource usage overhead. */
    waitresult = wait4(pid, &waitstatus, 0, &psbox->stat.ru);

    UPDATE_STATUS(psbox, S_STATUS_BLK);

    /* Save the initial resource usage for further reference */
    memcpy(&initru, &psbox->stat.ru, sizeof(struct rusage));

    /* Clear cache in order to increase timing accuracy */
    flush_cache();
    flush_cache();

    /* Entering the tracing loop */
    do
    {
        /* Trace state refresh of the prisoner program */
        UPDATE_STATUS(psbox, S_STATUS_BLK);

        /* In case nothing happened (possible when the 3rd argument of *wait4*
         * contains the WNOHANG flag), we just go on with next wait(). */
        if (waitresult == 0)
        {
            DBG("wait: nothing happened");
            goto cont;
        }

        /* Figure *net* resource usage (eliminate initru) */
        TIMEVAL_INPLACE_SUBTRACT(psbox->stat.ru.ru_utime, initru.ru_utime);
        TIMEVAL_INPLACE_SUBTRACT(psbox->stat.ru.ru_stime, initru.ru_stime);
        psbox->stat.ru.ru_majflt -= initru.ru_majflt;
        psbox->stat.ru.ru_minflt -= initru.ru_minflt;
        psbox->stat.ru.ru_nswap -= initru.ru_nswap;

        DBG("ru.ru_utime.tv_sec  % 10ld", psbox->stat.ru.ru_utime.tv_sec);
        DBG("ru.ru_utime.tv_usec % 10ld", psbox->stat.ru.ru_utime.tv_usec);
        DBG("ru.ru_stime.tv_sec  % 10ld", psbox->stat.ru.ru_stime.tv_sec);
        DBG("ru.ru_stime.tv_usec % 10ld", psbox->stat.ru.ru_stime.tv_usec);
        DBG("ru.ru_majflt        % 10ld", psbox->stat.ru.ru_majflt);
        DBG("ru.ru_minflt        % 10ld", psbox->stat.ru.ru_minflt);
        DBG("ru.ru_nswap         % 10ld", psbox->stat.ru.ru_nswap);

        /* Raise appropriate events judging each wait status */
        if (WIFSTOPPED(waitstatus))
        {
            DBG("wait: stopped (%d)", WSTOPSIG(waitstatus));
            psbox->stat.signal = WSTOPSIG(waitstatus);
            /* Collect additional information of the prisoner process */
            if (!proc_probe(pid, PROBE_STAT, &proc))
            {
                WARNING("failed to probe the prisoner process");
                kill(-pid, SIGKILL);
                UPDATE_RESULT(psbox, S_RESULT_IE);
                goto done;
            }
            /* Raise appropriate event judging stop signal */
            switch (WSTOPSIG(waitstatus))
            {
            case SIGALRM:       /* real timer expired */
                POST_EVENT(&psbox->ctrl, _QUOTA, S_QUOTA_WALLCLOCK);
                break;
            case SIGXCPU:       /* CPU resource limit exceed */
            case SIGPROF:       /* profile timer expired */
            case SIGVTALRM:     /* virtual timer expired */
                POST_EVENT(&psbox->ctrl, _QUOTA, S_QUOTA_CPU);
                break;
            case SIGMLE:        /* SIGUSR1 used for reporting ML */
                POST_EVENT(&psbox->ctrl, _QUOTA, S_QUOTA_MEMORY);
                break;
            case SIGXFSZ:       /* Output file size exceeded */
                POST_EVENT(&psbox->ctrl, _QUOTA, S_QUOTA_DISK);
                break;
            case SIGTRAP:
                /* Update the tsc instructions counter */
                #ifdef WITH_TSC_COUNTER
                psbox->stat.tsc++;
                DBG("tsc                 %010llu", psbox->stat.tsc);
                #endif /* WITH_TSC_COUNTER */
                /* Collect additional information of prisoner process */
                if (!proc_probe(pid, PROBE_REGS, &proc))
                {
                    WARNING("failed to probe the prisoner process");
                    kill(-pid, SIGKILL);
                    UPDATE_RESULT(psbox, S_RESULT_IE);
                    goto done;
                }

                /* Update sandbox stat with the process runtime info */
                {
                    psbox->stat.vsize = proc.vsize;
                    if (psbox->stat.vsize_peak < proc.vsize)
                    {
                        psbox->stat.vsize_peak = proc.vsize;
                    }
                    psbox->stat.rss = proc.rss * getpagesize();
                }

                /* Detect memory usage against quota */
                if (psbox->stat.vsize_peak > psbox->task.quota[S_QUOTA_MEMORY])
                {
                    kill(-pid, SIGMLE);
                }

                /* For `single step' tracing mode, we have to probe the current
                 * op code (i.e. INT80 for i386 platforms) to tell whether the
                 * prisoner process is invoking a system call. For `system call'
                 * tracing mode, however, every *SIGTRAP* indicates a system
                 * call currently being invoked or just returned. */
                #ifdef WITH_TSC_COUNTER
                if (IS_SYSCALL(&proc) || IS_SYSRET(&proc))
                #endif /* WITH_TSC_COUNTER */
                {
                    int scno = THE_SYSCALL(&proc);
                    if (scno != sc_stack[sc_top])
                    {
                        sc_stack[++sc_top] = scno;
                        psbox->stat.syscall = scno;
                        SET_IN_SYSCALL(&proc);
                        POST_EVENT(&psbox->ctrl, _SYSCALL, scno,
                                                           SYSCALL_ARG1(&proc),
                                                           SYSCALL_ARG2(&proc),
                                                           SYSCALL_ARG3(&proc),
                                                           SYSCALL_ARG4(&proc),
                                                           SYSCALL_ARG5(&proc));
                    }
                    else
                    {
                        CLR_IN_SYSCALL(&proc);
                        sc_stack[sc_top--] = 0;
                        POST_EVENT(&psbox->ctrl, _SYSRET, scno,
                                                          SYSRET_RETVAL(&proc));
                    }
                }
                #ifdef WITH_TSC_COUNTER
                else
                {
                    goto next;
                }
                #endif /* WITH_TSC_COUNTER */
                break;
            default:            /* Other runtime error */
                POST_EVENT(&psbox->ctrl, _SIGNAL, WSTOPSIG(waitstatus));
                break;
            }
        } /* stopped */
        else if (WIFSIGNALED(waitstatus))
        {
            DBG("wait: signaled (%d)", WTERMSIG(waitstatus));
            psbox->stat.signal = WTERMSIG(waitstatus);
            POST_EVENT(&psbox->ctrl, _SIGNAL, WTERMSIG(waitstatus));
        }
        else if (WIFEXITED(waitstatus))
        {
            DBG("wait: exited (%d)", WEXITSTATUS(waitstatus));
            psbox->stat.exitcode = WEXITSTATUS(waitstatus);
            POST_EVENT(&psbox->ctrl, _EXIT, WEXITSTATUS(waitstatus));
        }

        /* Wait for the policy to determine the next action */
        SINK_EVENT(&psbox->ctrl);

        /* Perform the desired action */
        switch (psbox->ctrl.action.type)
        {
        case S_ACTION_CONT:
    next:
            #ifdef WITH_TSC_COUNTER
            if (!trace_next(&proc, TRACE_SINGLE_STEP))
            #else
            if (!trace_next(&proc, TRACE_SYSTEM_CALL))
            #endif /* WITH_TSC_COUNTER */
            {
                WARNING("trace_next");
                kill(-pid, SIGKILL);
                UPDATE_RESULT(psbox, S_RESULT_IE);
                break;
            }
            /* There is no need to update state here! */
            goto cont;          /* Continue with next wait() */
        case S_ACTION_FINI:
            UPDATE_RESULT(psbox, psbox->ctrl.action.data._FINI.result);
            break;
        case S_ACTION_KILL:
            /* Using trace_kill can effectively prevent overrun of undesired
             * behavior, i.e. illegal system call. */
            trace_kill(&proc, SIGKILL);
            UPDATE_RESULT(psbox, psbox->ctrl.action.data._KILL.result);
            break;
        }
        break;                  /* Exiting the tracing loop! */

    cont:
        /* Wait until the prisoner process is trapped  */
        UPDATE_STATUS(psbox, S_STATUS_EXE);
        DBG("----------------------------------------------------------------");
        DBG("wait4(%d,%p,%d,%p)", pid, &waitstatus, 0, &psbox->stat.ru);
        waitresult = waitstatus = 0;
    } while ((waitresult = wait4(pid, &waitstatus, 0, &psbox->stat.ru)) >= 0);

done:
    /* Get wallclock stop time (call a second time to compensate overhead) */
    gettimeofday(&psbox->stat.stopped, NULL);

    UPDATE_STATUS(psbox, S_STATUS_FIN);

    /* Resume the control logic */
    CLEAR_EVENT(&psbox->ctrl);

    DBG("leaving: the tracing thread");

    /* Restore signal handlers */
    signal(SIGTERM, interrupt_signal);
    signal(SIGINT, interrupt_signal);
    signal(SIGQUIT, quit_signal);

    FUNC_RET((void *)&psbox->result, "sandbox_tracer()");
}
//------------------------------------------------------------------------------
// Name: handle_event
// Desc:
//------------------------------------------------------------------------------
IDebugEvent::const_pointer DebuggerCore::handle_event(edb::tid_t tid, int status) {

	// note that we have waited on this thread
	waited_threads_.insert(tid);

	// was it a thread exit event?
	if(WIFEXITED(status)) {
		threads_.remove(tid);
		waited_threads_.remove(tid);

		// if this was the last thread, return true
		// so we report it to the user.
		// if this wasn't, then we should silently
		// procceed.
		if(!threads_.empty()) {
			return nullptr;
		}
	}

	// was it a thread create event?
	if(is_clone_event(status)) {

		unsigned long new_tid;
		if(ptrace_get_event_message(tid, &new_tid) != -1) {

			auto newThread     = std::make_shared<PlatformThread>(this, process_, new_tid);
			newThread->status_ = 0;
			newThread->state_  = PlatformThread::Stopped;

			threads_.insert(new_tid, newThread);

			int thread_status = 0;
			if(!waited_threads_.contains(new_tid)) {
				if(native::waitpid(new_tid, &thread_status, __WALL) > 0) {
					waited_threads_.insert(new_tid);
				}
			}

			if(!WIFSTOPPED(thread_status) || WSTOPSIG(thread_status) != SIGSTOP) {
				qDebug("[warning] new thread [%d] received an event besides SIGSTOP", static_cast<int>(new_tid));
			}
			
			newThread->status_ = thread_status;

			// TODO: what the heck do we do if this isn't a SIGSTOP?
			newThread->resume();
		}

		ptrace_continue(tid, 0);
		return nullptr;
	}

	// normal event


	auto e = std::make_shared<PlatformEvent>();

	e->pid_    = pid();
	e->tid_    = tid;
	e->status_ = status;
	if(ptrace_getsiginfo(tid, &e->siginfo_) == -1) {
		// TODO: handle no info?
	}

	active_thread_ = tid;
	
	auto it = threads_.find(tid);
	if(it != threads_.end()) {
		it.value()->status_ = status;
	}

	stop_threads();
	return e;
}
//------------------------------------------------------------------------------
// Name: open
// Desc:
//------------------------------------------------------------------------------
bool DebuggerCore::open(const QString &path, const QString &cwd, const QList<QByteArray> &args, const QString &tty) {
	detach();

	switch(pid_t pid = fork()) {
	case 0:
		// we are in the child now...

		// set ourselves (the child proc) up to be traced
		ptrace_traceme();

		// redirect it's I/O
		if(!tty.isEmpty()) {
			FILE *const std_out = freopen(qPrintable(tty), "r+b", stdout);
			FILE *const std_in  = freopen(qPrintable(tty), "r+b", stdin);
			FILE *const std_err = freopen(qPrintable(tty), "r+b", stderr);

			Q_UNUSED(std_out);
			Q_UNUSED(std_in);
			Q_UNUSED(std_err);
		}

		// do the actual exec
		execute_process(path, cwd, args);

		// we should never get here!
		abort();
		break;
	case -1:
		// error! for some reason we couldn't fork
		reset();
		return false;
	default:
		// parent
		do {
			reset();

			int status;
			if(native::waitpid(pid, &status, __WALL) == -1) {
				return false;
			}

			// the very first event should be a STOP of type SIGTRAP
			if(!WIFSTOPPED(status) || WSTOPSIG(status) != SIGTRAP) {
				detach();
				return false;
			}

			waited_threads_.insert(pid);

			// enable following clones (threads)
			if(ptrace_set_options(pid, PTRACE_O_TRACECLONE) == -1) {
				qDebug("[DebuggerCore] failed to set PTRACE_SETOPTIONS: %s", strerror(errno));
				detach();
				return false;
			}
			
#ifdef PTRACE_O_EXITKILL
			if(ptrace_set_options(pid, PTRACE_O_EXITKILL) == -1) {
				qDebug("[DebuggerCore] failed to set PTRACE_SETOPTIONS: %s", strerror(errno));
				detach();
				return false;
			}
#endif

			// setup the first event data for the primary thread
			waited_threads_.insert(pid);
			
			// create the process
			process_ = new PlatformProcess(this, pid);
			

			// the PID == primary TID
			auto newThread     = std::make_shared<PlatformThread>(this, process_, pid);
			newThread->status_ = status;
			newThread->state_  = PlatformThread::Stopped;
			
			threads_[pid]   = newThread;

			pid_            = pid;
			active_thread_   = pid;
			binary_info_    = edb::v1::get_binary_info(edb::v1::primary_code_region());

			detectDebuggeeBitness();

			return true;
		} while(0);
		break;
	}
}
示例#10
0
文件: sandbox.cpp 项目: Jisuanke/wai
int Sandbox::Run(bool is_rf, bool is_hvc) {
    if (access(m_path.c_str(), R_OK | X_OK)) {
        fprintf(stderr, "Cannot access %s\n", m_path.c_str());
        return -1;
    }
    fprintf(stderr, "%s begin to run\n", m_path.c_str());
    int fd1[2], fd2[2], info_fd[2];
    if (pipe(fd1) < 0 || pipe(fd2) < 0 || pipe(info_fd) < 0) {
        fprintf(stderr, "Error on pipe()\n");
        return -1;
    }
    pid_t child_pid = fork();
    if (child_pid < 0) {
        fprintf(stderr, "error on fork()\n");
        return -1;
    } else if (child_pid == 0) {
        close(fd1[1]);
        close(fd2[0]);
        close(info_fd[0]);
        pid_t grandson_pid = fork();
        if (grandson_pid < 0) {
            fprintf(stderr, "error on fork()\n");
            return -1;
        } else if (grandson_pid == 0) {
            // grandson: the actual executable
            close(info_fd[1]);
            if (fd1[0] != STDIN_FILENO) {
                dup2(fd1[0], STDIN_FILENO);
                close(fd1[0]);
            }
            if (fd2[1] != STDOUT_FILENO) {
                dup2(fd2[1], STDOUT_FILENO);
                close(fd2[1]);
            }
            // setrlimit
            if (set_quota() < 0) {
                fprintf(stderr, "set_quota() error\n");
            }
            ptrace(PTRACE_TRACEME, 0, NULL, NULL);
            if (is_hvc) {
              execl(m_path.c_str(), m_path.c_str(), "1", NULL);
            } else {
              execl(m_path.c_str(), m_path.c_str(), NULL);
            }
            fprintf(stderr, "execl failed, errno: %d\n", errno);
            return -1;  
        } else {
            fprintf(stderr, "%d: i am the sandbox of %d\n", getpid(), grandson_pid);
            // son: the sandbox
            close(fd1[0]);
            close(fd2[1]);
            char pid_buf[16];
            sprintf(pid_buf, "%d\n", grandson_pid);
            write(info_fd[1], pid_buf, strlen(pid_buf));
            sleep(1); // sleep to ensure the grand recv the msg
            int st, in_call = 0;
            while (1) {
                struct rusage ru;
                wait4(grandson_pid, &st, 0, &ru);
                m_time_cost = ru.ru_utime.tv_sec * 1000 +
                         ru.ru_utime.tv_usec / 1000;
                if (WIFEXITED(st)) {
                    m_exit_flag = EXIT_NORMAL;
                    fprintf(stderr, "exit_normal\n");
                    break;
                }
                if (WIFSIGNALED(st) || (WIFSTOPPED(st) && WSTOPSIG(st) != SIGTRAP)) {
                    if (WIFSTOPPED(st)) {
                        switch (WSTOPSIG(st)) {
                            case SIGXCPU:
                                m_exit_flag = EXIT_TLE;
                                fprintf(stderr, "pid:%d m_exit_flag:%d\n", getpid(), EXIT_TLE);
                                break;
                            case SIGPIPE:
                                // match is over, the match process is terminated
                                m_exit_flag = EXIT_NORMAL;
                                break;
                            default:
                                fprintf(stderr, "pid:%d exit: WSTOPSIG(st):%d\n", getpid(), WSTOPSIG(st));
                                m_exit_flag = EXIT_RE;
                        }
                    }
                    else if (WIFSIGNALED(st)) {
                        fprintf(stderr, "termed by sig: %d\n", WTERMSIG(st));
                        m_exit_flag = EXIT_RE;
                    } else {
                        fprintf(stderr, "termed by sig: %d\n", WTERMSIG(st));
                    }
                    ptrace(PTRACE_KILL, grandson_pid, NULL, NULL);
                    break;
                }
                if (in_call == 0) {
#ifdef __x86_64__
                    long long orig_eax = ptrace(PTRACE_PEEKUSER, grandson_pid,
                            8 * ORIG_RAX, NULL);
#else
                    int orig_eax = ptrace(PTRACE_PEEKUSER, grandson_pid, 
                            4 * ORIG_EAX, NULL);
#endif
                    assert(orig_eax >= 0 && orig_eax < 512);
                    if (is_rf && --m_limit[orig_eax] < 0) {
                        m_exit_flag = EXIT_RF;
                        fprintf(stderr, "pid:%d Sys call %d reach limit\n", 
                                getpid(), static_cast<int>(orig_eax));
                    }
                    ++m_stat[orig_eax];
                    in_call = 1;
                } else {
                    in_call = 0;
                }
                if (m_exit_flag == EXIT_RF) {
                    ptrace(PTRACE_KILL, grandson_pid, NULL, NULL);
                    break;
                }
                ptrace(PTRACE_SYSCALL, grandson_pid, NULL, NULL);
            }
            char buf[16];
            // sprintf(buf, "%d %d\n", GetID(), GetUsedTime());
            // write(GetInfoFd(), buf, strlen(buf));
            fprintf(stderr, "%d: the proc in sandbox exit type: %d, time_cost: %d\n", getpid(), m_exit_flag, m_time_cost);
            fprintf(stderr, "%d: i am exited\n", getpid());
            sprintf(buf, "%d %d\n", m_exit_flag, m_time_cost);
            write(info_fd[1], buf, strlen(buf));
            exit(0);    // the sandbox process exit
        }
    } else {
        // parent
        close(fd1[0]);
        close(fd2[1]);
        close(info_fd[1]);
        recv_fd = fd2[0];
        send_fd = fd1[1];
        recv_info_fd = info_fd[0];
        char buf_pid[16];
        read(recv_info_fd, buf_pid, sizeof(buf_pid)-1);
        // read the client's pid
        sscanf(buf_pid, "%d", &m_client_pid);
        fprintf(stderr, "%d: i am grand, i recv the client pid: %d\n", getpid(), m_client_pid);
    }
    return 0;
}
示例#11
0
文件: xocopy.c 项目: yingted/home
int
main (int argc, char *argv[])
{
    char *filename;
    char out_filename[8192];
    char buf[1024];
    struct stat stat_buf;
    pid_t pid;
    int status;
    int ret_val;
    size_t file_size;
    unsigned int addr;
    int bad_usage;

    filename = NULL;
    addr = 0;

    /* process args: assigning values to bad_usage filename and possibly addr */
    bad_usage = 1;
    if (argc == 2) {
        filename = argv[1];
        bad_usage = 0;
    }
    else if (argc == 4) {
        filename = argv[3];

        if (strcmp(argv[1], "-a") == 0) {
            if ((argv[2][0] == '0') && (tolower(argv[2][1]) == 'x'))
                addr = strtol(argv[2], NULL, 16);
            else
                addr = strtol(argv[2], NULL, 10);
            if (errno != ERANGE)
                bad_usage = 0;
        }
    }

    if (bad_usage) {
        fprintf(stderr, "Obtains an executable copy of a binary with execute "
                "but no read permission\n"
                "Usage: %s [-a addr] <file>\n"
                "  where addr is the memory address of the elf header\n",
                argv[0]);
        exit(EXIT_FAILURE);
    }

    if (stat(filename, &stat_buf) != 0) {
        snprintf(buf, sizeof(buf), "couldn't stat file `%s'", filename);
        perror(buf);
        exit(EXIT_FAILURE);
    }

    /* remember file size of original file */
    file_size = stat_buf.st_size;

    if ( (pid = fork()) == 0) {
        /* child */
        if (ptrace(PTRACE_TRACEME, 0, 0, 0) == 0) {
            execl(filename, filename, NULL);
            snprintf(buf, sizeof(buf), "couldn't exec `%s'", filename);
            perror(buf);
        }
        else {
            perror("ptrace(PTRACE_TRACEME, ...)");
        }
        _exit(EXIT_FAILURE);
    }

    ret_val = EXIT_FAILURE;
    if (waitpid(pid, &status, WUNTRACED) == pid) {
        if (!WIFEXITED(status)) {
            /* SIGTRAP is delivered to child after execve */
            if (WIFSTOPPED(status) && WSTOPSIG(status) == SIGTRAP) {
                if (addr == 0)
                    addr = find_elf_header(pid);
                if (addr != 0) {
                    snprintf(out_filename, sizeof(out_filename), "%s.out",
                             basename(filename));

                    if (save_to_file(out_filename, pid, addr, file_size)) {
                        chmod(out_filename, 00755);
                        fprintf(stdout, "created file `%s'\n", out_filename);
                        ret_val = EXIT_SUCCESS;
                    }
                }
                else {
                    fprintf(stderr, "couldn't find elf header in memory\n");
                }
            }
            else {
                fprintf(stderr, "didn't receive SIGTRAP after execve\n");
            }

            /* kill child as we are finished */
            ptrace(PTRACE_KILL, pid, 0, 0);
        }
    }
    else {
        perror("waitpid");
    }

    return(ret_val);
}
示例#12
0
int
main (int argc, char **argv)
{
  int status, pid, pending_sig, optind = 1, state = 1;

  as = unw_create_addr_space (&_UPT_accessors, 0);
  if (!as)
    panic ("unw_create_addr_space() failed");

  if (argc == 1)
    {
      static char *args[] = { "self", "/bin/ls", "/usr", NULL };

      /* automated test case */
      argv = args;
    }
  else if (argc > 1)
    while (argv[optind][0] == '-')
      {
	if (strcmp (argv[optind], "-v") == 0)
	  ++optind, verbose = 1;
	else if (strcmp (argv[optind], "-i") == 0)
	  ++optind, trace_mode = INSTRUCTION;	/* backtrace at each insn */
	else if (strcmp (argv[optind], "-s") == 0)
	  ++optind, trace_mode = SYSCALL;	/* backtrace at each syscall */
	else if (strcmp (argv[optind], "-t") == 0)
	  /* Execute until raise(SIGUSR1), then backtrace at each insn
	     until raise(SIGUSR2).  */
	  ++optind, trace_mode = TRIGGER;
	else if (strcmp (argv[optind], "-c") == 0)
	  /* Enable caching of unwind-info.  */
	  ++optind, unw_set_caching_policy (as, UNW_CACHE_GLOBAL);
	else if (strcmp (argv[optind], "-n") == 0)
	  /* Don't look-up and print symbol names.  */
	  ++optind, print_names = 0;
	else
	  fprintf(stderr, "unrecognized option: %s\n", argv[optind++]);
        if (optind >= argc)
          break;
      }

  target_pid = fork ();
  if (!target_pid)
    {
      /* child */

      if (!verbose)
	dup2 (open ("/dev/null", O_WRONLY), 1);

#if HAVE_DECL_PTRACE_TRACEME
      ptrace (PTRACE_TRACEME, 0, 0, 0);
#elif HAVE_DECL_PT_TRACE_ME
      ptrace (PT_TRACE_ME, 0, 0, 0);
#else
#error Trace me
#endif

      if ((argc > 1) && (optind == argc)) {
        fprintf(stderr, "Need to specify a command line for the child\n");
        exit (-1);
      }
      execve (argv[optind], argv + optind, environ);
      _exit (-1);
    }
  atexit (target_pid_kill);

  ui = _UPT_create (target_pid);

  while (nerrors <= nerrors_max)
    {
      pid = wait4 (-1, &status, 0, NULL);
      if (pid == -1)
	{
	  if (errno == EINTR)
	    continue;

	  panic ("wait4() failed (errno=%d)\n", errno);
	}
      pending_sig = 0;
      if (WIFSIGNALED (status) || WIFEXITED (status)
	  || (WIFSTOPPED (status) && WSTOPSIG (status) != SIGTRAP))
	{
	  if (WIFEXITED (status))
	    {
	      if (WEXITSTATUS (status) != 0)
		panic ("child's exit status %d\n", WEXITSTATUS (status));
	      break;
	    }
	  else if (WIFSIGNALED (status))
	    {
	      if (!killed)
		panic ("child terminated by signal %d\n", WTERMSIG (status));
	      break;
	    }
	  else
	    {
	      pending_sig = WSTOPSIG (status);
	      /* Avoid deadlock:  */
	      if (WSTOPSIG (status) == SIGKILL)
	        break;
	      if (trace_mode == TRIGGER)
		{
		  if (WSTOPSIG (status) == SIGUSR1)
		    state = 0;
		  else if  (WSTOPSIG (status) == SIGUSR2)
		    state = 1;
		}
	      if (WSTOPSIG (status) != SIGUSR1 && WSTOPSIG (status) != SIGUSR2)
	        {
		  static int count = 0;

		  if (count++ > 100)
		    {
		      panic ("Too many child unexpected signals (now %d)\n",
			     WSTOPSIG (status));
			killed = 1;
		    }
	        }
	    }
	}

      switch (trace_mode)
	{
	case TRIGGER:
	  if (state)
#if HAVE_DECL_PTRACE_CONT
	    ptrace (PTRACE_CONT, target_pid, 0, 0);
#elif HAVE_DECL_PT_CONTINUE
	    ptrace (PT_CONTINUE, target_pid, (caddr_t)1, 0);
#else
#error Port me
#endif
	  else
	    {
	      do_backtrace ();
#if HAVE_DECL_PTRACE_SINGLESTEP
	      if (ptrace (PTRACE_SINGLESTEP, target_pid, 0, pending_sig) < 0)
          {
            panic ("ptrace(PTRACE_SINGLESTEP) failed (errno=%d)\n", errno);
            killed = 1;
          }
#elif HAVE_DECL_PT_STEP
	      if (ptrace (PT_STEP, target_pid, (caddr_t)1, pending_sig) < 0)
          {
            panic ("ptrace(PT_STEP) failed (errno=%d)\n", errno);
            killed = 1;
          }
#else
#error Singlestep me
#endif
	    }
	  break;

	case SYSCALL:
	  if (!state)
	    do_backtrace ();
	  state ^= 1;
#if HAVE_DECL_PTRACE_SYSCALL
	  ptrace (PTRACE_SYSCALL, target_pid, 0, pending_sig);
#elif HAVE_DECL_PT_SYSCALL
	  ptrace (PT_SYSCALL, target_pid, (caddr_t)1, pending_sig);
#else
#error Syscall me
#endif
	  break;

	case INSTRUCTION:
	  do_backtrace ();
#if HAVE_DECL_PTRACE_SINGLESTEP
	      ptrace (PTRACE_SINGLESTEP, target_pid, 0, pending_sig);
#elif HAVE_DECL_PT_STEP
	      ptrace (PT_STEP, target_pid, (caddr_t)1, pending_sig);
#else
#error Singlestep me
#endif
	  break;
	}
      if (killed)
        kill (target_pid, SIGKILL);
    }
示例#13
0
/* Run the command with op as command line argument(s) and return the exit
 * status + the output */
static int 
external_run_cmd(struct pluginDevice *sd, const char *op, char **output)
{
	const int		BUFF_LEN=4096;
	char			buff[BUFF_LEN];
	int			read_len = 0;
	int			status, rc;
	char * 			data = NULL;
	FILE *			file;
	char			cmd[FILENAME_MAX+64];
	struct stat		buf;
	int			slen;
	char *path, *new_path, *logtag, *savevar = NULL;
	int new_path_len, logtag_len;
	gboolean		nodata;

	rc = snprintf(cmd, FILENAME_MAX, "%s/%s", 
		STONITH_EXT_PLUGINDIR, sd->subplugin);
	if (rc <= 0 || rc >= FILENAME_MAX) {
		LOG(PIL_CRIT, "%s: external command too long.", __FUNCTION__);
		return -1;
	}
	
	if (stat(cmd, &buf) != 0) {
		LOG(PIL_CRIT, "%s: stat(2) of %s failed: %s",
			__FUNCTION__, cmd, strerror(errno));
                return -1;
        }

        if (!S_ISREG(buf.st_mode) 
	    || (!(buf.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)))) {
		LOG(PIL_CRIT, "%s: %s found NOT to be executable.",
			__FUNCTION__, cmd);
		return -1;
	}

	if (buf.st_mode & (S_IWGRP|S_IWOTH)) {
		LOG(PIL_CRIT, "%s: %s found to be writable by group/others, "
			"NOT executing for security purposes.",
			__FUNCTION__, cmd);
		return -1;
	}

	strcat(cmd, " ");
	strcat(cmd, op);

	/* We only have a global environment to use here. So we add our
	 * options to it, and then later remove them again. */
	if (sd->cmd_opts) {
		g_hash_table_foreach(sd->cmd_opts, ext_add_to_env, NULL);
	}

	/* external plugins need path to ha_log.sh */
	path = getenv("PATH");
	if (strncmp(GLUE_SHARED_DIR,path,strlen(GLUE_SHARED_DIR))) {
		new_path_len = strlen(path)+strlen(GLUE_SHARED_DIR)+2;
		new_path = (char *)g_malloc(new_path_len);
		snprintf(new_path, new_path_len, "%s:%s", GLUE_SHARED_DIR, path);
		setenv("PATH", new_path, 1);
		g_free(new_path);
	}

	/* set the logtag appropriately */
	logtag_len = strlen(PIL_PLUGIN_S)+strlen(sd->subplugin)+2;
	logtag = (char *)g_malloc(logtag_len);
	snprintf(logtag, logtag_len, "%s/%s", PIL_PLUGIN_S, sd->subplugin);
	if (getenv(LOGTAG_VAR)) {
		savevar = g_strdup(getenv(LOGTAG_VAR));
	}
	setenv(LOGTAG_VAR, logtag, 1);
	g_free(logtag);

	if (Debug) {
		LOG(PIL_DEBUG, "%s: Calling '%s'", __FUNCTION__, cmd );
	}
	file = popen(cmd, "r");
	if (NULL==file) {
		LOG(PIL_CRIT, "%s: Calling '%s' failed",
			__FUNCTION__, cmd);
		rc = -1;
		goto out;
	}

	if (output) {
		slen=0;
		data = MALLOC(1);
		data[slen] = EOS;
	}
	while (!feof(file)) {
		nodata = TRUE;
		if (output) {
			read_len = fread(buff, 1, BUFF_LEN, file);
			if (read_len > 0) {
				data = REALLOC(data, slen+read_len+1);
				if (data == NULL) {
					break;
				}
				memcpy(data + slen, buff, read_len);
				slen += read_len;
				data[slen] = EOS;
				nodata = FALSE;
			}
		} else {
			if (fgets(buff, BUFF_LEN, file)) {	
				LOG(PIL_INFO, "%s: '%s' output: %s", __FUNCTION__, cmd, buff);
				nodata = FALSE;
			}
		}
		if (nodata) {
			sleep(1);
		}
	}
	if (output && !data) {
		LOG(PIL_CRIT, "%s: out of memory", __FUNCTION__);
		rc = -1;
		goto out;
	}

	status = pclose(file);
	if (WIFEXITED(status)) {
		rc = WEXITSTATUS(status);
		if (rc != 0 && Debug) {
			LOG(PIL_DEBUG,
				"%s: Calling '%s' returned %d", __FUNCTION__, cmd, rc);
		}
	} else {
		if (WIFSIGNALED(status)) {
			LOG(PIL_CRIT, "%s: '%s' got signal %d",
				__FUNCTION__, cmd, WTERMSIG(status));
		} else if (WIFSTOPPED(status)) {
			LOG(PIL_INFO, "%s: '%s' stopped with signal %d",
				__FUNCTION__, cmd, WSTOPSIG(status));
		} else {
			LOG(PIL_CRIT, "%s: '%s' exited abnormally (core dumped?)",
				__FUNCTION__, cmd);
		}
		rc = -1;
	}
	if (Debug && output && data) {
		LOG(PIL_DEBUG, "%s: '%s' output: %s", __FUNCTION__, cmd, data);
	}

out:
	if (savevar) {
		setenv(LOGTAG_VAR, savevar, 1);
		g_free(savevar);
	} else {
		unsetenv(LOGTAG_VAR);
	}
	if (sd->cmd_opts)  {
		g_hash_table_foreach(sd->cmd_opts, ext_del_from_env, NULL);
	}
	if (!rc) {
		if (output) {
			*output = data;
		}
	} else {
		if (data) {
			FREE(data);
		}
		if (output) {
			*output = NULL;
		}
	}
	return rc;
}
示例#14
0
void TraceProcess::traceMe() {
    struct user_regs_struct regs;

    DLOG(INFO) << pid << " trace_me\n";

    //the waitpid function will be interuppted by the SIGCHLD signal
    int wret;
#ifdef HAVE_WAIT4
	while((wret = wait4(this->pid, &status, 0, &process_usage)) > 0) {
		getusage = true;
#else
    while((wret = waitpid(this->pid, &status, 0)) > 0) {
#endif
        //DLOG(INFO) << pid << " waitpid return " << wret << "\n";

        if(WIFSIGNALED(status)) {
            DLOG(INFO) << "TraceProcess()::traceMe(): child was killed by signal\n";

            _exit = true;
            if(WTERMSIG(status) == SIGKILL && this->_result == -1) {
                this->_result = RUNTIME_ERROR;
            }
            break;
        }

        if(!WIFSTOPPED(status)) {
            //if(WEXITSTATUS(status)) {
            //    this->_result = RUNTIME_ERROR;
            //}
            _exit = true;
            break;
        }

        int sig = WSTOPSIG(status);
        if(sig != SIGTRAP) {
            DLOG(INFO) << "TraceProcess()::traceMe(): caught a signal " << sig << "\n";

            getRunningTime();
            getRunningMemory();

            switch(sig) {
            case SIGFPE:
                DLOG(INFO) << "TraceProcess()::traceMe(): SIGFPE\n";

                this->_result = FLOATING_POINT_ERROR;
                break;

            case SIGXCPU:
                DLOG(INFO) << "TraceProcess()::traceMe(): SIGXCPU\n";

                this->_result = TIME_LIMIT_EXCEEDED;
                break;

            case SIGBUS:
            case SIGSEGV:
                DLOG(INFO) << "TraceProcess()::traceMe(): SIGSEGV\n";

                this->_result = SEGMENTATION_FAULT;
                break;

            case SIGXFSZ:
                DLOG(INFO) << "TraceProcess()::traceMe(): SIGXFSZ\n";

                this->_result = OUTPUT_LIMIT_EXCEEDED;
                break;

            case SIGILL:
            case SIGKILL:
                DLOG(INFO) << "TraceProcess()::traceMe(): SIGKILL\n";

                if(this->_result == -1) {
                    this->_result = RUNTIME_ERROR;
                }
                break;

            case SIGALRM:
                ;
            }

            ptrace(PTRACE_SYSCALL, this->pid, NULL, sig);
            continue;
        }

        ptrace(PTRACE_GETREGS, this->pid, 0, &regs);
        
        switch(regs.ORIG_EAX) {
        case SYS_exit:
        case SYS_exit_group:
            DLOG(INFO) << "TraceProcess()::traceMe(): child sys_exit\n";

            getRunningTime();
            getRunningMemory();
            break;

        case SYS_execve:
            if(!first_exec) {
                first_exec = true;
                DLOG(INFO) << pid << " execve, ptrace it\n";

                ptrace(PTRACE_SYSCALL, this->pid, NULL, NULL);
                continue;
            }
            break;

        case SYS_brk:
            if(!insyscall) {
               brk = (unsigned long)regs.EBX;
               insyscall = true;
            }else{
                if(((unsigned long)regs.EAX) < brk) {
                    DLOG(INFO) << "TraceProcess()::traceMe(): brk request " << brk << " return " << regs.EAX << "\n";

                    this->_result = MEMORY_LIMIT_EXCEEDED;
                    ptrace(PTRACE_KILL, this->pid, 0, 0);
                    continue;
                }
                insyscall = false;
            }
            break;
        
        case SYS_open:
            if(!insyscall) {
                char path[FILENAME_MAX + 1];
                insyscall = true;
                getdata(regs.EBX, path, sizeof(path));
				DLOG(INFO) << "open file:" << path << "\n";
                if(!canOpen(path, regs.ECX)) {
					regs.ORIG_EAX = SYS_exit;
					regs.EBX = 1;
					ptrace(PTRACE_SETREGS, this->pid, 0, &regs);
                    this->_result = RUNTIME_ERROR;
					break;
                }
            }else{
                insyscall = false;
            }
            ptrace(PTRACE_SYSCALL, this->pid, 0, 0);
            continue;
        }

        if(regs.ORIG_EAX < sizeof(disabled_syscall) &&
            disabled_syscall[regs.ORIG_EAX]) {

            DLOG(INFO) << "TraceProcess()::traceMe(): Restricted syscall " << regs.ORIG_EAX << "\n";

            this->_result = RESTRICTED_FUNCTION;
            getRunningTime();
            getRunningMemory();

			regs.ORIG_EAX = SYS_exit;
			regs.EAX = SYS_exit;
			regs.EBX = 1;
			ptrace(PTRACE_SETREGS, this->pid, NULL, &regs);
            ptrace(PTRACE_KILL, this->pid, 0, 0);
			continue;
        }else{
            ptrace(PTRACE_SYSCALL, this->pid, 0, 0);
        }

        ptrace(PTRACE_SYSCALL, this->pid, NULL, NULL);
    }
}
示例#15
0
static int
linux_wait_for_event (struct thread_info *child)
{
  CORE_ADDR stop_pc;
  struct process_info *event_child;
  int wstat;

  /* Check for a process with a pending status.  */
  /* It is possible that the user changed the pending task's registers since
     it stopped.  We correctly handle the change of PC if we hit a breakpoint
     (in check_removed_breakpoints); signals should be reported anyway.  */
  if (child == NULL)
    {
      event_child = (struct process_info *)
	find_inferior (&all_processes, status_pending_p, NULL);
      if (debug_threads && event_child)
	fprintf (stderr, "Got a pending child %d\n", event_child->lwpid);
    }
  else
    {
      event_child = get_thread_process (child);
      if (event_child->status_pending_p
	  && check_removed_breakpoint (event_child))
	event_child = NULL;
    }

  if (event_child != NULL)
    {
      if (event_child->status_pending_p)
	{
	  if (debug_threads)
	    fprintf (stderr, "Got an event from pending child %d (%04x)\n",
		     event_child->lwpid, event_child->status_pending);
	  wstat = event_child->status_pending;
	  event_child->status_pending_p = 0;
	  event_child->status_pending = 0;
	  current_inferior = get_process_thread (event_child);
	  return wstat;
	}
    }

  /* We only enter this loop if no process has a pending wait status.  Thus
     any action taken in response to a wait status inside this loop is
     responding as soon as we detect the status, not after any pending
     events.  */
  while (1)
    {
      if (child == NULL)
	event_child = NULL;
      else
	event_child = get_thread_process (child);

      linux_wait_for_process (&event_child, &wstat);

      if (event_child == NULL)
	error ("event from unknown child");

      current_inferior = (struct thread_info *)
	find_inferior_id (&all_threads, event_child->tid);

      if (using_threads)
	{
	  /* Check for thread exit.  */
	  if (! WIFSTOPPED (wstat))
	    {
	      if (debug_threads)
		fprintf (stderr, "Thread %d (LWP %d) exiting\n",
			 event_child->tid, event_child->head.id);

	      /* If the last thread is exiting, just return.  */
	      if (all_threads.head == all_threads.tail)
		return wstat;

	      dead_thread_notify (event_child->tid);

	      remove_inferior (&all_processes, &event_child->head);
	      free (event_child);
	      remove_thread (current_inferior);
	      current_inferior = (struct thread_info *) all_threads.head;

	      /* If we were waiting for this particular child to do something...
		 well, it did something.  */
	      if (child != NULL)
		return wstat;

	      /* Wait for a more interesting event.  */
	      continue;
	    }

	  if (WIFSTOPPED (wstat)
	      && WSTOPSIG (wstat) == SIGSTOP
	      && event_child->stop_expected)
	    {
	      if (debug_threads)
		fprintf (stderr, "Expected stop.\n");
	      event_child->stop_expected = 0;
	      linux_resume_one_process (&event_child->head,
					event_child->stepping, 0);
	      continue;
	    }

	  /* FIXME drow/2002-06-09: Get signal numbers from the inferior's
	     thread library?  */
	  if (WIFSTOPPED (wstat)
	      && (WSTOPSIG (wstat) == SIGRTMIN
		  || WSTOPSIG (wstat) == SIGRTMIN + 1))
	    {
	      if (debug_threads)
		fprintf (stderr, "Ignored signal %d for %d (LWP %d).\n",
			 WSTOPSIG (wstat), event_child->tid,
			 event_child->head.id);
	      linux_resume_one_process (&event_child->head,
					event_child->stepping,
					WSTOPSIG (wstat));
	      continue;
	    }
	}

      /* If this event was not handled above, and is not a SIGTRAP, report
	 it.  */
      if (!WIFSTOPPED (wstat) || WSTOPSIG (wstat) != SIGTRAP)
	return wstat;

      /* If this target does not support breakpoints, we simply report the
	 SIGTRAP; it's of no concern to us.  */
      if (the_low_target.get_pc == NULL)
	return wstat;

      stop_pc = get_stop_pc ();

      /* bp_reinsert will only be set if we were single-stepping.
	 Notice that we will resume the process after hitting
	 a gdbserver breakpoint; single-stepping to/over one
	 is not supported (yet).  */
      if (event_child->bp_reinsert != 0)
	{
	  if (debug_threads)
	    fprintf (stderr, "Reinserted breakpoint.\n");
	  reinsert_breakpoint (event_child->bp_reinsert);
	  event_child->bp_reinsert = 0;

	  /* Clear the single-stepping flag and SIGTRAP as we resume.  */
	  linux_resume_one_process (&event_child->head, 0, 0);
	  continue;
	}

      if (debug_threads)
	fprintf (stderr, "Hit a (non-reinsert) breakpoint.\n");

      if (check_breakpoints (stop_pc) != 0)
	{
	  /* We hit one of our own breakpoints.  We mark it as a pending
	     breakpoint, so that check_removed_breakpoints () will do the PC
	     adjustment for us at the appropriate time.  */
	  event_child->pending_is_breakpoint = 1;
	  event_child->pending_stop_pc = stop_pc;

	  /* Now we need to put the breakpoint back.  We continue in the event
	     loop instead of simply replacing the breakpoint right away,
	     in order to not lose signals sent to the thread that hit the
	     breakpoint.  Unfortunately this increases the window where another
	     thread could sneak past the removed breakpoint.  For the current
	     use of server-side breakpoints (thread creation) this is
	     acceptable; but it needs to be considered before this breakpoint
	     mechanism can be used in more general ways.  For some breakpoints
	     it may be necessary to stop all other threads, but that should
	     be avoided where possible.

	     If breakpoint_reinsert_addr is NULL, that means that we can
	     use PTRACE_SINGLESTEP on this platform.  Uninsert the breakpoint,
	     mark it for reinsertion, and single-step.

	     Otherwise, call the target function to figure out where we need
	     our temporary breakpoint, create it, and continue executing this
	     process.  */
	  if (the_low_target.breakpoint_reinsert_addr == NULL)
	    {
	      event_child->bp_reinsert = stop_pc;
	      uninsert_breakpoint (stop_pc);
	      linux_resume_one_process (&event_child->head, 1, 0);
	    }
	  else
	    {
	      reinsert_breakpoint_by_bp
		(stop_pc, (*the_low_target.breakpoint_reinsert_addr) ());
	      linux_resume_one_process (&event_child->head, 0, 0);
	    }

	  continue;
	}

      /* If we were single-stepping, we definitely want to report the
	 SIGTRAP.  The single-step operation has completed, so also
         clear the stepping flag; in general this does not matter, 
	 because the SIGTRAP will be reported to the client, which
	 will give us a new action for this thread, but clear it for
	 consistency anyway.  It's safe to clear the stepping flag
         because the only consumer of get_stop_pc () after this point
	 is check_removed_breakpoints, and pending_is_breakpoint is not
	 set.  It might be wiser to use a step_completed flag instead.  */
      if (event_child->stepping)
	{
	  event_child->stepping = 0;
	  return wstat;
	}

      /* A SIGTRAP that we can't explain.  It may have been a breakpoint.
	 Check if it is a breakpoint, and if so mark the process information
	 accordingly.  This will handle both the necessary fiddling with the
	 PC on decr_pc_after_break targets and suppressing extra threads
	 hitting a breakpoint if two hit it at once and then GDB removes it
	 after the first is reported.  Arguably it would be better to report
	 multiple threads hitting breakpoints simultaneously, but the current
	 remote protocol does not allow this.  */
      if ((*the_low_target.breakpoint_at) (stop_pc))
	{
	  event_child->pending_is_breakpoint = 1;
	  event_child->pending_stop_pc = stop_pc;
	}

      return wstat;
    }

  /* NOTREACHED */
  return 0;
}
示例#16
0
文件: start_up.c 项目: ubante/linux
static void __init check_sysemu(void)
{
	unsigned long regs[MAX_REG_NR];
	int pid, n, status, count=0;

	non_fatal("Checking syscall emulation patch for ptrace...");
	sysemu_supported = 0;
	pid = start_ptraced_child();

	if (ptrace(PTRACE_SYSEMU, pid, 0, 0) < 0)
		goto fail;

	CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
	if (n < 0)
		fatal_perror("check_sysemu : wait failed");
	if (!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGTRAP))
		fatal("check_sysemu : expected SIGTRAP, got status = %d\n",
		      status);

	if (ptrace(PTRACE_GETREGS, pid, 0, regs) < 0)
		fatal_perror("check_sysemu : PTRACE_GETREGS failed");
	if (PT_SYSCALL_NR(regs) != __NR_getpid) {
		non_fatal("check_sysemu got system call number %d, "
			  "expected %d...", PT_SYSCALL_NR(regs), __NR_getpid);
		goto fail;
	}

	n = ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_RET_OFFSET, os_getpid());
	if (n < 0) {
		non_fatal("check_sysemu : failed to modify system call "
			  "return");
		goto fail;
	}

	if (stop_ptraced_child(pid, 0, 0) < 0)
		goto fail_stopped;

	sysemu_supported = 1;
	non_fatal("OK\n");
	set_using_sysemu(!force_sysemu_disabled);

	non_fatal("Checking advanced syscall emulation patch for ptrace...");
	pid = start_ptraced_child();

	if ((ptrace(PTRACE_OLDSETOPTIONS, pid, 0,
		   (void *) PTRACE_O_TRACESYSGOOD) < 0))
		fatal_perror("check_sysemu: PTRACE_OLDSETOPTIONS failed");

	while (1) {
		count++;
		if (ptrace(PTRACE_SYSEMU_SINGLESTEP, pid, 0, 0) < 0)
			goto fail;
		CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
		if (n < 0)
			fatal_perror("check_sysemu: wait failed");

		if (WIFSTOPPED(status) &&
		    (WSTOPSIG(status) == (SIGTRAP|0x80))) {
			if (!count) {
				non_fatal("check_sysemu: SYSEMU_SINGLESTEP "
					  "doesn't singlestep");
				goto fail;
			}
			n = ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_RET_OFFSET,
				   os_getpid());
			if (n < 0)
				fatal_perror("check_sysemu : failed to modify "
					     "system call return");
			break;
		}
		else if (WIFSTOPPED(status) && (WSTOPSIG(status) == SIGTRAP))
			count++;
		else {
			non_fatal("check_sysemu: expected SIGTRAP or "
				  "(SIGTRAP | 0x80), got status = %d\n",
				  status);
			goto fail;
		}
	}
	if (stop_ptraced_child(pid, 0, 0) < 0)
		goto fail_stopped;

	sysemu_supported = 2;
	non_fatal("OK\n");

	if (!force_sysemu_disabled)
		set_using_sysemu(sysemu_supported);
	return;

fail:
	stop_ptraced_child(pid, 1, 0);
fail_stopped:
	non_fatal("missing\n");
}
示例#17
0
static unsigned char
linux_wait (char *status)
{
  int w;
  struct thread_info *child = NULL;

retry:
  /* If we were only supposed to resume one thread, only wait for
     that thread - if it's still alive.  If it died, however - which
     can happen if we're coming from the thread death case below -
     then we need to make sure we restart the other threads.  We could
     pick a thread at random or restart all; restarting all is less
     arbitrary.  */
  if (cont_thread > 0)
    {
      child = (struct thread_info *) find_inferior_id (&all_threads,
						       cont_thread);

      /* No stepping, no signal - unless one is pending already, of course.  */
      if (child == NULL)
	linux_resume (0, 0);
    }

  enable_async_io ();
  w = linux_wait_for_event (child);
  stop_all_processes ();
  disable_async_io ();

  /* If we are waiting for a particular child, and it exited,
     linux_wait_for_event will return its exit status.  Similarly if
     the last child exited.  If this is not the last child, however,
     do not report it as exited until there is a 'thread exited' response
     available in the remote protocol.  Instead, just wait for another event.
     This should be safe, because if the thread crashed we will already
     have reported the termination signal to GDB; that should stop any
     in-progress stepping operations, etc.

     Report the exit status of the last thread to exit.  This matches
     LinuxThreads' behavior.  */

  if (all_threads.head == all_threads.tail)
    {
      if (WIFEXITED (w))
	{
	  fprintf (stderr, "\nChild exited with retcode = %x \n", WEXITSTATUS (w));
	  *status = 'W';
	  clear_inferiors ();
	  return ((unsigned char) WEXITSTATUS (w));
	}
      else if (!WIFSTOPPED (w))
	{
	  fprintf (stderr, "\nChild terminated with signal = %x \n", WTERMSIG (w));
	  clear_inferiors ();
	  *status = 'X';
	  return ((unsigned char) WTERMSIG (w));
	}
    }
  else
    {
      if (!WIFSTOPPED (w))
	goto retry;
    }

  *status = 'T';
  return ((unsigned char) WSTOPSIG (w));
}
示例#18
0
static void summarize (FILE *fp, const char *fmt, char **command, resource_t *resp)
{
    unsigned long r;		/* Elapsed real milliseconds.  */
    unsigned long v;		/* Elapsed virtual (CPU) milliseconds.  */

    if (WIFSTOPPED (resp->waitstatus))
	fprintf (fp, "Command stopped by signal %d\n", WSTOPSIG (resp->waitstatus));
    else if (WIFSIGNALED (resp->waitstatus))
	fprintf (fp, "Command terminated by signal %d\n", WTERMSIG (resp->waitstatus));
    else if (WIFEXITED (resp->waitstatus) && WEXITSTATUS (resp->waitstatus))
	fprintf (fp, "Command exited with non-zero status %d\n", WEXITSTATUS (resp->waitstatus));

    /* Convert all times to milliseconds.  Occasionally, one of these values
       comes out as zero.  Dividing by zero causes problems, so we first
       check the time value.  If it is zero, then we take `evasive action'
       instead of calculating a value.  */

    r = resp->elapsed.tv_sec * 1000 + resp->elapsed.tv_usec / 1000;

    v = resp->ru.ru_utime.tv_sec * 1000 + resp->ru.ru_utime.TV_MSEC +
	resp->ru.ru_stime.tv_sec * 1000 + resp->ru.ru_stime.TV_MSEC;

    while (*fmt)
    {
	switch (*fmt)
	{
	    case '%':
		switch (*++fmt)
		{
		    case '%':		/* Literal '%'.  */
			putc ('%', fp);
			break;
		    case 'C':		/* The command that got timed.  */
			fprintargv (fp, command, " ");
			break;
		    case 'D':		/* Average unshared data size.  */
			fprintf (fp, "%lu",
				MSEC_TO_TICKS (v) == 0 ? 0 :
				ptok ((UL) resp->ru.ru_idrss) / MSEC_TO_TICKS (v) +
				ptok ((UL) resp->ru.ru_isrss) / MSEC_TO_TICKS (v));
			break;
		    case 'E':		/* Elapsed real (wall clock) time.  */
			if (resp->elapsed.tv_sec >= 3600)	/* One hour -> h:m:s.  */
			    fprintf (fp, "%ldh %ldm %02lds",
				    resp->elapsed.tv_sec / 3600,
				    (resp->elapsed.tv_sec % 3600) / 60,
				    resp->elapsed.tv_sec % 60);
			else
			    fprintf (fp, "%ldm %ld.%02lds",	/* -> m:s.  */
				    resp->elapsed.tv_sec / 60,
				    resp->elapsed.tv_sec % 60,
				    resp->elapsed.tv_usec / 10000);
			break;
		    case 'F':		/* Major page faults.  */
			fprintf (fp, "%ld", resp->ru.ru_majflt);
			break;
		    case 'I':		/* Inputs.  */
			fprintf (fp, "%ld", resp->ru.ru_inblock);
			break;
		    case 'K':		/* Average mem usage == data+stack+text.  */
			fprintf (fp, "%lu",
				MSEC_TO_TICKS (v) == 0 ? 0 :
				ptok ((UL) resp->ru.ru_idrss) / MSEC_TO_TICKS (v) +
				ptok ((UL) resp->ru.ru_isrss) / MSEC_TO_TICKS (v) +
				ptok ((UL) resp->ru.ru_ixrss) / MSEC_TO_TICKS (v));
			break;
		    case 'M':		/* Maximum resident set size.  */
			fprintf (fp, "%lu", ptok ((UL) resp->ru.ru_maxrss));
			break;
		    case 'O':		/* Outputs.  */
			fprintf (fp, "%ld", resp->ru.ru_oublock);
			break;
		    case 'P':		/* Percent of CPU this job got.  */
			/* % cpu is (total cpu time)/(elapsed time).  */
			if (r > 0)
			    fprintf (fp, "%lu%%", (v * 100 / r));
			else
			    fprintf (fp, "?%%");
			break;
		    case 'R':		/* Minor page faults (reclaims).  */
			fprintf (fp, "%ld", resp->ru.ru_minflt);
			break;
		    case 'S':		/* System time.  */
			fprintf (fp, "%ld.%02ld",
				resp->ru.ru_stime.tv_sec,
				resp->ru.ru_stime.TV_MSEC / 10);
			break;
		    case 'T':		/* System time.  */
			if (resp->ru.ru_stime.tv_sec >= 3600)	/* One hour -> h:m:s.  */
			    fprintf (fp, "%ldh %ldm %02lds",
				    resp->ru.ru_stime.tv_sec / 3600,
				    (resp->ru.ru_stime.tv_sec % 3600) / 60,
				    resp->ru.ru_stime.tv_sec % 60);
			else
			    fprintf (fp, "%ldm %ld.%02lds",	/* -> m:s.  */
				    resp->ru.ru_stime.tv_sec / 60,
				    resp->ru.ru_stime.tv_sec % 60,
				    resp->ru.ru_stime.tv_usec / 10000);
			break;
		    case 'U':		/* User time.  */
			fprintf (fp, "%ld.%02ld",
				resp->ru.ru_utime.tv_sec,
				resp->ru.ru_utime.TV_MSEC / 10);
			break;
		    case 'u':		/* User time.  */
			if (resp->ru.ru_utime.tv_sec >= 3600)	/* One hour -> h:m:s.  */
			    fprintf (fp, "%ldh %ldm %02lds",
				    resp->ru.ru_utime.tv_sec / 3600,
				    (resp->ru.ru_utime.tv_sec % 3600) / 60,
				    resp->ru.ru_utime.tv_sec % 60);
			else
			    fprintf (fp, "%ldm %ld.%02lds",	/* -> m:s.  */
				    resp->ru.ru_utime.tv_sec / 60,
				    resp->ru.ru_utime.tv_sec % 60,
				    resp->ru.ru_utime.tv_usec / 10000);
			break;
		    case 'W':		/* Times swapped out.  */
			fprintf (fp, "%ld", resp->ru.ru_nswap);
			break;
		    case 'X':		/* Average shared text size.  */
			fprintf (fp, "%lu",
				MSEC_TO_TICKS (v) == 0 ? 0 :
				ptok ((UL) resp->ru.ru_ixrss) / MSEC_TO_TICKS (v));
			break;
		    case 'Z':		/* Page size.  */
			fprintf (fp, "%d", getpagesize ());
			break;
		    case 'c':		/* Involuntary context switches.  */
			fprintf (fp, "%ld", resp->ru.ru_nivcsw);
			break;
		    case 'e':		/* Elapsed real time in seconds.  */
			fprintf (fp, "%ld.%02ld",
				resp->elapsed.tv_sec,
				resp->elapsed.tv_usec / 10000);
			break;
		    case 'k':		/* Signals delivered.  */
			fprintf (fp, "%ld", resp->ru.ru_nsignals);
			break;
		    case 'p':		/* Average stack segment.  */
			fprintf (fp, "%lu",
				MSEC_TO_TICKS (v) == 0 ? 0 :
				ptok ((UL) resp->ru.ru_isrss) / MSEC_TO_TICKS (v));
			break;
		    case 'r':		/* Incoming socket messages received.  */
			fprintf (fp, "%ld", resp->ru.ru_msgrcv);
			break;
		    case 's':		/* Outgoing socket messages sent.  */
			fprintf (fp, "%ld", resp->ru.ru_msgsnd);
			break;
		    case 't':		/* Average resident set size.  */
			fprintf (fp, "%lu",
				MSEC_TO_TICKS (v) == 0 ? 0 :
				ptok ((UL) resp->ru.ru_idrss) / MSEC_TO_TICKS (v));
			break;
		    case 'w':		/* Voluntary context switches.  */
			fprintf (fp, "%ld", resp->ru.ru_nvcsw);
			break;
		    case 'x':		/* Exit status.  */
			fprintf (fp, "%d", WEXITSTATUS (resp->waitstatus));
			break;
		    case '\0':
			putc ('?', fp);
			return;
		    default:
			putc ('?', fp);
			putc (*fmt, fp);
		}
		++fmt;
		break;

	    case '\\':		/* Format escape.  */
		switch (*++fmt)
		{
		    case 't':
			putc ('\t', fp);
			break;
		    case 'n':
			putc ('\n', fp);
			break;
		    case '\\':
			putc ('\\', fp);
			break;
		    default:
			putc ('?', fp);
			putc ('\\', fp);
			putc (*fmt, fp);
		}
		++fmt;
		break;

	    default:
		putc (*fmt++, fp);
	}

	if (ferror (fp))
	    bb_error_msg_and_die("write error");
    }
    putc ('\n', fp);

    if (ferror (fp))
	bb_error_msg_and_die("write error");
}
bool run_test(int cpu)
{
	int status;
	pid_t pid = fork();
	pid_t wpid;

	if (pid < 0) {
		ksft_print_msg("fork() failed: %s\n", strerror(errno));
		return false;
	}
	if (pid == 0)
		child(cpu);

	wpid = waitpid(pid, &status, __WALL);
	if (wpid != pid) {
		ksft_print_msg("waitpid() failed: %s\n", strerror(errno));
		return false;
	}
	if (!WIFSTOPPED(status)) {
		ksft_print_msg("child did not stop: %s\n", strerror(errno));
		return false;
	}
	if (WSTOPSIG(status) != SIGSTOP) {
		ksft_print_msg("child did not stop with SIGSTOP: %s\n",
			strerror(errno));
		return false;
	}

	if (ptrace(PTRACE_SINGLESTEP, pid, NULL, NULL) < 0) {
		if (errno == EIO) {
			ksft_exit_skip(
				"ptrace(PTRACE_SINGLESTEP) not supported on this architecture: %s\n",
				strerror(errno));
		}
		ksft_print_msg("ptrace(PTRACE_SINGLESTEP) failed: %s\n",
			strerror(errno));
		return false;
	}

	wpid = waitpid(pid, &status, __WALL);
	if (wpid != pid) {
		ksft_print_msg("waitpid() failed: $s\n", strerror(errno));
		return false;
	}
	if (WIFEXITED(status)) {
		ksft_print_msg("child did not single-step: %s\n",
			strerror(errno));
		return false;
	}
	if (!WIFSTOPPED(status)) {
		ksft_print_msg("child did not stop: %s\n", strerror(errno));
		return false;
	}
	if (WSTOPSIG(status) != SIGTRAP) {
		ksft_print_msg("child did not stop with SIGTRAP: %s\n",
			strerror(errno));
		return false;
	}

	if (ptrace(PTRACE_CONT, pid, NULL, NULL) < 0) {
		ksft_print_msg("ptrace(PTRACE_CONT) failed: %s\n",
			strerror(errno));
		return false;
	}

	wpid = waitpid(pid, &status, __WALL);
	if (wpid != pid) {
		ksft_print_msg("waitpid() failed: %s\n", strerror(errno));
		return false;
	}
	if (!WIFEXITED(status)) {
		ksft_print_msg("child did not exit after PTRACE_CONT: %s\n",
			strerror(errno));
		return false;
	}

	return true;
}
示例#20
0
/**
 * Signal handler for the server.
 */
void handle_sigs(void)
{
	pid_t  chld;
	int    chld_status;
	int    i;
	int    do_exit;

	switch(sig_flag){
		case 0: break; /* do nothing*/
		case SIGPIPE:
				/* SIGPIPE might be rarely received on use of
				   exec module; simply ignore it
				 */
				LM_WARN("SIGPIPE received and ignored\n");
				break;
		case SIGINT:
		case SIGTERM:
			/* we end the program in all these cases */
			if (sig_flag==SIGINT)
				LM_DBG("INT received, program terminates\n");
			else
				LM_DBG("SIGTERM received, program terminates\n");
				
			/* first of all, kill the children also */
			kill_all_children(SIGTERM);
			if (signal(SIGALRM, sig_alarm_kill) == SIG_ERR ) {
				LM_ERR("could not install SIGALARM handler\n");
				/* continue, the process will die anyway if no
				 * alarm is installed which is exactly what we want */
			}
			alarm(OPENSER_SHUTDOWN_TIME); /* 1 minute close timeout */

			while(wait(0) > 0); /* Wait for all the children to terminate */
			signal(SIGALRM, sig_alarm_abort);

			cleanup(1); /* cleanup & show status*/
			alarm(0);
			signal(SIGALRM, SIG_IGN);
			dprint("Thank you for flying " NAME "\n");
			exit(0);
			break;
			
		case SIGUSR1:
#ifdef PKG_MALLOC
			LOG(memlog, "Memory status (pkg):\n");
			pkg_status();
#endif
#ifdef SHM_MEM
			LOG(memlog, "Memory status (shm):\n");
			shm_status();
#endif
			break;
			
		case SIGCHLD:
			do_exit = 0;
			while ((chld=waitpid( -1, &chld_status, WNOHANG ))>0) {
				/* is it a process we know about? */
				for( i=0 ; i<counted_processes ; i++ )
					if (pt[i].pid==chld) break;
				if (i==counted_processes) {
					LM_DBG("unkown child process %d ended. Ignoring\n",chld);
					continue;
				}
				do_exit = 1;
				/* process the signal */
				if (WIFEXITED(chld_status)) 
					LM_INFO("child process %d exited normally,"
							" status=%d\n", chld, 
							WEXITSTATUS(chld_status));
				else if (WIFSIGNALED(chld_status)) {
					LM_INFO("child process %d exited by a signal"
							" %d\n", chld, WTERMSIG(chld_status));
#ifdef WCOREDUMP
					LM_INFO("core was %sgenerated\n",
							 WCOREDUMP(chld_status) ?  "" : "not " );
#endif
				}else if (WIFSTOPPED(chld_status)) 
					LM_INFO("child process %d stopped by a"
								" signal %d\n", chld,
								 WSTOPSIG(chld_status));
			}
			if (!do_exit)
				break;
			LM_INFO("terminating due to SIGCHLD\n");
			/* exit */
			kill_all_children(SIGTERM);
			if (signal(SIGALRM, sig_alarm_kill) == SIG_ERR ) {
				LM_ERR("could not install SIGALARM handler\n");
				/* continue, the process will die anyway if no
				 * alarm is installed which is exactly what we want */
			}
			alarm(OPENSER_SHUTDOWN_TIME); /* 1 minute close timeout */
			while(wait(0) > 0); /* wait for all the children to terminate*/
			signal(SIGALRM, sig_alarm_abort);
			cleanup(1); /* cleanup & show status*/
			alarm(0);
			signal(SIGALRM, SIG_IGN);
			LM_DBG("terminating due to SIGCHLD\n");
			exit(0);
			break;
		
		case SIGHUP: /* ignoring it*/
			LM_DBG("SIGHUP received, ignoring it\n");
			break;
		default:
			LM_CRIT("unhandled signal %d\n", sig_flag);
	}
	sig_flag=0;
}
示例#21
0
int main(int argc, char **argv) {

	int i;
	long page_size=getpagesize();
	double error;

	long long start_before,stop_after;

	void *addr[MAX_EVENTS],*addr2[MAX_EVENTS];

	struct perf_event_attr pe;

	int fd[MAX_EVENTS],fd2[MAX_EVENTS],ret1,ret2;
	int status;

	unsigned long long values[MAX_EVENTS],enabled[MAX_EVENTS],running[MAX_EVENTS];
	unsigned long long values2[MAX_EVENTS],enabled2[MAX_EVENTS],running2[MAX_EVENTS];

	int count=2;

	pid_t pid,pid2;

	quiet=test_quiet();

	if (!quiet) {
		printf("This test checks if rdpmc multi-attach works.\n\n");
	}

	/* See if we support rdpmc access */
	if (!detect_rdpmc(quiet)) {
		test_skip(test_string);
	}

	/*********************************/
	/* start and pause two children  */
	/*********************************/

	/* fork a child */
	pid = fork();
	if ( pid < 0 ) {
		fprintf(stderr,"Failed fork\n");
		test_fail(test_string);
	}
	else if (pid==0) {
		/* in child */
		exit(wait_for_attach_and_loop(1));
	}

	if ( ptrace( PTRACE_ATTACH, pid, NULL, NULL ) == -1 ) {
		fprintf(stderr,"Error attaching to %d\n",pid);
		return -1;
	}
	if ( waitpid( pid, &status, 0 ) == -1 ) {
		fprintf(stderr,"Error waitpid %d\n",pid);
		return -1;
	}
	if ( WIFSTOPPED( status ) == 0 ) {
		fprintf(stderr,"WIFSTOPPED didn't happen %d\n",pid);
		test_fail(test_string);
	}



	/* fork a second child */
	pid2 = fork();
	if ( pid2 < 0 ) {
		fprintf(stderr,"Failed fork\n");
		test_fail(test_string);
	}
	else if (pid2==0) {
		/* in child */
		exit(wait_for_attach_and_loop(2));
	}

	if ( ptrace( PTRACE_ATTACH, pid2, NULL, NULL ) == -1 ) {
		fprintf(stderr,"Error attaching to %d\n",pid2);
		return -1;
	}
	if ( waitpid( pid2, &status, 0 ) == -1 ) {
		fprintf(stderr,"Error waitpid %d\n",pid2);
		return -1;
	}
	if ( WIFSTOPPED( status ) == 0 ) {
		fprintf(stderr,"WIFSTOPPED didn't happen %d\n",pid2);
		test_fail(test_string);
	}



	/*****************************/
	/* TEST START/WORK/READ/STOP */
	/*****************************/

	/* Open event, pid1  */
	memset(&pe,0,sizeof(struct perf_event_attr));

	pe.type=PERF_TYPE_HARDWARE;
	pe.size=sizeof(struct perf_event_attr);

	fd[0]=-1;

	for(i=0;i<count;i++) {

		if (i==0) {
			pe.config=PERF_COUNT_HW_INSTRUCTIONS;
			pe.disabled=1;
			pe.pinned=1;
		}
		else {
			pe.config=PERF_COUNT_HW_CPU_CYCLES;
			pe.disabled=0;
			pe.pinned=0;
		}

		fd[i]=perf_event_open(&pe,pid,-1,fd[0],0);
		if (fd[i]<0) {
			fprintf(stderr,"Error opening event %d\n",i);
			test_fail(test_string);
		}

		/* mmap() event */
		addr[i]=mmap(NULL,page_size, PROT_READ, MAP_SHARED,fd[i],0);
		if (addr[i] == MAP_FAILED) {
			fprintf(stderr,"Error mmap()ing event %d!\n",i);
			test_fail(test_string);
		}
	}




	/* Open event, pid2  */
	memset(&pe,0,sizeof(struct perf_event_attr));

	pe.type=PERF_TYPE_HARDWARE;
	pe.size=sizeof(struct perf_event_attr);

	fd2[0]=-1;

	for(i=0;i<count;i++) {

		if (i==0) {
			pe.config=PERF_COUNT_HW_INSTRUCTIONS;
			pe.disabled=1;
			pe.pinned=1;
		}
		else {
			pe.config=PERF_COUNT_HW_CPU_CYCLES;
			pe.disabled=0;
			pe.pinned=0;
		}

		fd2[i]=perf_event_open(&pe,pid2,-1,fd2[0],0);
		if (fd2[i]<0) {
			fprintf(stderr,"Error opening event %d\n",i);
			test_fail(test_string);
		}

		/* mmap() event */
		addr2[i]=mmap(NULL,page_size, PROT_READ, MAP_SHARED,fd2[i],0);
		if (addr2[i] == MAP_FAILED) {
			fprintf(stderr,"Error mmap()ing event %d!\n",i);
			test_fail(test_string);
		}
	}


	/* start */
	start_before=rdtsc();
	ret1=ioctl(fd[0], PERF_EVENT_IOC_ENABLE,0);

	/* start up pid */
	if ( ptrace( PTRACE_CONT, pid, NULL, NULL ) == -1 ) {
		fprintf(stderr,"Couldn't continue %d\n",pid);
		return -1;
	}
	if ( waitpid( pid, &status, 0 ) == -1 ) {
		fprintf(stderr,"Couldn't waitpid() %d\n",pid );
		return -1;
	}
	if ( WIFSTOPPED( status ) == 0 ) {
		test_fail(test_string);
	}
	if ( WSTOPSIG( status ) != SIGSTOP ) {
		test_fail(test_string);
	}


	ret1=ioctl(fd2[0], PERF_EVENT_IOC_ENABLE,0);

	/* start up pid2 */
	if ( ptrace( PTRACE_CONT, pid2, NULL, NULL ) == -1 ) {
		fprintf(stderr,"Couldn't continue %d\n",pid2);
		return -1;
	}
	if ( waitpid( pid2, &status, 0 ) == -1 ) {
		fprintf(stderr,"Couldn't waitpid() %d\n",pid2 );
		return -1;
	}
	if ( WIFSTOPPED( status ) == 0 ) {
		test_fail(test_string);
	}
	if ( WSTOPSIG( status ) != SIGSTOP ) {
		test_fail(test_string);
	}



	/* Wait for the SIGSTOP. */
	if ( ptrace( PTRACE_CONT, pid, NULL, NULL ) == -1 ) {
              fprintf(stderr, "sigstop fail\n" );
              return -1;
	}

	if ( waitpid( pid, &status, 0 ) == -1 ) {
		fprintf(stderr, "waitpid() pid\n" );
		return -1;
	}
	if ( WIFSTOPPED( status ) == 0 ) {
              test_fail(test_string);
	}
	if ( WSTOPSIG( status ) != SIGSTOP ) {
              test_fail(test_string);
	}



	/* Wait for the SIGSTOP. */
	if ( ptrace( PTRACE_CONT, pid2, NULL, NULL ) == -1 ) {
              fprintf(stderr, "sigstop fail\n" );
              return -1;
	}

	if ( waitpid( pid2, &status, 0 ) == -1 ) {
		fprintf(stderr, "waitpid() pid\n" );
		return -1;
	}
	if ( WIFSTOPPED( status ) == 0 ) {
              test_fail(test_string);
	}
	if ( WSTOPSIG( status ) != SIGSTOP ) {
              test_fail(test_string);
	}


	/* read */
	for(i=0;i<count;i++) {
		values[i] = mmap_read_self(addr[i], &enabled[i], &running[i]);
	}

	/* stop */
	ret2=ioctl(fd[0], PERF_EVENT_IOC_DISABLE,0);
	ret2=ioctl(fd2[0], PERF_EVENT_IOC_DISABLE,0);

	for(i=0;i<count;i++) {
		values2[i] = mmap_read_self(addr2[i], &enabled2[i], &running2[i]);
	}

	stop_after=rdtsc();

	if (ret1<0) {
		fprintf(stderr,"Error starting!\n");
		test_fail(test_string);
	}

	if (ret2<0) {
		fprintf(stderr,"Error stopping!\n");
		test_fail(test_string);
	}

	if (values[0]<0) {
		if (!quiet) printf("rdpmc support not available.\n");
		test_yellow_no(test_string);
	}

	for(i=0;i<count;i++) {
		close(fd[i]);
		close(fd2[i]);
		munmap(addr[i],page_size);
		munmap(addr2[i],page_size);
	}

	if (!quiet) {
		printf("Trying attach: %lld cycles\n",
			stop_after-start_before);
		for(i=0;i<count;i++) {
			if (values[i]==-1) {
				printf("\t* RDPMC 1 Event %x -- rdpmc not supported\n",i);
			}
			else {
				printf("\t* RDPMC 1 Event %x -- count: %lld enabled %lld running: %lld\n",
					i,values[i],enabled[i],running[i]);
			}
		}
		for(i=0;i<count;i++) {
			if (values2[i]==-1) {
				printf("\t* RDPMC 2 Event %x -- rdpmc not supported\n",i);
			}
			else {
				printf("\t* RDPMC 2 Event %x -- count: %lld enabled %lld running: %lld\n",
					i,values2[i],enabled2[i],running2[i]);
			}

		}
	}

	if (!quiet) printf("\n");

	if ((values[0]!=-1) || (values2[0]!=-1)) {

		error=display_error(values[0],
					values[0],
					values[0],
					1000000ULL,quiet);

		if ((error>10.0) || ( error<-10.0)) {
			if (!quiet) printf("Error out of range!\n");
			test_fail(test_string);
		}

		error=display_error(values2[0],
					values2[0],
					values2[0],
					2000000ULL,quiet);

		if ((error>10.0) || ( error<-10.0)) {
			if (!quiet) printf("Error out of range!\n");
			test_fail(test_string);
		}

		if (!quiet) {
			printf("Should not have worked\n");
		}
		test_fail(test_string);
	}


	for(i=0;i<count;i++) {
		close(fd[i]);
		munmap(addr[i],page_size);
	}

	test_pass(test_string);

	return 0;
}
示例#22
0
/* some of this code is based on /usr/bin/time source code */
void
print_stats(struct timeval *start, struct timeval *end,
            struct rusage *ru, int status)
{
    unsigned long r;            /* Elapsed real milliseconds.  */
    unsigned long v;            /* Elapsed virtual (CPU) milliseconds.  */
    end->tv_sec -= start->tv_sec;
    if (end->tv_usec < start->tv_usec) {
        /* Manually carry a one from the seconds field.  */
        end->tv_usec += 1000000;
        --end->tv_sec;
    }
    end->tv_usec -= start->tv_usec;

    if (WIFSTOPPED (status)) {
        fprintf(FP, "Command stopped by signal %d\n",
                WSTOPSIG (status));
    } else if (WIFSIGNALED (status)) {
        fprintf(FP, "Command terminated by signal %d\n",
                WTERMSIG (status));
    } else if (WIFEXITED (status) && WEXITSTATUS (status)) {
        fprintf(FP, "Command exited with non-zero status %d\n",
                WEXITSTATUS (status));
    }

    /* Convert all times to milliseconds.  Occasionally, one of these values
       comes out as zero.  Dividing by zero causes problems, so we first
       check the time value.  If it is zero, then we take `evasive action'
       instead of calculating a value.  */
    
    r = end->tv_sec * 1000 + end->tv_usec / 1000;
    
    v = ru->ru_utime.tv_sec * 1000 + ru->ru_utime.TV_MSEC +
        ru->ru_stime.tv_sec * 1000 + ru->ru_stime.TV_MSEC;

    /* Elapsed real (wall clock) time.  */
    if (end->tv_sec >= 3600) {  /* One hour -> h:m:s.  */
        fprintf(FP, "%ld:%02ld:%02ldelapsed ",
                 end->tv_sec / 3600,
                 (end->tv_sec % 3600) / 60,
                 end->tv_sec % 60);
    } else {
        fprintf(FP, "%ld:%02ld.%02ldelapsed ",  /* -> m:s.  */
                 end->tv_sec / 60,
                 end->tv_sec % 60,
                 end->tv_usec / 10000);
    }
    /* % cpu is (total cpu time)/(elapsed time).  */
    if (r > 0)
        fprintf(FP, "%lu%%CPU ", (v * 100 / r));
    else
        fprintf(FP, "?%%CPU ");
    fprintf(FP, "%ld.%02lduser ",
            ru->ru_utime.tv_sec, ru->ru_utime.TV_MSEC / 10);
    fprintf(FP, "%ld.%02ldsystem ",
            ru->ru_stime.tv_sec, ru->ru_stime.TV_MSEC / 10);
    fprintf(FP, "(%ldmajor+%ldminor)pagefaults %ldswaps\n",
            ru->ru_majflt,/* Major page faults.  */
            ru->ru_minflt,/* Minor page faults.  */
            ru->ru_nswap); /* times swapped out */
    fprintf(FP, "(%lu tot, %lu RSS, %lu data, %lu stk, %lu exe, %lu lib)k\n",
            vmstats.VmSize, vmstats.VmRSS, vmstats.VmData,
            vmstats.VmStk, vmstats.VmExe, vmstats.VmLib);

#if VERBOSE
    fprintf(FP, "Memory usage:\n");
    fprintf(FP, "\tVmSize: %d kB\n", vmstats.VmSize);
    fprintf(FP, "\tVmLck: %d kB\n", vmstats.VmLck);
    fprintf(FP, "\tVmRSS: %d kB\n", vmstats.VmRSS);
    fprintf(FP, "\tVmData: %d kB\n", vmstats.VmData);
    fprintf(FP, "\tVmStk: %d kB\n", vmstats.VmStk);
    fprintf(FP, "\tVmExe: %d kB\n", vmstats.VmExe);
    fprintf(FP, "\tVmLib: %d kB\n", vmstats.VmLib);
#endif
}
示例#23
0
int64_t HHVM_FUNCTION(pcntl_wstopsig,
                      int status) {
  return WSTOPSIG(status);
}
示例#24
0
static void
ppp_watch_cb (GPid pid, gint status, gpointer user_data)
{
	NMPPPManager *manager = NM_PPP_MANAGER (user_data);
	NMPPPManagerPrivate *priv = NM_PPP_MANAGER_GET_PRIVATE (manager);
	guint err;

	g_assert (pid == priv->pid);

	if (WIFEXITED (status)) {
		err = WEXITSTATUS (status);
		if (err != 0)
			ppp_exit_code (err, priv->pid);
	} else if (WIFSTOPPED (status)) {
		nm_log_info (LOGD_PPP, "pppd pid %d stopped unexpectedly with signal %d", priv->pid, WSTOPSIG (status));
	} else if (WIFSIGNALED (status)) {
		nm_log_info (LOGD_PPP, "pppd pid %d died with signal %d", priv->pid, WTERMSIG (status));
	} else
		nm_log_info (LOGD_PPP, "pppd pid %d died from an unknown cause", priv->pid);

	nm_log_dbg (LOGD_PPP, "pppd pid %d cleaned up", priv->pid);
	priv->pid = 0;
	g_signal_emit (manager, signals[STATE_CHANGED], 0, NM_PPP_STATUS_DEAD);
}
示例#25
0
int stop_crfs(const char *crfs_mnt, int crfs_pid)
{
    extern int mt_id;
    int rv;
    char cmd[MAX_CMD_LEN];

    if (strlen(crfs_mnt) != 0) {
        snprintf(cmd, MAX_CMD_LEN, "fusermount -u %s > /dev/null 2>&1", crfs_mnt);
        PRINT_DEBUG(DEBUG_Fork_verbose, "Stop CRFS: %s\n", cmd);
        rv = system(cmd);
        if (rv == -1) {
            PRINT_DEBUG(DEBUG_Fork_verbose, "system call to fusermount failed\n");
        } else {
            PRINT_DEBUG(DEBUG_Fork_verbose, "system call to fusermount returned %d\n", rv);
            if (WIFEXITED(rv)) {
                PRINT_DEBUG(DEBUG_Fork_verbose, "fusermount exited with status %d\n", WEXITSTATUS(rv));
            } else if (WIFSIGNALED(rv)) {
                PRINT_DEBUG(DEBUG_Fork_verbose, "fusermount terminated with signal %d\n", WTERMSIG(rv));
            } else if (WIFSTOPPED(rv)) {
                PRINT_DEBUG(DEBUG_Fork_verbose, "fusermount stopped with signal %d\n", WSTOPSIG(rv));
            } else if (WIFCONTINUED(rv)) {
                PRINT_DEBUG(DEBUG_Fork_verbose, "fusermount continued\n");
            }
        }
    }
    if (crfs_pid > 0) {
        rv = kill(crfs_pid, SIGTERM);
        PRINT_DEBUG(DEBUG_Fork_verbose, "kill with SIGTERM ret=%d\n", rv);
        usleep(100000);         // wait for CRFS to terminate
        rv = kill(crfs_pid, SIGINT);
        PRINT_DEBUG(DEBUG_Fork_verbose, "kill with SIGINT ret=%d\n", rv);
    }
    //snprintf(path, MAX_PATH_LEN, "/tmp/cr-%s/", crfs_sessionid);
    //rv = rmdir(path);
    return 0;
}
示例#26
0
unsigned ReqProg_load( void )
{
    char                        **args;
    char                        *parms;
    char                        *parm_start;
    int                         i;
    char                        exe_name[PATH_MAX];
    char                        *name;
    pid_t                       save_pgrp;
    prog_load_req               *acc;
    prog_load_ret               *ret;
    unsigned                    len;
    int                         status;

    acc = GetInPtr( 0 );
    ret = GetOutPtr( 0 );

    last_sig = -1;
    have_rdebug = FALSE;
    dbg_dyn = NULL;
    at_end = FALSE;
    parms = (char *)GetInPtr( sizeof( *acc ) );
    parm_start = parms;
    len = GetTotalSize() - sizeof( *acc );
    if( acc->true_argv ) {
        i = 1;
        for( ;; ) {
            if( len == 0 ) break;
            if( *parms == '\0' ) {
                i++;
            }
            ++parms;
            --len;
        }
        args = alloca( i * sizeof( *args ) );
        parms = parm_start;
        len = GetTotalSize() - sizeof( *acc );
        i = 1;
        for( ;; ) {
            if( len == 0 ) break;
            if( *parms == '\0' ) {
                args[i++] = parms + 1;
            }
            ++parms;
            --len;
        }
        args[i - 1] = NULL;
    } else {
        while( *parms != '\0' ) {
            ++parms;
            --len;
        }
        ++parms;
        --len;
        i = SplitParms( parms, NULL, len );
        args = alloca( (i + 2)  * sizeof( *args ) );
        args[SplitParms( parms, &args[1], len ) + 1] = NULL;
    }
    args[0] = parm_start;
    attached = TRUE;
    pid = RunningProc( args[0], &name );
    if( pid == 0 || ptrace( PTRACE_ATTACH, pid, NULL, NULL ) == -1 ) {
        attached = FALSE;
        args[0] = name;
        if( FindFilePath( TRUE, args[0], exe_name ) == 0 ) {
            exe_name[0] = '\0';
        }
        save_pgrp = getpgrp();
        setpgid( 0, OrigPGrp );
        pid = fork();
        if( pid == -1 )
            return( 0 );
        if( pid == 0 ) {
            if( ptrace( PTRACE_TRACEME, 0, NULL, NULL ) < 0 ) {
                exit( 1 );
            }
            execve( exe_name, (const char **)args, (const char **)dbg_environ );
            exit( 1 ); /* failsafe */
        }
        setpgid( 0, save_pgrp );
    } else if( pid ) {
        GetExeNameFromPid( pid, exe_name, PATH_MAX );
    }
    ret->flags = 0;
    ret->mod_handle = 0;
    if( (pid != -1) && (pid != 0) ) {
        int status;

        ret->task_id = pid;
        ret->flags |= LD_FLAG_IS_PROT | LD_FLAG_IS_32;
        /* wait until it hits _start (upon execve) or
           gives us a SIGSTOP (if attached) */
        if( waitpid( pid, &status, 0 ) < 0 )
            goto fail;
        if( !WIFSTOPPED( status ) )
            goto fail;
        if( attached ) {
            ret->flags |= LD_FLAG_IS_STARTED;
            if( WSTOPSIG( status ) != SIGSTOP )
                goto fail;
        } else {
            if( WSTOPSIG( status ) != SIGTRAP )
                goto fail;
        }

#if defined( MD_x86 )
        if( !GetFlatSegs( &flatCS, &flatDS ) )
            goto fail;
#endif

        dbg_dyn = GetDebuggeeDynSection( exe_name );
        AddProcess();
        errno = 0;
    }
    ret->err = errno;
    if( ret->err != 0 ) {
        pid = 0;
    }
    CONV_LE_32( ret->err );
    CONV_LE_32( ret->task_id );
    CONV_LE_32( ret->mod_handle );
    return( sizeof( *ret ) );
fail:
    if( pid != 0 && pid != -1 ) {
        if( attached ) {
            ptrace( PTRACE_DETACH, pid, NULL, NULL );
            attached = FALSE;
        } else {
            ptrace( PTRACE_KILL, pid, NULL, NULL );
            waitpid( pid, &status, 0 );
        }
    }
    pid = 0;
    CONV_LE_32( ret->err );
    CONV_LE_32( ret->task_id );
    CONV_LE_32( ret->mod_handle );
    return( 0 );
}
示例#27
0
static bool client_exec_script(struct master_service_connection *conn)
{
	const char *const *args;
	string_t *input;
	void *buf;
	size_t prev_size, scanpos;
	bool header_complete = FALSE;
	ssize_t ret;
	int status;
	pid_t pid;

	net_set_nonblock(conn->fd, FALSE);
	input = buffer_create_dynamic(pool_datastack_create(), IO_BLOCK_SIZE);

	/* Input contains:

	   VERSION .. <lf>
	   [alarm=<secs> <lf>]
	   "noreply" | "-" (or anything really) <lf>

	   arg 1 <lf>
	   arg 2 <lf>
	   ...
	   <lf>
	   DATA

	   This is quite a horrible protocol. If alarm is specified, it MUST be
	   before "noreply". If "noreply" isn't given, something other string
	   (typically "-") must be given which is eaten away.
	*/		
	alarm(SCRIPT_READ_TIMEOUT_SECS);
	scanpos = 1;
	while (!header_complete) {
		const unsigned char *pos, *end;

		prev_size = input->used;
		buf = buffer_append_space_unsafe(input, IO_BLOCK_SIZE);

		/* peek in socket input buffer */
		ret = recv(conn->fd, buf, IO_BLOCK_SIZE, MSG_PEEK);
		if (ret <= 0) {
			buffer_set_used_size(input, prev_size);
			if (strchr(str_c(input), '\n') != NULL)
				script_verify_version(t_strcut(str_c(input), '\n'));

			if (ret < 0)
				i_fatal("recv(MSG_PEEK) failed: %m");

			i_fatal("recv(MSG_PEEK) failed: disconnected");
		}

		/* scan for final \n\n */
		pos = CONST_PTR_OFFSET(input->data, scanpos);
		end = CONST_PTR_OFFSET(input->data, prev_size + ret);
		for (; pos < end; pos++) {
			if (pos[-1] == '\n' && pos[0] == '\n') {
				header_complete = TRUE;
				pos++;
				break;
			}
		}
		scanpos = pos - (const unsigned char *)input->data;

		/* read data for real (up to and including \n\n) */
		ret = recv(conn->fd, buf, scanpos-prev_size, 0);
		if (prev_size+ret != scanpos) {
			if (ret < 0)
				i_fatal("recv() failed: %m");
			if (ret == 0)
				i_fatal("recv() failed: disconnected");
			i_fatal("recv() failed: size of definitive recv() differs from peek");
		}
		buffer_set_used_size(input, scanpos);
	}
	alarm(0);

	/* drop the last two LFs */
	buffer_set_used_size(input, scanpos-2);

	args = t_strsplit(str_c(input), "\n");
	script_verify_version(*args); args++;
	if (*args != NULL) {
		if (strncmp(*args, "alarm=", 6) == 0) {
			unsigned int seconds;
			if (str_to_uint(*args + 6, &seconds) < 0)
				i_fatal("invalid alarm option");
			alarm(seconds);
			args++;
		}
		if (strcmp(*args, "noreply") == 0) {
			/* no need to fork and check exit status */
			exec_child(conn, args + 1);
			i_unreached();
		}
		if (**args == '\0')
			i_fatal("empty options");
		args++;
	}

	if ((pid = fork()) == (pid_t)-1) {
		i_error("fork() failed: %m");
		return FALSE;
	}

	if (pid == 0) {
		/* child */
		exec_child(conn, args);
		i_unreached();
	}

	/* parent */

	/* check script exit status */
	if (waitpid(pid, &status, 0) < 0) {
		i_error("waitpid() failed: %m");
		return FALSE;
	} else if (WIFEXITED(status)) {
		ret = WEXITSTATUS(status);
		if (ret != 0) {
			i_error("Script terminated abnormally, exit status %d", (int)ret);
			return FALSE;
		}
	} else if (WIFSIGNALED(status)) {
		i_error("Script terminated abnormally, signal %d", WTERMSIG(status));
		return FALSE;
	} else if (WIFSTOPPED(status)) {
		i_fatal("Script stopped, signal %d", WSTOPSIG(status));
		return FALSE;
	} else {
		i_fatal("Script terminated abnormally, return status %d", status);
		return FALSE;
	}
	return TRUE;
}
示例#28
0
static unsigned ProgRun( int step )
{
    static int          ptrace_sig = 0;
    static int          ld_state = 0;
    user_regs_struct    regs;
    int                 status;
    prog_go_ret         *ret;
    void                (*old)(int);
    int                 debug_continue;

    if( pid == 0 )
        return( 0 );
    ret = GetOutPtr( 0 );

    if( at_end ) {
        ptrace_sig = 0;
        ret->conditions = COND_TERMINATE;
        goto end;
    }

    /* we only want child-generated SIGINTs now */
    do {
        old = setsig( SIGINT, SIG_IGN );
        if( step ) {
            Out( "PTRACE_SINGLESTEP\n" );
            if( ptrace( PTRACE_SINGLESTEP, pid, NULL, (void *)ptrace_sig ) == -1 )
                perror( "PTRACE_SINGLESTEP" );
        } else {
            Out( "PTRACE_CONT\n" );
            if( ptrace( PTRACE_CONT, pid, NULL, (void *)ptrace_sig ) == -1 )
                perror( "PTRACE_CONT" );
        }
        waitpid( pid, &status, 0 );
        setsig( SIGINT, old );

#if defined( MD_x86 )
        ptrace( PTRACE_GETREGS, pid, NULL, &regs );
#elif defined( MD_ppc )
        regs.eip = ptrace( PTRACE_PEEKUSER, pid, REGSIZE * PT_NIP, NULL );
        regs.esp = ptrace( PTRACE_PEEKUSER, pid, REGSIZE * PT_R1, NULL );
#elif defined( MD_mips )
        regs.eip = ptrace( PTRACE_PEEKUSER, pid, (void *)PC, NULL );
        regs.esp = ptrace( PTRACE_PEEKUSER, pid, (void *)29, NULL );
#endif
        Out( " eip " );
        OutNum( regs.eip );
        Out( "\n" );

        debug_continue = FALSE;
        if( WIFSTOPPED( status ) ) {
            switch( ( ptrace_sig = WSTOPSIG( status ) ) ) {
            case SIGSEGV:
            case SIGILL:
            case SIGFPE:
            case SIGABRT:
            case SIGBUS:
            case SIGQUIT:
            case SIGSYS:
                last_sig = ptrace_sig;
                ret->conditions = COND_EXCEPTION;
                ptrace_sig = 0;
                break;
            case SIGINT:
                ret->conditions = COND_USER;
                ptrace_sig = 0;
                break;
            case SIGTRAP:
                ret->conditions = step ? COND_TRACE : COND_BREAK;
                Out( "sigtrap\n" );
                ptrace_sig = 0;
                break;
            default:
                /* For signals that we do not wish to handle, we need
                 * to continue the debuggee until we get a signal
                 * that we need to handle
                 */
                Out( "Unknown signal " );
                OutNum( ptrace_sig );
                Out( "\n" );
                debug_continue = TRUE;
                break;
            }
        } else if( WIFEXITED( status ) ) {
            Out( "WIFEXITED\n" );
            at_end = TRUE;
            ret->conditions = COND_TERMINATE;
            ptrace_sig = 0;
            goto end;
        }
    } while( debug_continue );

    if( ret->conditions == COND_BREAK ) {
#if defined( MD_x86 )
        if( regs.eip == rdebug.r_brk + sizeof( old_ld_bp ) ) {
#elif defined( MD_ppc ) || defined( MD_mips )
        if( regs.eip == rdebug.r_brk ) {
#endif
            int         psig = 0;
            void        (*oldsig)(int);
            bp_t        opcode = BRK_POINT;

            /* The dynamic linker breakpoint was hit, meaning that
             * libraries are being loaded or unloaded. This gets a bit
             * tricky because we must restore the original code that was
             * at the breakpoint and execute it, but we still want to
             * keep the breakpoint.
             */
            WriteMem( pid, &old_ld_bp, rdebug.r_brk, sizeof( old_ld_bp ) );
            ReadMem( pid, &rdebug, (addr48_off)dbg_rdebug, sizeof( rdebug ) );
            Out( "ld breakpoint hit, state is " );
            switch( rdebug.r_state ) {
            case RT_ADD:
                Out( "RT_ADD\n" );
                ld_state = RT_ADD;
                AddOneLib( rdebug.r_map );
                break;
            case RT_DELETE:
                Out( "RT_DELETE\n" );
                ld_state = RT_DELETE;
                break;
            case RT_CONSISTENT:
                Out( "RT_CONSISTENT\n" );
                if( ld_state == RT_DELETE )
                    DelOneLib( rdebug.r_map );
                ld_state = RT_CONSISTENT;
                break;
            default:
                Out( "error!\n" );
                break;
            }
            regs.orig_eax = -1;
#if defined( MD_x86 )
            regs.eip--;
            ptrace( PTRACE_SETREGS, pid, NULL, &regs );
#endif
            oldsig = setsig( SIGINT, SIG_IGN );
            ptrace( PTRACE_SINGLESTEP, pid, NULL, (void *)psig );
            waitpid( pid, &status, 0 );
            setsig( SIGINT, oldsig );
            WriteMem( pid, &opcode, rdebug.r_brk, sizeof( old_ld_bp ) );
            ret->conditions = COND_LIBRARIES;
        } else {
#if defined( MD_x86 )
            Out( "decrease eip(sigtrap)\n" );
            regs.orig_eax = -1;
            regs.eip--;
            ptrace( PTRACE_SETREGS, pid, NULL, &regs );
#endif
        }
    }
    orig_eax = regs.orig_eax;
    last_eip = regs.eip;
    ret->program_counter.offset = regs.eip;
    ret->program_counter.segment = regs.cs;
    ret->stack_pointer.offset = regs.esp;
    ret->stack_pointer.segment = regs.ss;
    ret->conditions |= COND_CONFIG;

    /* If debuggee has dynamic section, try getting the r_debug struct
     * every time the debuggee stops. The r_debug data may not be available
     * immediately after the debuggee process loads.
     */
    if( !have_rdebug && (dbg_dyn != NULL) ) {
        if( Get_ld_info( pid, dbg_dyn, &rdebug, &dbg_rdebug ) ) {
            bp_t        opcode;

            AddInitialLibs( rdebug.r_map );
            have_rdebug = TRUE;
            ret->conditions |= COND_LIBRARIES;

            /* Set a breakpoint in dynamic linker. That way we can be
             * informed on dynamic library load/unload events.
             */
            ReadMem( pid, &old_ld_bp, rdebug.r_brk, sizeof( old_ld_bp ) );
            Out( "Setting ld breakpoint at " );
            OutNum( rdebug.r_brk );
            Out( " old opcode was " );
            OutNum( old_ld_bp );
            Out( "\n" );
            opcode = BRK_POINT;
            WriteMem( pid, &opcode, rdebug.r_brk, sizeof( opcode ) );
        }
    }
 end:
    CONV_LE_32( ret->stack_pointer.offset );
    CONV_LE_16( ret->stack_pointer.segment );
    CONV_LE_32( ret->program_counter.offset );
    CONV_LE_16( ret->program_counter.segment );
    CONV_LE_16( ret->conditions );
    return( sizeof( *ret ) );
}

unsigned ReqProg_step( void )
{
    return( ProgRun( TRUE ) );
}

unsigned ReqProg_go( void )
{
    return( ProgRun( FALSE ) );
}

unsigned ReqRedirect_stdin( void  )
{
    redirect_stdin_ret *ret;

    ret = GetOutPtr( 0 );
    ret->err = 1;
    return( sizeof( *ret ) );
}
示例#29
0
void StartProg( char *cmd, char *prog, char *full_args, char *dos_args )
{
    char            exe_name[PATH_MAX];
    pid_t           save_pgrp;
    pid_t           pid;
    int             status;

    MaxThread = 0;
    GrowArrays( 1 );
    HaveRdebug = FALSE;
    DbgDyn = NULL;
    OrigPGrp = getpgrp();
    Attached = TRUE;
    pid = Pid = SamplePid;

    /* allow attaching to existing process by pid */
    if( pid == 0 || ptrace( PTRACE_ATTACH, pid, NULL, NULL ) == -1 ) {
        int         num_args;
        size_t      len;
        char        **argv;

        Attached = FALSE;

        /* massage 'full_args' into argv format */
        len = strlen( full_args );
        num_args = SplitParms( full_args, NULL, len );
        argv = alloca( (num_args + 2)  * sizeof( *argv ) );
        argv[SplitParms( full_args, &argv[1], len ) + 1] = NULL;
        argv[0] = prog;

        Output( MsgArray[MSG_SAMPLE_1 - ERR_FIRST_MESSAGE] );
        Output( prog );
        Output( "\n" );

        save_pgrp = getpgrp();
        setpgid( 0, OrigPGrp );
        pid = fork();
        if( pid == -1 )
            InternalError( MsgArray[MSG_SAMPLE_3 - ERR_FIRST_MESSAGE] );
        if( pid == 0 ) {
            int     rc;

            if( ptrace( PTRACE_TRACEME, 0, NULL, NULL ) < 0 ) {
                InternalError( MsgArray[MSG_SAMPLE_4 - ERR_FIRST_MESSAGE] );
            }
            dbg_printf( "executing '%s'\n", prog );
            for( rc = 0; argv[rc] != NULL; ++rc )
                dbg_printf( "argv[%d] = '%s'\n", rc, argv[rc] );

            rc = execve( prog, (char const * const *)argv, (char const * const *)environ );
            dbg_printf( "execve() failed, returned %d\n", rc );
            InternalError( MsgArray[MSG_SAMPLE_3 - ERR_FIRST_MESSAGE] );  // failsafe
        }
        setpgid( 0, save_pgrp );
        strcpy( exe_name, prog );
    } else if( pid ) {
        GetExeNameFromPid( pid, exe_name, PATH_MAX );
        Output( MsgArray[MSG_SAMPLE_1 - ERR_FIRST_MESSAGE] );
        Output( exe_name );
        Output( "\n" );
    }

    if( (pid != -1) && (pid != 0) ) {
        /* wait until it hits _start (upon execve) or
           gives us a SIGSTOP (if attached) */
        if( waitpid( pid, &status, 0 ) < 0 )
            goto fail;
        if( !WIFSTOPPED( status ) )
            goto fail;
        if( Attached ) {
            if( WSTOPSIG( status ) != SIGSTOP )
                goto fail;
        } else {
            if( WSTOPSIG( status ) != SIGTRAP )
                goto fail;
        }

        DbgDyn = GetDebuggeeDynSection( exe_name );
        errno = 0;
    }
    if( errno != 0 ) {
        pid = 0;
    }
    else {
        /* record information about main executable and initialize shared
         * library tracking
         */
        InitLibMap();
        CodeLoad( exe_name, 0, SAMP_MAIN_LOAD );
        SampleLoop( pid );
        FiniLibMap();
    }
    return;

fail:
    if( pid != 0 && pid != -1 ) {
        if( Attached ) {
            ptrace( PTRACE_DETACH, pid, NULL, NULL );
            Attached = FALSE;
        } else {
            ptrace( PTRACE_KILL, pid, NULL, NULL );
            waitpid( pid, &status, 0 );
        }
    }
    InternalError( MsgArray[MSG_SAMPLE_5 - ERR_FIRST_MESSAGE] );
}
示例#30
0
int main(int nargs, char *args[])
{
  char *line, *words[MAX_WORDS];
  char string[1024],combined[1024],line_s[MAX_LINE];
  char c, *dir=NULL,*cwd, pwd[PATH_MAX];
  char username[128],password[128],viFile[256],viTemp[256];
  char comname[128],authkey[80],authkeyword[64],key[64];
  int  gotauthkey=0,gotusername=0,gotvi=0,gotnew=0;
  int  res, i, n, status, nwords=0;
  FILE *auth_fp = (FILE *)0;
  FILE *key_fp = (FILE *)0;
  pid_t wpid, pid;
  char mode[] = "0755";
  struct stat stbuf;

  // get server login user and password
  while ((c = getopt(nargs, args, "dhu:l:")) != -1)
    switch (c) {

    case 'h':             // help
      printf("Usage: %s {-d} {-h} {-u <username>}\n\n",args[0]);
      printf("-d : don't delete /tmp files\n");
      printf("-h : help\n");
      printf("-u : commands.com username\n");
      exit(0);

    case 'u':             // username
      strcpy(username,optarg);
      gotusername = 1;
      strcpy(password,getpass("Password: "******"Usage: %s {-d} {-h} {-u <username>}\n\n",args[0]);
      printf("-d : don't delete /tmp files\n");
      printf("-h : help\n");
      printf("-u : commands.com username\n");
      exit(0);
      break;
    }

  // if we have both the username and password, login and
  // get the authkey

  // get the authorization key for the username
  if (gotusername) {
    if ((res = getAuthKey(username, password, authkey, key)) != 0) {
      printf("Unable to get authkey from server (%d)\n",res);
      exit(1);
    }
  } else {
    getKeyVal(key);
  }

  // create the authkey.json file only if we have -u
  sprintf (comname,"/tmp/.%s.commands.com",getenv("USER"));
  if (gotusername) {
    sscanf (authkey,"{\"%[^\"]\":\"%[^\"]",authkeyword,authKeyVal);
    if (!strcmp(authkeyword,"error")) {
      printf("Invalid Login.. Exiting.\n");
      exit(1);
      // do not save error as authkey
    } else {
      auth_fp = fopen(comname,"w");
      if (auth_fp == NULL) {
        printf("unable to create %s\n",comname);
        exit(1);
      }
      fputs(authkey,auth_fp);
      fputs("\n",auth_fp);
      fclose(auth_fp);
    }
  } else {
    auth_fp = fopen(comname, "r");
    if (auth_fp != NULL) {
      if(fgets(authkey, 64, auth_fp) == NULL) {
        printf("Unable to read authkey from %s\n",comname);
        exit(1);
      }
      // remove trailing \n
      n = strlen(authkey);
      if (authkey[n-1] == '\n') authkey[n-1] = '\0';
      gotauthkey = 1;
    }
  }

  // create the key.json file
  key_fp = fopen(fName(KEY_NAME),"w");
  if (key_fp == NULL) {
    printf("unable to create %s\n",fName(KEY_NAME));
    exit(1);
  }
  fputs(key,key_fp);
  fputs("\n",key_fp);
  fclose(key_fp);

  // save off the key url to display to the user when we are done
  sscanf (key,"{\"key\":\"%[^\"]",keyVal);
  sprintf (displayUrl,"%s/%s",gotoKeyUrl,keyVal);

  // save off the authkey value
  if (gotusername || gotauthkey) {
    sscanf (authkey,"{\"%[^\"]\":\"%[^\"]",authkeyword,authKeyVal);
    if (!strcmp(authkeyword,"error")) {
      printf("\nError: %s\n\n",authKeyVal);
      exit(1);
    } else {
      printf("\nSuccessfully logged in...");
      if (gotusername) {
        printf("\nAuthKey saved to %s.  Delete file to return to Anonymous posting.\n",comname);
      } else {
        printf("\nAuthKey retrieved from %s.  Delete file to return to Anonymous posting.\n",comname);
      }
    }
  } else {
    strcpy(authKeyVal,"");
  }


  // set up termination function
  atexit((void *)terminate);

  // catch abort signals
  signal(SIGINT,(void *)terminate2);	// trap ctl-c
  signal(SIGTERM,(void *)terminate2);	// trap kill -15

  // create the post.txt file
  post_fp = fopen(fName(POST_NAME),"w");
  if (post_fp == NULL) {
    printf("unable to create post file %s\n",fName(POST_NAME));
    exit(1);
  }

  // record all input from the user
  while(1)
    {
      if (!gotdebug)
        unlink(fName(SHELL_NAME));

	line = rl_gets();
        if (line == NULL) {		// trap ctl-d
          exit(1);
        } else {
	  strcpy(line_s, line);
        }
      line = rl_gets();
      strcpy(line_s, line);
      if (line == NULL) {		// trap ctl-d
        exit(1);
      }

      // break the line up into words
      tokenize(line, words, &nwords);

      // just a blank line?
      if (words[0] == NULL) {
        continue;
      }

      // are we done ?
      if (!strcasecmp(words[0], "exit")) {
        exit(1);
      }

      fputs("monitor$ ",post_fp);
      fflush(post_fp);
      fputs(line_s,post_fp);
      fflush(post_fp);
      fputs("\n",post_fp);
      fflush(post_fp);



      // toss out any commands that cannot be handled such
      // as those that use libcurses.so

      if (!strcasecmp(words[0], "top")) {
        printf("Unable to capture output from %s\n",words[0]);
        sprintf(string,"Unable to capture output from %s\n",words[0]);
        fputs(string,post_fp);
        fflush(post_fp);
        continue;
      }


      // builtin command
      if (!strcasecmp(words[0], "cd")) {
        if (nwords == 1)                     dir = getenv("HOME");
        if (nwords == 2 && *words[1] == '~') dir = getenv("HOME");
        if (nwords == 2 && *words[1] != '~') dir = words[1];
        if (chdir(dir) == -1) {
          perror("chdir");
          fputs(strerror(errno),post_fp);
          fflush(post_fp);
          fputs("\n",post_fp);
          fflush(post_fp);
          continue;
        }
        continue;
      }

      // builtin command
      if (!strcasecmp(words[0], "pwd")) {
        if(NULL == (cwd = getcwd(pwd, PATH_MAX))) {
          strcpy(pwd,"Unable to get current working directory\n");
        }
        printf("%s\n",pwd);
        fputs(pwd,post_fp);
        fflush(post_fp);
        fputs("\n",post_fp);
        fflush(post_fp);
        continue;
      }

      // builtin command
      if (!strcasecmp(words[0], "export")) {
        if (nwords > 1) {
          putenv(words[1]);
          continue;
        }
      }

      // look for "ls" by itself and add -C to make it tabbed format
      // because when piped through tee, it thinks it is not connected
      // to a terminal.
      if (!strcasecmp(words[0], "ls")) {
        if (nwords == 1) {
          words[1] = "-C";
          nwords = 2;
        }
      }

      // look for "man" and add | col -b
      if (!strcasecmp(words[0], "man")) {
        if (nwords == 2) {
          words[2] = "|";
          words[3] = "col";
          words[4] = "-b";
          nwords = 5;
        }
        // for when there is a "man 3 foo"
        if (nwords == 3) {
          words[3] = "|";
          words[4] = "col";
          words[5] = "-b";
          nwords = 6;
        }
      }

      // process special "vi" command
      if (!strcasecmp(words[0], "vi")) {
        if (nwords == 1) {
          printf("Please specify the new file you wish to create.\n");
          printf("It is required to correctly log the new file.\n");
          continue;
        }
        gotvi = 1;
        if (stat(words[1],&stbuf) != 0) {
          // new file
          gotnew=1;
          strcpy(viFile,words[1]);
        } else {
          // make copy of existing file
          strcpy(viFile,words[1]);
          strcpy(viTemp,fName(TEMP_NAME));
          my_cp(viFile,viTemp);
          gotnew=0;
        }
      } else {
        gotvi = 0;
      }

      // close the post.txt before forking
      fclose(post_fp);

      // OK, lets process the external command using fork/execvp
      if ((pid = fork ()) < 0) {
        perror ("fork");
        exit(0);
      }

      // this will split output between the terminal and post.txt
      //  <command> 2>&1 | tee -ai <file>
      if (pid == 0) {		// if child then exec the command
        if (!gotvi) {
          // create the bash script
          tmp_fp = fopen(fName(SHELL_NAME),"w");
          if (tmp_fp == NULL) {
            printf("unable to create %s file\n",fName(SHELL_NAME));
            exit(1);
          }
          // set file permission to 755
          i = strtol(mode, 0, 8);
          chmod (fName(SHELL_NAME),i);
          memset(combined,0,sizeof(combined));
          for(i=0;i<nwords;i++) {
            strcat(combined,words[i]);
            strcat(combined," ");
          }

          sprintf(string,"#!/bin/bash -l\n%s 2>&1 | tee -ai %s\n",combined,fName(POST_NAME));
          fputs(string,tmp_fp);
          fclose(tmp_fp);

          execlp ("/bin/bash","bash","-c",fName(SHELL_NAME),(char *)0);
          perror ("execlp");
          exit(0);
        } else {

          execlp ("vi","vi",viFile,(char *)0);
          perror ("execlp");
          exit(0);
        }
      }

      if (pid > 0)            // parent waits for child process to terminate
        {
          do {
            wpid = waitpid(pid, &status, WUNTRACED);
            if (wpid == -1) {
              perror("waitpid");
              return(0);
            }


            if (WIFEXITED(status)) {
              //printf("child exited, status=%d\n", WEXITSTATUS(status));


            } else if (WIFSIGNALED(status)) {
              printf("process killed (signal %d)\n", WTERMSIG(status));


            } else if (WIFSTOPPED(status)) {
              printf("process stopped (signal %d)\n", WSTOPSIG(status));


            } else {    // Non-standard case -- may never happen
              printf("Unexpected status (0x%x)\n", status);
            }
          } while (!WIFEXITED(status) && !WIFSIGNALED(status));

          // existing file
          if (gotvi && !gotnew) {
            my_diff(viTemp,viFile,fName(POST_NAME));
            unlink(viTemp);
          }

          // new file
          if (gotvi && gotnew) {
            my_append(viFile,fName(POST_NAME));
          }

          // re-open the post.txt file
          post_fp = fopen(fName(POST_NAME),"a");
          if (post_fp == NULL) {
            printf("unable to re-open post file %s\n",fName(POST_NAME));
            exit(2);
          }

        }



    }

  exit(0);
}