gdb.c

来自「umon bootloader source code, support mip」· C语言 代码 · 共 676 行 · 第 1/2 页

C
676
字号
}

/* gdb_cmd():
 *	First function called out of the monitor's command interpreter.  It
 *	does a basic syntax verification and then passes parameters to the
 *	appropriate handler above.
 *	Incoming syntax is
 *
 *		$ CMD # CSUM (of CMD)
 *
 *	where:
 *		$		is the ascii '$' character (0x24)
 *		#		is the ascii '#' character (0x23)
 *		CMD		is some command line consisting of a command and arguments
 *		CSUM	is the checksum of the characters in CMD
 *
 *	for example:
 *		
 *		$m4015bc,2#5a
 *
 *	Returns...
 *		 0 if command is not processed;
 *		 1 if command is processed;
 *		-1 if command is processed but has an error;
 *
 *	If this code detects an error, then send an error code back to GDB.
 *	According to the article, there are no defined error codes in GDB so
 *	we will use the following...
 *		1 	indicates a missing '#' at the end of the incoming cmd string.
 *		2 	indicates a bad checksum calculation.
 *		3 	indicates some command processing error.
 *		4 	indicates bad 'X' command parsing.
 */
int
gdb_cmd(uchar *line)
{
	char 	*comma, *colon, *cp, *bp, buf[32];
	int		len, clen, err, i;
	uchar	mycsum, incsum;

	gdbContinueFptr = (void(*)())0;

	/* If the command is 'X', then we have to treat it "special" because
	 * it contains binary data...
	 */
	if (line[1] == 'X') {
		comma = strchr(line,',');
		colon = strchr(line,':');
		if ((comma) && (colon)) {
			bp = buf;
			cp = line;
			while(cp <= colon)
				*bp++ = *cp++;
			*bp = 0;
			gdbTrace("GDB_CMD: '%s'\n",buf);
		}
		else {
			gdbTrace("GDB_CMD: 'X'\n");
			gdb_err(GDBERR_BADXFMT);	/* Unexpected 'X' command format */
		}
	}
	else if (line[0] == 0x03) {
		gdbTrace("GDB_CTRLC\n");
		gdb_sig(2);
		return(1);
	}
	else {
		gdbTrace("GDB_CMD: '%s'\n",line);
		len = strlen(line);

		if (line[len-3] != '#') {
			gdb_err(GDBERR_NOHASH);		/* Missing ending '#' */
			return(-1);
		}

		clen = len - 3;
		mycsum = 0;
		for(i=1;i<clen;i++)
			mycsum += line[i];

		incsum = (uchar)strtol(line+len-2,(char **)0,16);
		if (mycsum != incsum) {
			gdb_err(GDBERR_BADCSUM);	/* Checksum failure */
			return(-1);
		}
	}

	err = 0;
	line++;
	switch(*line) {
		case 'm':		/* Memory read */
			err = gdb_m(line);
			break;
		case 'M':		/* Memory write (Ascii-coded-hex) */
			err = gdb_M(line);
			break;
		case 'X':		/* Memory write (Binary) */
			err = gdb_X(line);
			break;
		case 's':		/* Step */
			gdb_response("S05");
			break;
		case 'c':		/* Continue */
			gdb_c(line);
			break;
		case '?':		/* Last signal */
			gdb_response("S05");
			break;
		case 'g':		/* get all registers */
			gdb_g(line);
			break;
		case 'q':		/* Query */
			gdb_q(line);
			break;
		case 'P':		/* PRR=HHHHHHHH... reg*/
			gdb_P(line);
			break;
		case 'H':		/* Thread */
			gdb_ok();
			break;
		case 'k':		/* Quit */
			gdb_ok();
			break;
		default:		/* Unknown... return empty response. */
			gdb_response("");
			break;
	}
	if (err) {
		gdb_err(GDBERR_GENERR);			/* Command processing error */
	}
	return(1);
}

/* Gdb():
 * This is the command at the CLI that allows the monitor to connect
 * to a gdb debugger via the serial port.  It currently assumes that
 * the console port is the same port as is being used for the gdb
 * connection.  Eventually this needs to be modified to provide an 
 * option for the gdb protocol to run on some serial port other than
 * the console.
 *
 * The connection command in gdb to connect to via serial port (PC)
 * is:
 *	target remote com1
 */
char *GdbHelp[] = {
	"Enter gdb mode",
	"(no options)",
	0,
};

int
Gdb(int argc, char *argv)
{
	int		state, quit;
	uchar	*lp, c;
	static	uchar	line[1024];

	printf("Entering GDB mode, to exit manually type: '$k#00'\n");

	lp = (uchar *)0;
	quit = 0;
	state = 0;
	gdbUdp = 0;
	gdbTrace = Mtrace;
	while(!quit) {
		c = getchar();
		switch(state) {
			case 0:				/* Wait for start of message */
				if (c == '$') {
					lp = line;
					*lp++ = c;
					state = 1;
				}
				break;
			case 1:	
				*lp++ = c;		/* This is the command character */
				state = 2;
				break;
			case 2:
				if (c == '#') {
					state = 3;
					*lp++ = c;
				}
				else {
					*lp++ = c;
				}
				break;
			case 3:
				*lp++ = c;
				state = 4;
				break;
			case 4:
				*lp++ = c;
				*lp = 0;
				state = 0;
				if (line[1] == 'k')
					quit = 1;
				gdb_cmd(line);
				break;
			default:
				break;
		}
	}
	putchar('\n');
	return(CMD_SUCCESS);
}

