Beispiel #1
0
/*
 * This function does all command processing for interfacing to
 * a remote gdb.  Note that the error codes are ignored by gdb
 * at present, but might eventually become meaningful. (XXX)
 * It might makes sense to use POSIX errno values, because
 * that is what the gdb/remote.c functions want to return.
 */
int
kgdb_trap(int type, db_regs_t *regs)
{
	label_t jmpbuf;
	vaddr_t addr;
	size_t len;
	u_char *p;

	if (kgdb_dev < 0 || kgdb_getc == NULL) {
		/* not debugging */
		return (0);
	}

	/* Detect and recover from unexpected traps. */
	if (kgdb_recover != 0) {
		printf("kgdb: caught trap 0x%x at %p\n",
			   type, (void *)PC_REGS(regs));
		kgdb_send("E0E"); /* 14==EFAULT */
		longjmp(kgdb_recover);
	}

	/*
	 * The first entry to this function is normally through
	 * a breakpoint trap in kgdb_connect(), in which case we
	 * must advance past the breakpoint because gdb will not.
	 *
	 * Machines vary as to where they leave the PC after a
	 * breakpoint trap.  Those that leave the PC set to the
	 * address of the trap instruction (i.e. pc532) will not
	 * define FIXUP_PC_AFTER_BREAK(), and therefore will just
	 * advance the PC.  On machines that leave the PC set to
	 * the instruction after the trap, FIXUP_PC_AFTER_BREAK
	 * will be defined to back-up the PC, so that after the
	 * "first-time" part of the if statement below has run,
	 * the PC will be the same as it was on entry.
	 *
	 * On the first entry here, we expect that gdb is not yet
	 * listening to us, so just enter the interaction loop.
	 * After the debugger is "active" (connected) it will be
	 * waiting for a "signaled" message from us.
	 */
	if (kgdb_active == 0) {
		if (!IS_BREAKPOINT_TRAP(type, 0)) {
			/* No debugger active -- let trap handle this. */
			return (0);
		}
		/* Make the PC point at the breakpoint... */
#ifdef	FIXUP_PC_AFTER_BREAK
		FIXUP_PC_AFTER_BREAK(regs);
#endif
		/* ... and then advance past it. */
#ifdef	PC_ADVANCE
		PC_ADVANCE(regs);
#else
		SET_PC_REGS(regs, PC_REGS(regs) + BKPT_SIZE);
#endif
		kgdb_active = 1;
	} else {
		/* Tell remote host that an exception has occurred. */
		snprintf(buffer, sizeof buffer, "S%02x", kgdb_signal(type));
		kgdb_send(buffer);
	}

	/* Stick frame regs into our reg cache. */
	kgdb_getregs(regs, gdb_regs);

	/*
	 * Interact with gdb until it lets us go.
	 * If we cause a trap, resume here.
	 */
	(void)setjmp((kgdb_recover = &jmpbuf));
	for (;;) {
		kgdb_recv(buffer, sizeof(buffer));
		switch (buffer[0]) {

		default:
			/* Unknown command. */
			kgdb_send("");
			continue;

		case KGDB_SIGNAL:
			/*
			 * 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".
			 */
			snprintf(buffer, sizeof buffer, "S%02x",
			    kgdb_signal(type));
			kgdb_send(buffer);
			continue;

		case KGDB_REG_R:
			mem2hex(buffer, gdb_regs, sizeof(gdb_regs));
			kgdb_send(buffer);
			continue;

		case KGDB_REG_W:
			p = hex2mem(gdb_regs, buffer + 1, sizeof(gdb_regs));
			if (p == NULL || *p != '\0')
				kgdb_send("E01");
			else {
				kgdb_setregs(regs, gdb_regs);
				kgdb_send("OK");
			}
			continue;

		case KGDB_MEM_R:
			p = buffer + 1;
			addr = hex2i(&p);
			if (*p++ != ',') {
				kgdb_send("E02");
				continue;
			}
			len = hex2i(&p);
			if (*p != '\0') {
				kgdb_send("E03");
				continue;
			}
			if (len > sizeof(buffer) / 2) {
				kgdb_send("E04");
				continue;
			}
			if (kgdb_acc(addr, len) == 0) {
				kgdb_send("E05");
				continue;
			}
			db_read_bytes(addr, (size_t)len,
					(char *)buffer + sizeof(buffer) / 2);
			mem2hex(buffer, buffer + sizeof(buffer) / 2, len);
			kgdb_send(buffer);
			continue;

		case KGDB_MEM_W:
			p = buffer + 1;
			addr = hex2i(&p);
			if (*p++ != ',') {
				kgdb_send("E06");
				continue;
			}
			len = hex2i(&p);
			if (*p++ != ':') {
				kgdb_send("E07");
				continue;
			}
			if (len > (sizeof(buffer) - (p - buffer))) {
				kgdb_send("E08");
				continue;
			}
			p = hex2mem(buffer, p, sizeof(buffer));
			if (p == NULL) {
				kgdb_send("E09");
				continue;
			}
			if (kgdb_acc(addr, len) == 0) {
				kgdb_send("E0A");
				continue;
			}
			db_write_bytes(addr, (size_t)len, (char *)buffer);
			kgdb_send("OK");
			continue;

		case KGDB_DETACH:
			kgdb_active = 0;
			printf("kgdb detached\n");
			db_clear_single_step(regs);
			kgdb_send("OK");
			goto out;

		case KGDB_KILL:
			kgdb_active = 0;
			printf("kgdb detached\n");
			db_clear_single_step(regs);
			goto out;

		case KGDB_CONT:
			if (buffer[1]) {
				p = buffer + 1;
				addr = hex2i(&p);
				if (*p) {
					kgdb_send("E0B");
					continue;
				}
				SET_PC_REGS(regs, addr);
			}
			db_clear_single_step(regs);
			goto out;

		case KGDB_STEP:
			if (buffer[1]) {
				p = buffer + 1;
				addr = hex2i(&p);
				if (*p) {
					kgdb_send("E0B");
					continue;
				}
				SET_PC_REGS(regs, addr);
			}
			db_set_single_step(regs);
			goto out;
		}
	}
 out:
	kgdb_recover = 0;
	return (1);
}
Beispiel #2
0
boolean_t
db_stop_at_pc(db_regs_t *regs, boolean_t *is_breakpoint)
{
	db_addr_t	pc, old_pc;
	db_breakpoint_t	bkpt;

	db_clear_breakpoints();
	db_clear_watchpoints();
	old_pc = pc = PC_REGS(regs);

#ifdef	FIXUP_PC_AFTER_BREAK
	if (*is_breakpoint) {
		/*
		 * Breakpoint trap.  Fix up the PC if the
		 * machine requires it.
		 */
		FIXUP_PC_AFTER_BREAK(regs);
		pc = PC_REGS(regs);
	}
#endif

	/*
	 * Now check for a breakpoint at this address.
	 */
	bkpt = db_find_breakpoint_here(pc);
	if (bkpt) {
		if (--bkpt->count == 0) {
			db_clear_single_step(regs);
			bkpt->count = bkpt->init_count;
			*is_breakpoint = TRUE;
			return (TRUE);	/* stop here */
		}
	} else if (*is_breakpoint
#ifdef SOFTWARE_SSTEP
	    && !((db_taken_bkpt && db_taken_bkpt->address == pc) ||
	    (db_not_taken_bkpt && db_not_taken_bkpt->address == pc))
#endif
	    ) {
#ifdef PC_ADVANCE
		PC_ADVANCE(regs);
#else
# ifdef SET_PC_REGS
		SET_PC_REGS(regs, old_pc);
# else
		PC_REGS(regs) = old_pc;
# endif
#endif
	}
	db_clear_single_step(regs);
		
	*is_breakpoint = FALSE;

	if (db_run_mode == STEP_INVISIBLE) {
		db_run_mode = STEP_CONTINUE;
		return (FALSE);	/* continue */
	}
	if (db_run_mode == STEP_COUNT) {
		return (FALSE); /* continue */
	}
	if (db_run_mode == STEP_ONCE) {
		if (--db_loop_count > 0) {
			if (db_sstep_print) {
				db_printf("\t\t");
				db_print_loc_and_inst(pc);
				db_printf("\n");
			}
			return (FALSE);	/* continue */
		}
	}
	if (db_run_mode == STEP_RETURN) {
	    db_expr_t ins = db_get_value(pc, sizeof(int), FALSE);

	    /* continue until matching return */

	    if (!inst_trap_return(ins) &&
		(!inst_return(ins) || --db_call_depth != 0)) {
		if (db_sstep_print) {
		    if (inst_call(ins) || inst_return(ins)) {
			int i;

			db_printf("[after %6d]     ", db_inst_count);
			for (i = db_call_depth; --i > 0; )
			    db_printf("  ");
			db_print_loc_and_inst(pc);
			db_printf("\n");
		    }
		}
		if (inst_call(ins))
		    db_call_depth++;
		return (FALSE);	/* continue */
	    }
	}
	if (db_run_mode == STEP_CALLT) {
	    db_expr_t ins = db_get_value(pc, sizeof(int), FALSE);

	    /* continue until call or return */

	    if (!inst_call(ins) && !inst_return(ins) &&
		!inst_trap_return(ins)) {
		return (FALSE);	/* continue */
	    }
	}
	db_run_mode = STEP_NONE;
	return (TRUE);
}