static void
handle_sigtrap(struct child *son)
{
	long scno, ret;
	const char *scname;

	/* We get this event twice, one at entering a
	 * system call and one at exiting a system
	 * call. */
	if (son->insyscall) {
		if (!pink_util_get_return(son->pid, &ret))
			err(1, "pink_util_get_return");
		if (son->inexecve) {
			son->inexecve = false;
			if (ret == 0) { /* execve was successful */
				/* Update bitness */
				son->bitness = pink_bitness_get(son->pid);
				if (son->bitness == PINK_BITNESS_UNKNOWN)
					err(1, "pink_bitness_get");
				printf(" = 0 (Updating the bitness of child %i to %s mode)\n",
					son->pid, pink_bitness_name(son->bitness));
				son->printret = false;
				return;
			}
		}
		son->insyscall = false;
		if (!son->printret) {
			son->printret = true;
			return;
		}
		/* Exiting the system call, print the
		 * return value. */
		putchar(' ');
		print_ret(ret);
		putchar('\n');
	}
	else {
		son->insyscall = true;
		/* Get the system call number and call
		 * the appropriate decoder. */
		if (!pink_util_get_syscall(son->pid, son->bitness, &scno))
			err(1, "pink_util_get_syscall");
		scname = pink_name_syscall(scno, son->bitness);
		assert(scname != NULL);

		if (!strcmp(scname, "execve"))
			son->inexecve = true;

		if (!strcmp(scname, "open"))
			decode_open(son->pid, son->bitness);
		else if (!strcmp(scname, "execve"))
			decode_execve(son->pid, son->bitness);
		else if (!strcmp(scname, "bind") || !strcmp(scname, "connect"))
			decode_socketcall(son->pid, son->bitness, scname);
		else
			printf("%s()", scname);
	}
}
int
main(int argc, char **argv)
{
	int sig, status, exit_code;
	pink_event_t event;
	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);
		event = pink_event_decide(status);
		assert(event == PINK_EVENT_STOP);

		/* Set up the tracing options. */
		if (!pink_trace_setup(son.pid, PINK_TRACE_OPTION_SYSGOOD | PINK_TRACE_OPTION_EXEC)) {
			perror("pink_trace_setup");
			pink_trace_kill(son.pid);
			return EXIT_FAILURE;
		}

		/* 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.dead = son.insyscall = false;
		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. */
			event = pink_event_decide(status);
			switch (event) {
			case PINK_EVENT_SYSCALL:
				handle_syscall(&son);
				break;
				break;
			case PINK_EVENT_EXEC:
				/* Update bitness */
				son.bitness = pink_bitness_get(son.pid);
				if (son.bitness == PINK_BITNESS_UNKNOWN)
					err(1, "pink_bitness_get");
				else
					printf(" (Updating the bitness of child %i to %s mode)\n",
						son.pid, pink_bitness_name(son.bitness));
				break;
			case PINK_EVENT_GENUINE:
			case PINK_EVENT_UNKNOWN:
				/* Send the signal to the traced child as it
				 * was a genuine signal.
				 */
				sig = WSTOPSIG(status);
				break;
			case PINK_EVENT_EXIT_GENUINE:
				exit_code = WEXITSTATUS(status);
				printf("Child %i exited normally with return code %d\n",
						son.pid, exit_code);
				son.dead = true;
				break;
			case PINK_EVENT_EXIT_SIGNAL:
				exit_code = 128 + WTERMSIG(status);
				printf("Child %i exited with signal %d\n",
						son.pid, WTERMSIG(status));
				son.dead = true;
				break;
			default:
				/* Nothing */
				;
			}
			if (son.dead)
				break;
		}

		return exit_code;
	}
}
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;
	}
}