#if INCLUDE_ETHERNET
/* processGDB():
 * This is the function that allows a remote gdb host to connect to
 * the monitor with gdb at the udp level.  The connection command in
 * gdb to do this is:
 *
 *	target remote udp:TARGET_IP:TARGET_PORT
 */
int
processGDB(struct ether_header *ehdr,ushort size)
{
	char	*gdbp;
	struct	ip *ihdr, *ti, *ri;
	struct	Udphdr *uhdr, *tu, *ru;
	struct	ether_header *te;

	/* If SHOW_GDB is set (via ether -vg), then we dump the trace to
	 * the console; otherwise, we use mtrace.
	 */
	if (EtherVerbose & SHOW_GDB)
		gdbTrace = printf;
	else
		gdbTrace = Mtrace;

	ihdr = (struct ip *)(ehdr + 1);
	uhdr = (struct Udphdr *)((char *)ihdr + IP_HLEN(ihdr));
	gdbp = (char *)(uhdr + 1);
	size = ecs(uhdr->uh_ulen) - sizeof(struct Udphdr);

	/* Check for ACK/NAK here:
	 */
	if (size == 1) {
		if ((*gdbp == '+') || (*gdbp == '-')) {
			gdbTrace("GDB_%s\n",*gdbp == '+' ? "ACK" : "NAK");
			return(0);
		}
	}

	/* Copy the incoming udp payload (the gdb command) to gdbIbuf[]
	 * and NULL terminate it...
	 */
	memcpy(gdbIbuf,gdbp,size);
	gdbIbuf[size] = 0;

	/* Now that we've stored away the GDB command request, we
	 * initially respond with the GDB acknowledgement ('+')...
	 */
	te = EtherCopy(ehdr);
	ti = (struct ip *) (te + 1);
	ri = (struct ip *) (ehdr + 1);
	ti->ip_vhl = ri->ip_vhl;
	ti->ip_tos = ri->ip_tos;
	ti->ip_len = ecs((1 + (sizeof(struct ip) + sizeof(struct Udphdr))));
	ti->ip_id = ipId();
	ti->ip_off = ri->ip_off;
	ti->ip_ttl = UDP_TTL;
	ti->ip_p = IP_UDP;
	memcpy((char *)&(ti->ip_src.s_addr),(char *)BinIpAddr,
		sizeof(struct in_addr));
	memcpy((char *)&(ti->ip_dst.s_addr),(char *)&(ri->ip_src.s_addr),
		sizeof(struct in_addr));
	tu = (struct Udphdr *) (ti + 1);
	ru = (struct Udphdr *) (ri + 1);
	tu->uh_sport = ru->uh_dport;
	tu->uh_dport = ru->uh_sport;
	tu->uh_ulen = ecs((ushort)(sizeof(struct Udphdr) + 1));
	gdbp = (char *)(tu+1);
	*gdbp = '+';

	ipChksum(ti);		/* Compute checksum of ip hdr */
	udpChksum(ti);		/* Compute UDP checksum */

	sendBuffer(sizeof(struct ether_header) + sizeof(struct ip) + 
		sizeof(struct Udphdr) + 1);

	/* Wrap the processing of the incoming packet with a set/clear
	 * of the gdbUdp flag so that the other gdb code can act 
	 * accordingly.
	 */
	gdbUdp = 1;
	if (gdb_cmd(gdbIbuf) == 0) {
		gdbUdp = 0;
		return(0);
	}
	gdbUdp = 0;

	/* Add 1 to the gdbRlen to include the NULL termination.
	 */
	gdbRlen++;	


	/* The second respons is only done if gdb_cmd returns non-zero.
	 * It is the response to the gdb command issued by the debugger
	 * on the host.
	 */
	te = EtherCopy(ehdr);
	ti = (struct ip *) (te + 1);
	ri = (struct ip *) (ehdr + 1);
	ti->ip_vhl = ri->ip_vhl;
	ti->ip_tos = ri->ip_tos;
	ti->ip_len = ecs((gdbRlen + (sizeof(struct ip) + sizeof(struct Udphdr))));
	ti->ip_id = ipId();
	ti->ip_off = ri->ip_off;
	ti->ip_ttl = UDP_TTL;
	ti->ip_p = IP_UDP;
	memcpy((char *)&(ti->ip_src.s_addr),(char *)BinIpAddr,
		sizeof(struct in_addr));
	memcpy((char *)&(ti->ip_dst.s_addr),(char *)&(ri->ip_src.s_addr),
		sizeof(struct in_addr));

	tu = (struct Udphdr *) (ti + 1);
	ru = (struct Udphdr *) (ri + 1);
	tu->uh_sport = ru->uh_dport;
	tu->uh_dport = ru->uh_sport;
	tu->uh_ulen = ecs((ushort)(sizeof(struct Udphdr) + gdbRlen));
	memcpy((char *)(tu+1),gdbRbuf,gdbRlen);

	ipChksum(ti);		/* Compute checksum of ip hdr */
	udpChksum(ti);		/* Compute UDP checksum */

	sendBuffer(sizeof(struct ether_header) + sizeof(struct ip) + 
		sizeof(struct Udphdr) + gdbRlen);

	return(1);
}
#endif

#endif

⌨️ 快捷键说明

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