188 调试器的最小实现

pic_dbg.c

#include <stdio.h>
#include <stdlib.h>
#include <sys/ptrace.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/user.h>
#include <sys/reg.h>

void print_user_regs(struct user_regs_struct *puregs)
{
	if (puregs) {
		printf("-- user regs --\n");
		//printf("   r15: %lld\n", puregs->r15);
		//printf("   r14: %lld\n", puregs->r14);
		//printf("   r13: %lld\n", puregs->r13);
		//printf("   r12: %lld\n", puregs->r12);
		printf("   rbp: %p\n", (void *)puregs->rbp);
		//printf("   rbx: %lld\n", puregs->rbx);
		//printf("   r11: %lld\n", puregs->r11);
		//printf("   r10: %lld\n", puregs->r10);
		//printf("   r9: %lld\n", puregs->r9); 
		//printf("   r8: %lld\n", puregs->r8); 
		printf("   rax: %lld\n", puregs->rax);
		//printf("   rcx: %lld\n", puregs->rcx);
		//printf("   rdx: %lld\n", puregs->rdx);
		printf("   rsi: %lld\n", puregs->rsi);
		printf("   rdi: %lld\n", puregs->rdi);
		printf("   orig_rax: %lld\n", puregs->orig_rax);
		printf("   rip: %p\n", (void *)puregs->rip);
		//printf("   cs: %lld\n", puregs->cs); 
		//printf("   eflags: %p\n", (void *)puregs->eflags);
		printf("   rsp: %p\n", (void *)puregs->rsp);
		//printf("   ss: %lld\n", puregs->ss); 
		//printf("   fs_base: %p\n", (void *)puregs->fs_base);
		//printf("   gs_base: %p\n", (void *)puregs->gs_base);
		//printf("   ds: %lld\n", puregs->ds); 
		//printf("   es: %lld\n", puregs->es); 
		//printf("   fs: %lld\n", puregs->fs); 
		//printf("   gs: %lld\n", puregs->gs); 
		printf("-- ---- ---- --\n\n");
	}
}

void print_user(struct user *pu)
{
	if (pu) {
		print_user_regs(&pu->regs);
		// u_fpvalid
		// i387
		printf("u_tsize: %lld\n", pu->u_tsize);
		printf("u_dsize: %lld\n", pu->u_dsize);
		printf("u_ssize: %lld\n", pu->u_ssize);
		printf("start_code: %lld\n", pu->start_code);
		printf("start_stack: %lld\n", pu->start_stack);
		printf("u_tsize: %lld\n", pu->signal);
		// reserved
		// u_ar0
		// __u_ar0_word
		// u_fpstate
		// __u_fpstate_word
		printf("u_comm: %s\n", pu->u_comm);
		for (int i = 0;
			i < sizeof(pu->u_debugreg)/sizeof(pu->u_debugreg[0]); i++)
			printf("u_debugreg[%i]: %lld\n", i, pu->u_debugreg[i]);
	}
}

