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

📄 trap.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
📖 第 1 页 / 共 2 页
字号:
{	ulong l, v, i, estack;	extern ulong etext;	int x;	if(getconf("*nodumpstack")){		iprint("dumpstack disabled\n");		return;	}	iprint("dumpstack\n");	x = 0;	x += print("ktrace /kernel/path %.8lux %.8lux <<EOF\n", ureg->pc, ureg->sp);	i = 0;	if(up	&& (ulong)&l >= (ulong)up->kstack	&& (ulong)&l <= (ulong)up->kstack+KSTACK)		estack = (ulong)up->kstack+KSTACK;	else if((ulong)&l >= (ulong)m->stack	&& (ulong)&l <= (ulong)m+BY2PG)		estack = (ulong)m+MACHSIZE;	else		return;	x += print("estackx %.8lux\n", estack);	for(l=(ulong)&l; l<estack; l+=4){		v = *(ulong*)l;		if((KTZERO < v && v < (ulong)&etext) || estack-l<32){			/*			 * we could Pick off general CALL (((uchar*)v)[-5] == 0xE8)			 * and CALL indirect through AX (((uchar*)v)[-2] == 0xFF && ((uchar*)v)[-2] == 0xD0),			 * but this is too clever and misses faulting address.			 */			x += print("%.8lux=%.8lux ", l, v);			i++;		}		if(i == 4){			i = 0;			x += print("\n");		}	}	if(i)		print("\n");	print("EOF\n");}voiddumpstack(void){	callwithureg(_dumpstack);}static voiddebugbpt(Ureg* ureg, void*){	char buf[ERRMAX];	if(up == 0)		panic("kernel bpt");	/* restore pc to instruction that caused the trap */	ureg->pc--;	sprint(buf, "sys: breakpoint");	postnote(up, 1, buf, NDebug);}static voiddoublefault(Ureg*, void*){	panic("double fault");}static voidunexpected(Ureg* ureg, void*){	print("unexpected trap %lud; ignoring\n", ureg->trap);}extern void checkpages(void);extern void checkfault(ulong, ulong);static voidfault386(Ureg* ureg, void*){	ulong addr;	int read, user, n, insyscall;	char buf[ERRMAX];	addr = getcr2();	read = !(ureg->ecode & 2);	user = (ureg->cs & 0xFFFF) == UESEL;	if(!user){		if(vmapsync(addr))			return;		if(addr >= USTKTOP)			panic("kernel fault: bad address pc=0x%.8lux addr=0x%.8lux", ureg->pc, addr);		if(up == nil)			panic("kernel fault: no user process pc=0x%.8lux addr=0x%.8lux", ureg->pc, addr);	}	if(up == nil)		panic("user fault: up=0 pc=0x%.8lux addr=0x%.8lux", ureg->pc, addr);	insyscall = up->insyscall;	up->insyscall = 1;	n = fault(addr, read);	if(n < 0){		if(!user){			dumpregs(ureg);			panic("fault: 0x%lux\n", addr);		}		checkpages();		checkfault(addr, ureg->pc);		sprint(buf, "sys: trap: fault %s addr=0x%lux",			read ? "read" : "write", addr);		postnote(up, 1, buf, NDebug);	}	up->insyscall = insyscall;}/* *  system calls */#include "../port/systab.h"/* *  Syscall is called directly from assembler without going through trap(). */voidsyscall(Ureg* ureg){	char *e;	ulong	sp;	long	ret;	int	i, s;	ulong scallnr;	if((ureg->cs & 0xFFFF) != UESEL)		panic("syscall: cs 0x%4.4luX\n", ureg->cs);	cycles(&up->kentry);	m->syscall++;	up->insyscall = 1;	up->pc = ureg->pc;	up->dbgreg = ureg;	if(up->procctl == Proc_tracesyscall){		up->procctl = Proc_stopme;		procctl(up);	}	scallnr = ureg->ax;	up->scallnr = scallnr;	if(scallnr == RFORK && up->fpstate == FPactive){		fpsave(&up->fpsave);		up->fpstate = FPinactive;	}	spllo();	sp = ureg->usp;	up->nerrlab = 0;	ret = -1;	if(!waserror()){		if(scallnr >= nsyscall || systab[scallnr] == 0){			pprint("bad sys call number %d pc %lux\n",				scallnr, ureg->pc);			postnote(up, 1, "sys: bad sys call", NDebug);			error(Ebadarg);		}		if(sp<(USTKTOP-BY2PG) || sp>(USTKTOP-sizeof(Sargs)-BY2WD))			validaddr(sp, sizeof(Sargs)+BY2WD, 0);		up->s = *((Sargs*)(sp+BY2WD));		up->psstate = sysctab[scallnr];		ret = systab[scallnr](up->s.args);		poperror();	}else{		/* failure: save the error buffer for errstr */		e = up->syserrstr;		up->syserrstr = up->errstr;		up->errstr = e;		if(0 && up->pid == 1)			print("syscall %lud error %s\n", scallnr, up->syserrstr);	}	if(up->nerrlab){		print("bad errstack [%lud]: %d extra\n", scallnr, up->nerrlab);		for(i = 0; i < NERR; i++)			print("sp=%lux pc=%lux\n",				up->errlab[i].sp, up->errlab[i].pc);		panic("error stack");	}	/*	 *  Put return value in frame.  On the x86 the syscall is	 *  just another trap and the return value from syscall is	 *  ignored.  On other machines the return value is put into	 *  the results register by caller of syscall.	 */	ureg->ax = ret;	if(up->procctl == Proc_tracesyscall){		up->procctl = Proc_stopme;		s = splhi();		procctl(up);		splx(s);	}	up->insyscall = 0;	up->psstate = 0;	if(scallnr == NOTED)		noted(ureg, *(ulong*)(sp+BY2WD));	if(scallnr!=RFORK && (up->procctl || up->nnote)){		splhi();		notify(ureg);	}	/* if we delayed sched because we held a lock, sched now */	if(up->delaysched)		sched();	kexit(ureg);}/* *  Call user, if necessary, with note. *  Pass user the Ureg struct and the note on his stack. */intnotify(Ureg* ureg){	int l;	ulong s, sp;	Note *n;	if(up->procctl)		procctl(up);	if(up->nnote == 0)		return 0;	if(up->fpstate == FPactive){		fpsave(&up->fpsave);		up->fpstate = FPinactive;	}	up->fpstate |= FPillegal;	s = spllo();	qlock(&up->debug);	up->notepending = 0;	n = &up->note[0];	if(strncmp(n->msg, "sys:", 4) == 0){		l = strlen(n->msg);		if(l > ERRMAX-15)	/* " pc=0x12345678\0" */			l = ERRMAX-15;		sprint(n->msg+l, " pc=0x%.8lux", ureg->pc);	}	if(n->flag!=NUser && (up->notified || up->notify==0)){		if(n->flag == NDebug)			pprint("suicide: %s\n", n->msg);		qunlock(&up->debug);		pexit(n->msg, n->flag!=NDebug);	}	if(up->notified){		qunlock(&up->debug);		splhi();		return 0;	}			if(!up->notify){		qunlock(&up->debug);		pexit(n->msg, n->flag!=NDebug);	}	sp = ureg->usp;	sp -= sizeof(Ureg);	if(!okaddr((ulong)up->notify, 1, 0)	|| !okaddr(sp-ERRMAX-4*BY2WD, sizeof(Ureg)+ERRMAX+4*BY2WD, 1)){		pprint("suicide: bad address in notify\n");		qunlock(&up->debug);		pexit("Suicide", 0);	}	up->ureg = (void*)sp;	memmove((Ureg*)sp, ureg, sizeof(Ureg));	*(Ureg**)(sp-BY2WD) = up->ureg;	/* word under Ureg is old up->ureg */	up->ureg = (void*)sp;	sp -= BY2WD+ERRMAX;	memmove((char*)sp, up->note[0].msg, ERRMAX);	sp -= 3*BY2WD;	*(ulong*)(sp+2*BY2WD) = sp+3*BY2WD;		/* arg 2 is string */	*(ulong*)(sp+1*BY2WD) = (ulong)up->ureg;	/* arg 1 is ureg* */	*(ulong*)(sp+0*BY2WD) = 0;			/* arg 0 is pc */	ureg->usp = sp;	ureg->pc = (ulong)up->notify;	up->notified = 1;	up->nnote--;	memmove(&up->lastnote, &up->note[0], sizeof(Note));	memmove(&up->note[0], &up->note[1], up->nnote*sizeof(Note));	qunlock(&up->debug);	splx(s);	return 1;}/* *   Return user to state before notify() */voidnoted(Ureg* ureg, ulong arg0){	Ureg *nureg;	ulong oureg, sp;	qlock(&up->debug);	if(arg0!=NRSTR && !up->notified) {		qunlock(&up->debug);		pprint("call to noted() when not notified\n");		pexit("Suicide", 0);	}	up->notified = 0;	nureg = up->ureg;	/* pointer to user returned Ureg struct */	up->fpstate &= ~FPillegal;	/* sanity clause */	oureg = (ulong)nureg;	if(!okaddr((ulong)oureg-BY2WD, BY2WD+sizeof(Ureg), 0)){		pprint("bad ureg in noted or call to noted when not notified\n");		qunlock(&up->debug);		pexit("Suicide", 0);	}	/*	 * Check the segment selectors are all valid, otherwise	 * a fault will be taken on attempting to return to the	 * user process.	 * Take care with the comparisons as different processor	 * generations push segment descriptors in different ways.	 */	if((nureg->cs & 0xFFFF) != UESEL || (nureg->ss & 0xFFFF) != UDSEL	  || (nureg->ds & 0xFFFF) != UDSEL || (nureg->es & 0xFFFF) != UDSEL	  || (nureg->fs & 0xFFFF) != UDSEL || (nureg->gs & 0xFFFF) != UDSEL){		pprint("bad segment selector in noted\n");		qunlock(&up->debug);		pexit("Suicide", 0);	}	/* don't let user change system flags */	nureg->flags = (ureg->flags & ~0xCD5) | (nureg->flags & 0xCD5);	memmove(ureg, nureg, sizeof(Ureg));	switch(arg0){	case NCONT:	case NRSTR:		if(!okaddr(nureg->pc, 1, 0) || !okaddr(nureg->usp, BY2WD, 0)){			qunlock(&up->debug);			pprint("suicide: trap in noted\n");			pexit("Suicide", 0);		}		up->ureg = (Ureg*)(*(ulong*)(oureg-BY2WD));		qunlock(&up->debug);		break;	case NSAVE:		if(!okaddr(nureg->pc, BY2WD, 0)		|| !okaddr(nureg->usp, BY2WD, 0)){			qunlock(&up->debug);			pprint("suicide: trap in noted\n");			pexit("Suicide", 0);		}		qunlock(&up->debug);		sp = oureg-4*BY2WD-ERRMAX;		splhi();		ureg->sp = sp;		((ulong*)sp)[1] = oureg;	/* arg 1 0(FP) is ureg* */		((ulong*)sp)[0] = 0;		/* arg 0 is pc */		break;	default:		pprint("unknown noted arg 0x%lux\n", arg0);		up->lastnote.flag = NDebug;		/* fall through */			case NDFLT:		if(up->lastnote.flag == NDebug){ 			qunlock(&up->debug);			pprint("suicide: %s\n", up->lastnote.msg);		} else			qunlock(&up->debug);		pexit(up->lastnote.msg, up->lastnote.flag!=NDebug);	}}longexecregs(ulong entry, ulong ssize, ulong nargs){	ulong *sp;	Ureg *ureg;	up->fpstate = FPinit;	fpoff();	sp = (ulong*)(USTKTOP - ssize);	*--sp = nargs;	ureg = up->dbgreg;	ureg->usp = (ulong)sp;	ureg->pc = entry;	return USTKTOP-sizeof(Tos);		/* address of kernel/user shared data */}/* *  return the userpc the last exception happened at */ulonguserpc(void){	Ureg *ureg;	ureg = (Ureg*)up->dbgreg;	return ureg->pc;}/* This routine must save the values of registers the user is not permitted * to write from devproc and then restore the saved values before returning. */voidsetregisters(Ureg* ureg, char* pureg, char* uva, int n){	ulong flags;	ulong cs;	ulong ss;	flags = ureg->flags;	cs = ureg->cs;	ss = ureg->ss;	memmove(pureg, uva, n);	ureg->flags = (ureg->flags & 0x00FF) | (flags & 0xFF00);	ureg->cs = cs;	ureg->ss = ss;}static voidlinkproc(void){	spllo();	up->kpfun(up->kparg);	pexit("kproc dying", 0);}voidkprocchild(Proc* p, void (*func)(void*), void* arg){	/*	 * gotolabel() needs a word on the stack in	 * which to place the return PC used to jump	 * to linkproc().	 */	p->sched.pc = (ulong)linkproc;	p->sched.sp = (ulong)p->kstack+KSTACK-BY2WD;	p->kpfun = func;	p->kparg = arg;}voidforkchild(Proc *p, Ureg *ureg){	Ureg *cureg;	/*	 * Add 2*BY2WD to the stack to account for	 *  - the return PC	 *  - trap's argument (ur)	 */	p->sched.sp = (ulong)p->kstack+KSTACK-(sizeof(Ureg)+2*BY2WD);	p->sched.pc = (ulong)forkret;	cureg = (Ureg*)(p->sched.sp+2*BY2WD);	memmove(cureg, ureg, sizeof(Ureg));	/* return value of syscall in child */	cureg->ax = 0;	/* Things from bottom of syscall which were never executed */	p->psstate = 0;	p->insyscall = 0;}/* Give enough context in the ureg to produce a kernel stack for * a sleeping process */voidsetkernur(Ureg* ureg, Proc* p){	ureg->pc = p->sched.pc;	ureg->sp = p->sched.sp+4;}ulongdbgpc(Proc *p){	Ureg *ureg;	ureg = p->dbgreg;	if(ureg == 0)		return 0;	return ureg->pc;}

⌨️ 快捷键说明

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