sys/i386/i386/kgdb_stub.c
/*
 * This function does all command procesing for interfacing to 
 * a remote gdb.
 */
This function does all command procesing for interfacing to
a remote gdb.
This function does all command procesing for interfacing to a remote gdb .
int 
kgdb_trap(int type, struct trapframe *frame)
{
	register u_long len;
	u_char *addr;
	register u_char *cp;
	register u_char out, in;
	register int outlen;
	int inlen;
	u_long gdb_regs[NUM_REGS];
	int saved_kgdb_active = kgdb_active;
	if (kgdb_dev < 0) {
		return (0);
	}
	if (kgdb_active == 0) {
#ifdef DONN
		if (kgdb_debug > 3)
			pg("kgdb_trap: start initialization\n");
#endif
		if (type != T_BPTFLT) {
			return (0);
		}
		kgdb_getc = 0;
		for (inlen = 0; constab[inlen].cn_probe; inlen++)
		    if (major(constab[inlen].cn_dev) == major(kgdb_dev)) {
			kgdb_getc = constab[inlen].cn_getc;
			kgdb_putc = constab[inlen].cn_putc;
			break;
		}
#ifdef DONN
		if (kgdb_debug > 3)
			pg("kgdb_trap: kgdb_getc = %x, kgdb_putc = %x\n",
				kgdb_getc, kgdb_putc);
#endif
		if (kgdb_getc == 0 || kgdb_putc == 0)
			return (0);
		in = GETC;
#ifdef DONN
		if (kgdb_debug > 3)
			pg("kgdb_trap: looking for sync %x\n", in);
#endif
		if (in == FRAME_END)
			in = GETC;
		if (KGDB_CMD(in) != KGDB_EXEC || (in & KGDB_ACK) != 0)
			return (0);
		while (GETC != FRAME_END)
			;
		printf("kgdb started from device %x\n", kgdb_dev);
		kgdb_send(in | KGDB_ACK, (u_char *)0, 0);
		kgdb_active = 1;
	}
	regs_to_gdb(frame, gdb_regs);
	if (saved_kgdb_active == kgdb_active) {
		outbuffer[0] = computeSignal(type);
		kgdb_send(KGDB_SIGNAL, outbuffer, 1);
	}
	while (1) {
		in = kgdb_recv(inbuffer, &inlen);
		if (in == 0 || (in & KGDB_ACK))
			continue;
		out = in | KGDB_ACK;
		switch (KGDB_CMD(in)) {
		case KGDB_SIGNAL:
			if (inlen == 0) {
				outbuffer[0] = computeSignal(type);
				kgdb_send(KGDB_SIGNAL, outbuffer, 1);
			}
			continue;
		case KGDB_REG_R:
		case KGDB_REG_R | KGDB_DELTA:
			cp = outbuffer;
			outlen = 0;
			for (len = inbuffer[0]; len < NUM_REGS; ++len) {
				if (reg_cache[len] != gdb_regs[len] ||
				    (in & KGDB_DELTA) == 0) {
					if (outlen + 5 > SL_MAXMSG) {
						out |= KGDB_MORE;
						break;
					}
					cp[outlen] = len;
					kgdb_copy((u_char *)&gdb_regs[len],
						  &cp[outlen + 1], 4);
					reg_cache[len] = gdb_regs[len];
					outlen += 5;
				}
			}
			break;
		case KGDB_REG_W:
		case KGDB_REG_W | KGDB_DELTA:
			cp = inbuffer;
			for (len = 0; len < inlen; len += 5) {
				register int j = cp[len];
				kgdb_copy(&cp[len + 1],
					  (u_char *)&gdb_regs[j], 4);
				reg_cache[j] = gdb_regs[j];
			}
			gdb_to_regs(frame, gdb_regs);
			outlen = 0;
			break;
		case KGDB_MEM_R:
			len = inbuffer[0];
			kgdb_copy(&inbuffer[1], (u_char *)&addr, 4);
			if (len + 1 > SL_MAXMSG) {
				outlen = 1;
				outbuffer[0] = E2BIG;
			} else if (!kgdb_acc(addr, len, B_READ)) {
				outlen = 1;
				outbuffer[0] = EFAULT;
			} else {
				outlen = len + 1;
				outbuffer[0] = 0;
				kgdb_copy(addr, &outbuffer[1], len);
			}
			break;
		case KGDB_MEM_W:
			len = inlen - 4;
			kgdb_copy(inbuffer, (u_char *)&addr, 4);
			outlen = 1;
			if (!kgdb_acc(addr, len, B_READ))
				outbuffer[0] = EFAULT;
			else {
				outbuffer[0] = 0;
#if 0				
				if (!kgdb_acc(addr, len, B_WRITE))
					chgkprot(addr, len, B_WRITE);
#endif
				kgdb_copy(&inbuffer[4], addr, len);
			}
			break;
		case KGDB_KILL:
			kgdb_active = 0;
			printf("kgdb detached\n");
		case KGDB_CONT:
			kgdb_send(out, 0, 0);
			frame->tf_eflags &=~ PSL_T;
			return (1);
		case KGDB_STEP:
			kgdb_send(out, 0, 0);
			frame->tf_eflags |= PSL_T;
			return (1);
		case KGDB_EXEC:
		default:
			outlen = 0;
			break;
		}
		kgdb_send(out, outbuffer, outlen);
	}
}
int kgdb_trap ( int type , struct trapframe * frame ) { register u_long len ; u_char * addr ; register u_char * cp ; register u_char out , in ; register int outlen ; int inlen ; u_long gdb_regs [ NUM_REGS ] ; int saved_kgdb_active = kgdb_active ; if ( kgdb_dev < 0 ) { return ( 0 ) ; } if ( kgdb_active == 0 ) { #ifdef DONN if ( kgdb_debug > 3 ) pg ( " \n " ) ; #endif if ( type != T_BPTFLT ) { return ( 0 ) ; } kgdb_getc = 0 ; for ( inlen = 0 ; constab [ inlen ] . cn_probe ; inlen ++ ) if ( major ( constab [ inlen ] . cn_dev ) == major ( kgdb_dev ) ) { kgdb_getc = constab [ inlen ] . cn_getc ; kgdb_putc = constab [ inlen ] . cn_putc ; break ; } #ifdef DONN if ( kgdb_debug > 3 ) pg ( " \n " , kgdb_getc , kgdb_putc ) ; #endif if ( kgdb_getc == 0 || kgdb_putc == 0 ) return ( 0 ) ; in = GETC ; #ifdef DONN if ( kgdb_debug > 3 ) pg ( " \n " , in ) ; #endif if ( in == FRAME_END ) in = GETC ; if ( KGDB_CMD ( in ) != KGDB_EXEC || ( in & KGDB_ACK ) != 0 ) return ( 0 ) ; while ( GETC != FRAME_END ) ; printf ( " \n " , kgdb_dev ) ; kgdb_send ( in | KGDB_ACK , ( u_char * ) 0 , 0 ) ; kgdb_active = 1 ; } regs_to_gdb ( frame , gdb_regs ) ; if ( saved_kgdb_active == kgdb_active ) { outbuffer [ 0 ] = computeSignal ( type ) ; kgdb_send ( KGDB_SIGNAL , outbuffer , 1 ) ; } while ( 1 ) { in = kgdb_recv ( inbuffer , & inlen ) ; if ( in == 0 || ( in & KGDB_ACK ) ) continue ; out = in | KGDB_ACK ; switch ( KGDB_CMD ( in ) ) { case KGDB_SIGNAL : if ( inlen == 0 ) { outbuffer [ 0 ] = computeSignal ( type ) ; kgdb_send ( KGDB_SIGNAL , outbuffer , 1 ) ; } continue ; case KGDB_REG_R : case KGDB_REG_R | KGDB_DELTA : cp = outbuffer ; outlen = 0 ; for ( len = inbuffer [ 0 ] ; len < NUM_REGS ; ++ len ) { if ( reg_cache [ len ] != gdb_regs [ len ] || ( in & KGDB_DELTA ) == 0 ) { if ( outlen + 5 > SL_MAXMSG ) { out |= KGDB_MORE ; break ; } cp [ outlen ] = len ; kgdb_copy ( ( u_char * ) & gdb_regs [ len ] , & cp [ outlen + 1 ] , 4 ) ; reg_cache [ len ] = gdb_regs [ len ] ; outlen += 5 ; } } break ; case KGDB_REG_W : case KGDB_REG_W | KGDB_DELTA : cp = inbuffer ; for ( len = 0 ; len < inlen ; len += 5 ) { register int j = cp [ len ] ; kgdb_copy ( & cp [ len + 1 ] , ( u_char * ) & gdb_regs [ j ] , 4 ) ; reg_cache [ j ] = gdb_regs [ j ] ; } gdb_to_regs ( frame , gdb_regs ) ; outlen = 0 ; break ; case KGDB_MEM_R : len = inbuffer [ 0 ] ; kgdb_copy ( & inbuffer [ 1 ] , ( u_char * ) & addr , 4 ) ; if ( len + 1 > SL_MAXMSG ) { outlen = 1 ; outbuffer [ 0 ] = E2BIG ; } else if ( ! kgdb_acc ( addr , len , B_READ ) ) { outlen = 1 ; outbuffer [ 0 ] = EFAULT ; } else { outlen = len + 1 ; outbuffer [ 0 ] = 0 ; kgdb_copy ( addr , & outbuffer [ 1 ] , len ) ; } break ; case KGDB_MEM_W : len = inlen - 4 ; kgdb_copy ( inbuffer , ( u_char * ) & addr , 4 ) ; outlen = 1 ; if ( ! kgdb_acc ( addr , len , B_READ ) ) outbuffer [ 0 ] = EFAULT ; else { outbuffer [ 0 ] = 0 ; #if 0 if ( ! kgdb_acc ( addr , len , B_WRITE ) ) chgkprot ( addr , len , B_WRITE ) ; #endif kgdb_copy ( & inbuffer [ 4 ] , addr , len ) ; } break ; case KGDB_KILL : kgdb_active = 0 ; printf ( " \n " ) ; case KGDB_CONT : kgdb_send ( out , 0 , 0 ) ; frame -> tf_eflags &= ~ PSL_T ; return ( 1 ) ; case KGDB_STEP : kgdb_send ( out , 0 , 0 ) ; frame -> tf_eflags |= PSL_T ; return ( 1 ) ; case KGDB_EXEC : default : outlen = 0 ; break ; } kgdb_send ( out , outbuffer , outlen ) ; } }
This function does all command procesing for interfacing to
 a remote gdb.
This function does all command procesing for interfacing to a remote gdb .
/* not debugging */ /* No debugger active -- let trap handle this. */ /*
		 * If the packet that woke us up isn't an exec packet,
		 * ignore it since there is no active debugger.  Also,
		 * we check that it's not an ack to be sure that the 
		 * remote side doesn't send back a response after the
		 * local gdb has exited.  Otherwise, the local host
		 * could trap into gdb if it's running a gdb kernel too.
		 */ /*
		 * If we came in asynchronously through the serial line,
		 * the framing character is eaten by the receive interrupt,
		 * but if we come in through a synchronous trap (i.e., via
		 * kgdb_connect()), we will see the extra character.
		 */ /*
		 * Do the printf *before* we ack the message.  This way
		 * we won't drop any inbound characters while we're 
		 * doing the polling printf.
		 */ /*
	 * Stick frame regs into our reg cache then tell remote host
	 * that an exception has occured.
	 */ /*
		 * Don't send an asynchronous SIGNAL message when we hit
		 * the first breakpoint.  Otherwise, we will drop the incoming
		 * packet while we output this one (and on entry the other 
		 * side isn't interested in the SIGNAL type -- if it is,
		 * it will have used a signal packet.)
		 */ /* Ignore inbound acks and error conditions. */ /*
			 * if this command came from a running gdb,
			 * answer it -- the other guy has no way of
			 * knowing if we're in or out of this loop
			 * when he issues a "remote-signal".  (Note
			 * that without the length check, we could
			 * loop here forever if the ourput line is
			 * looped back or the remote host is echoing.)
			 */ /* 386 can't write-protect against kernel! */ /* fall through */ /* Unknown command.  Ack with a null message. */ /* Send the reply */