int main(int argc, char *argv[])
{
	pid_t cpid, w;
	int status;
	struct user_regs_struct uregs;

	cpid = fork();
	if (cpid == -1) {
		perror("fork");
		exit(EXIT_FAILURE);
	}

	if (cpid == 0) {            /* Code executed by child */
		printf("Child PID is %ld\n", (long) getpid());
		ptrace(PTRACE_TRACEME, 0, NULL, NULL);

		char *newargv[] = { NULL, NULL, NULL, NULL };
		char *newenviron[] = { NULL };

		if (argc < 2) {
			fprintf(stderr, "Usage: %s <file-to-exec> [args]\n", argv[0]);
			exit(EXIT_FAILURE);
		}
		
		newargv[0] = argv[1];
		if (argv[2])
			newargv[1] = argv[2];
		if (argv[3])
			newargv[2] = argv[3];

		execve(argv[1], newargv, newenviron);
		perror("execve");   /* execve() returns only on error */
		exit(EXIT_FAILURE);
	} else {                    /* Code executed by parent */
		ptrace(PTRACE_SEIZE, cpid, NULL,
			PTRACE_O_EXITKILL | PTRACE_O_TRACEEXEC | PTRACE_O_TRACEEXIT);

#ifdef ADVERTISED_DISPLAY
		system("sleep 2; clear");
		for (int i = 0; i < 15; i++) {
			putchar('=');
			fflush(stdout);
			sleep(1);
		}
		puts(">");
		fflush(stdout);
		sleep(2);
		system("clear");
#endif

		/*
		 * wait for SIGTRAP(by execve)
		 */
		w = waitpid(cpid, &status, WUNTRACED | WCONTINUED);
		if (w == -1) {
			perror("waitpid");
			exit(EXIT_FAILURE);
		}
		if (WIFSTOPPED(status)) {
#ifdef ADVERTISED_DISPLAY
			puts(">> 系统调用execve");
#endif
			printf("stopped by signal %d\n", WSTOPSIG(status));
			printf("herein, successful calls to execve\n");
			ptrace(PTRACE_GETREGS, cpid, NULL, &uregs);
			print_user_regs(&uregs);
			ptrace(PTRACE_CONT, cpid, NULL, NULL);
		} else {
			printf("unexpected result, quit\n");
			exit(EXIT_FAILURE);
		}
#ifdef ADVERTISED_DISPLAY
		system("sleep 2; clear");
#endif

		/*
		 * wait for SIGTRAP(by asm int3 immediately after {)
		 */
		w = waitpid(cpid, &status, WUNTRACED | WCONTINUED);
		if (w == -1) {
			perror("waitpid");
			exit(EXIT_FAILURE);
		}
		if (WIFSTOPPED(status)) {
#ifdef ADVERTISED_DISPLAY
			puts(">> 进入sum函数");
#endif
			printf("stopped by signal %d\n", WSTOPSIG(status));
			printf("herein, immediately after {\n");
			ptrace(PTRACE_GETREGS, cpid, NULL, &uregs);
			print_user_regs(&uregs);
		} else {
			printf("unexpected result, quit\n");
			exit(EXIT_FAILURE);
		}
#ifdef ADVERTISED_DISPLAY
		system("sleep 2; clear");
#endif

		/*
		 * single step to next int3
		 */
		for (int i = 0; i < 5; i++) {
			ptrace(PTRACE_SINGLESTEP, cpid, NULL, NULL);
			w = waitpid(cpid, &status, WUNTRACED | WCONTINUED);
			if (w == -1) {
				perror("waitpid");
				exit(EXIT_FAILURE);
			}
			if (WIFSTOPPED(status)) {
#ifdef ADVERTISED_DISPLAY
				printf(">> 单步执行 - %d\n", i+1);
#endif
				printf("stopped by signal %d\n", WSTOPSIG(status));
				printf("herein, single-step %d\n", i+1);
				ptrace(PTRACE_GETREGS, cpid, NULL, &uregs);
				print_user_regs(&uregs);
			} else {
				printf("unexpected result, quit\n");
				exit(EXIT_FAILURE);
			}
#ifdef ADVERTISED_DISPLAY
			system("sleep 2; clear");
#endif
		}

		/*
		 * wait for SIGTRAP(by asm int3 immediately precede })
		 */
		ptrace(PTRACE_SINGLESTEP, cpid, NULL, NULL);
		w = waitpid(cpid, &status, WUNTRACED | WCONTINUED);
		if (w == -1) {
			perror("waitpid");
			exit(EXIT_FAILURE);
		}
		if (WIFSTOPPED(status)) {
#ifdef ADVERTISED_DISPLAY
			puts(">> 离开sum函数");
#endif
			printf("stopped by signal %d\n", WSTOPSIG(status));
			printf("herein, immediately precede }\n");
			ptrace(PTRACE_GETREGS, cpid, NULL, &uregs);
			print_user_regs(&uregs);
			ptrace(PTRACE_CONT, cpid, NULL, NULL);
		} else {
			printf("unexpected result, quit\n");
			exit(EXIT_FAILURE);
		}
#ifdef ADVERTISED_DISPLAY
		system("sleep 2; clear");
#endif

		/*
		 * wait for SIGTRAP(by exit_group syscall)
		 */
		w = waitpid(cpid, &status, WUNTRACED | WCONTINUED);
		if (w == -1) {
			perror("waitpid");
			exit(EXIT_FAILURE);
		}
		if (WIFSTOPPED(status)) {
#ifdef ADVERTISED_DISPLAY
			puts(">> 系统调用exit_group");
#endif
			printf("stopped by signal %d\n", WSTOPSIG(status));
			printf("herein, exit_group syscall\n");
			ptrace(PTRACE_GETREGS, cpid, NULL, &uregs);
			print_user_regs(&uregs);
			ptrace(PTRACE_CONT, cpid, NULL, NULL);
		} else {
			printf("unexpected result, quit\n");
			exit(EXIT_FAILURE);
		}
#ifdef ADVERTISED_DISPLAY
		system("sleep 2; clear");
#endif

		/*
		 * wait for ending of debugee
		 */
		w = waitpid(cpid, &status, WUNTRACED | WCONTINUED);
		if (w == -1) {
			perror("waitpid");
			exit(EXIT_FAILURE);
		}
		if (WIFEXITED(status)) {
#ifdef ADVERTISED_DISPLAY
			puts(">> 被调试程序即将终止");
#endif
			printf("exited, status=%d\n", WEXITSTATUS(status));
			printf("herein, ending of debugee\n");
			ptrace(PTRACE_GETREGS, cpid, NULL, &uregs);
			print_user_regs(&uregs);
		} else {
			printf("unexpected result, quit\n");
			exit(EXIT_FAILURE);
		}

		exit(EXIT_SUCCESS);
	}
}

prog.c

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include "sum.h"

int main(int argc, char *argv[])
{
	int op1 = 0, op2 = 0, res = 0;

	if (argc > 2)
		op2 = atoi(argv[2]);
	if (argc > 1)
		op1 = atoi(argv[1]);

	res = sum(op1, op2);

	return 0;
}

sum.c

#include "sum.h"

int sum(int op1, int op2)
{
__asm__("int3");
	int sum = 0;
	sum = op1 + op2;
__asm__("int3");
	return sum;
}

sum.h

#ifndef LTTC_SUM_H_
#define LTTC_SUM_H_

extern int sum(int op1, int op2);

#endif