⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 trace.c

📁 a sample debugger in Linux
💻 C
字号:
/** * file:trace.c * author:XXX * date:2/3/08 * * note: Although we define a subfunction named "getMainEntryPoint", actually, the address *       it gets is not the main() function entry point, but some virtul address prior to  *       main() function. Futhermore, there are still some bugs to be fixed. However, my free *       is so limited, yet, I really want some reader to fix bugs for me. And you are quarl- *       -ified to modify any lines of code below. If you do, please send email to notify me. *       My email address is zhucj041070075@gmail.com, I'm looking forward to your letters. */#include<stdio.h>#include<stdlib.h>#include<string.h>#include<unistd.h>#include<fcntl.h>#include<errno.h>#include<signal.h>#include<elf.h>#include<sys/types.h>#include<sys/stat.h>#include<sys/wait.h>#include<sys/ptrace.h>#include<asm/user.h>#define INPUTLINE 64void usage();void command();void ptraceErrCheck(int res, enum __ptrace_request req);int getUserRegs(pid_t pid, struct user_regs_struct * regs, int verbose);void setUserRegs(pid_t pid, struct user_regs_struct * regs);char ** CreateExecArgv(int argc, char ** argv);void FreeExecArgv(int argc, char ** argv);void calAddress(char * comm, unsigned long * bpAddr);int getMainEntryPoint(FILE * Elf_fp, unsigned long * bpAddr);int main(int argc, char ** argv){	if(argc < 2) {		usage();		return 0;	}	FILE * fp;	int stat_loc; long res; char comm[INPUTLINE];	pid_t pid;	long oldInstruct, newInstruct;	int IsInterrupted = 0; unsigned long bpAddr;//main entrypoint	struct user_regs_struct regs;	memset(&regs, 0, sizeof(struct user_regs_struct));	if((fp = fopen(argv[1], "r")) < 0) {		fprintf(stderr, "File not exist!\n");		return -1;	}	else {		int ret = getMainEntryPoint(fp, &bpAddr);//get Main EntryPoint		switch(ret) {			case 0:				fclose(fp);				break;			case -1://file read error				fprintf(stdout, "file read error!\n");				fclose(fp);				return -1;			case -2://data format error				fprintf(stdout, "data format error!\n");				fclose(fp);				return -1;		}	}	char ** ExecArgv = CreateExecArgv(argc, argv);	if(!ExecArgv) {		fprintf(stderr, "Failed to allocate memowy!\n");		return -1;	}TRACEHERE:	pid = fork();		if(pid < 0) {		fprintf(stderr, "Fork error!\n");		return -1;	}	else if( pid == 0) { //child		int ret = ptrace(PTRACE_TRACEME, 0, NULL, NULL);		ptraceErrCheck(ret, PTRACE_TRACEME);		execvp(ExecArgv[0] , ExecArgv);	}	else { //parent		res = waitpid(pid, &stat_loc, 0);				fprintf(stdout, "Begin to trace program %s!\n", ExecArgv[0]);		while(1) {			fprintf(stdout, "Command: ");			fgets(comm, INPUTLINE, stdin);			if(comm[0] == 'h') {//help				command();			}			else if(comm[0] == 'b') {//break				IsInterrupted = 1;								calAddress(comm, &bpAddr);				oldInstruct = ptrace(PTRACE_PEEKTEXT, pid, bpAddr, NULL);				ptraceErrCheck(oldInstruct, PTRACE_PEEKTEXT);				/**				 *here I'm not sure whether it's always successful to midify the				 *instructure code like this, maybe we will be signaled with SIGILL,				 *so this is a subtle bug.				 */				newInstruct = 0xcccccccc;				res = ptrace(PTRACE_POKETEXT, pid, bpAddr, newInstruct);				ptraceErrCheck(res, PTRACE_POKETEXT);				res = ptrace(PTRACE_CONT, pid, NULL, NULL);				ptraceErrCheck(res, PTRACE_CONT);				waitpid(pid, &stat_loc, 0);				if(WIFSTOPPED(stat_loc)) {					int signal = WSTOPSIG(stat_loc);					if(signal == SIGTRAP)						fprintf(stdout, "breakpoint at 0x%x \n", bpAddr);					else						fprintf(stdout, "Program %s interrupted by signal %d\n",							ExecArgv[0], signal);					getUserRegs(pid, &regs, 1);				}			}			else if(comm[0] == 'r') {//run				res = ptrace(PTRACE_CONT, pid, NULL, NULL);				ptraceErrCheck(res, PTRACE_CONT);				res = waitpid(pid, &stat_loc, 0);				fprintf(stdout, "Program %s exit with code %d\n",					ExecArgv[0], WEXITSTATUS(stat_loc));				goto TRACEHERE;			}			else if(comm[0] == 'c') {//continue				if(!IsInterrupted) {					fprintf(stdout, "program %s is not being running!\n", ExecArgv[0]);					continue;				}				IsInterrupted = 0;								res = getUserRegs(pid, &regs, 0);//Get the context of being ptraced process				/**				 *x86 instructioin CC(INT 3) cause a TRAP,then eip is increased to				 *point to the next instruction.So, here we must decrease eip to 				 *ensure it points to the trap-caused instruction.				 */				if(res) {					continue;				}				regs.eip--;				setUserRegs(pid, &regs);//set back context to the being ptraced process				res = ptrace(PTRACE_POKETEXT, pid, bpAddr, oldInstruct);				ptraceErrCheck(res, PTRACE_POKETEXT);				res = ptrace(PTRACE_CONT, pid, NULL, NULL);				ptraceErrCheck(res, PTRACE_CONT);				waitpid(pid, &stat_loc, 0);				if(WIFEXITED(stat_loc)) {					fprintf(stdout, "Program %s exit with code %d\n",						ExecArgv[0], WEXITSTATUS(stat_loc));				}				else if(WIFSTOPPED(stat_loc)) {					fprintf(stdout, "Program %s interrupted by signal %d\n",						ExecArgv[0], WSTOPSIG(stat_loc));				}				goto TRACEHERE;			}			else if(comm[0] == 'k') {//kill				res = ptrace(PTRACE_KILL, pid, NULL, NULL);				ptraceErrCheck(res, PTRACE_KILL);				fprintf(stdout, "program %s terminated!\n", ExecArgv[0]);				goto TRACEHERE;			}			else if(comm[0] == 'q') {//quit				res = ptrace(PTRACE_KILL, pid, NULL, NULL);				ptraceErrCheck(res, PTRACE_KILL);				fprintf(stdout, "Tracer quit!\n");				break;			}			else {				fprintf(stderr, "Unknown Command!\n");			}		}	}		FreeExecArgv(argc, ExecArgv);	return 0;}void usage(){	fprintf(stdout, " usage: trace [filename] [parameters]\n");}void command(){	fprintf(stdout, " command usage: b(break) *addr\n"			   "              : c(continue) \n"			   "              : r(run) \n"			   "              : h(help) \n"			   "              : k(kill) \n"			   "              : q(quit) \n");}void ptraceErrCheck(int res, enum __ptrace_request req){	if(res < 0 && errno != 0) {		perror("PTRACE error:");		switch(req) {			case PTRACE_KILL:				return;			default:				exit(-1);		}	}}int getUserRegs(pid_t pid, struct user_regs_struct * regs, int verbose){	long res = ptrace(PTRACE_GETREGS, pid, NULL, (void *)regs);	if(res < 0 && errno != 0) {		perror("PTRACE error:");		return -1;	}		if(verbose) {		fprintf(stdout, "registers infomation:\n");		fprintf(stdout, "	eax:	0x%x\n", regs->eax);		fprintf(stdout, "	ecx:	0x%x\n", regs->ecx);		fprintf(stdout, "	edx:	0x%x\n", regs->edx);		fprintf(stdout, "	ebx:	0x%x\n", regs->ebx);		fprintf(stdout, "	esp:	0x%x\n", regs->esp);		fprintf(stdout, "	ebp:	0x%x\n", regs->ebp);		fprintf(stdout, "	esi:	0x%x\n", regs->esi);		fprintf(stdout, "	edi:	0x%x\n", regs->edi);		fprintf(stdout, "	eip:	0x%x"		"<--Here eip points to the next instruction\n", regs->eip);		fprintf(stdout, "	eflags:	0x%x\n", regs->eflags);		fprintf(stdout, "	cs:	0x%x\n", regs->cs);		fprintf(stdout, "	ss:	0x%x\n", regs->ss);		fprintf(stdout, "	ds:	0x%x\n", regs->ds);		fprintf(stdout, "	es:	0x%x\n", regs->es);		fprintf(stdout, "	fs:	0x%x\n", regs->fs);		fprintf(stdout, "	gs:	0x%x\n", regs->gs);	}		return 0;}void setUserRegs(pid_t pid, struct user_regs_struct * regs){	long res = ptrace(PTRACE_SETREGS, pid, NULL, (void *)regs);	if(res < 0 && errno != 0) {		perror("PTRACE error:");		exit(-1);	}}void calAddress(char * comm, unsigned long * bpAddr){	//example:comm = b 0xffffffff	//we must strip all the prefix	//here we do not check the validity of Address	char * index = comm;	while(*index != '\0') {		if(!strncmp(index, "0x", 2)){			*bpAddr = (unsigned long)strtol(index + 2, NULL, 16);			printf("%x\n", *bpAddr);			return;		}		index++;	}}int getMainEntryPoint(FILE * Elf_fp, unsigned long * bpAddr){	Elf32_Ehdr elf_header;	if(fread(&elf_header, sizeof(Elf32_Ehdr), 1, Elf_fp) != 1)		return -1;//file read error	unsigned char * field = (unsigned char *)&elf_header.e_entry;		switch(elf_header.e_ident[EI_DATA]) {		case ELFDATA2LSB:			* bpAddr = ((unsigned long)(field[0]))				| (((unsigned long)(field[1])) << 8)				| (((unsigned long)(field[2])) << 16)				| (((unsigned long)(field[3])) << 24);			return 0;//success		case ELFDATA2MSB:			* bpAddr = ((unsigned long)(field[3]))				| (((unsigned long)(field[2])) << 8)				| (((unsigned long)(field[1])) << 16)				| (((unsigned long)(field[0])) << 24);			return 0;//success		default:			fprintf(stderr, "Unknown data format!\n");			return -2;//data format error	}}char ** CreateExecArgv(int argc, char ** argv){	char ** execArgv = (char **)malloc(sizeof(char *) * argc);	if(!execArgv) {		return NULL;	}	int i, size;char * index;	for(i = 1; i < argc; ++i) {		size = sizeof(argv[i]) + 1;		if(i == 1)			size += 2;		execArgv[i - 1] = (char *)malloc(sizeof(char) * size);		if(!execArgv[i - 1]) {			return NULL;		}		index = execArgv[i - 1];		if(i == 1) {			if(argv[i][0] != '/' && argv[i][0] != '.') {				strcpy(execArgv[i - 1], "./");				index = execArgv[i - 1] + 2;			}		}		strcpy(index, argv[i]);	}	execArgv[argc - 1] = (char *)0;		return execArgv;}void FreeExecArgv(int argc, char ** argv){	int i;	for(i = 0; i < argc; ++i) {		if(!argv[i])			free(argv[i]);	}	free(argv);}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -