| 
									
										
										
										
											2008-02-08 04:19:31 -08:00
										 |  |  | /* MN10300 GDB stub
 | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Originally written by Glenn Engel, Lake Stevens Instrument Division | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Contributed by HP Systems | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Modified for SPARC by Stu Grossman, Cygnus Support. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Modified for Linux/MIPS (and MIPS in general) by Andreas Busse | 
					
						
							|  |  |  |  * Send complaints, suggestions etc. to <andy@waldorf-gmbh.de> | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Copyright (C) 1995 Andreas Busse | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved. | 
					
						
							|  |  |  |  * Modified for Linux/mn10300 by David Howells <dhowells@redhat.com> | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  *  To enable debugger support, two things need to happen.  One, a | 
					
						
							|  |  |  |  *  call to set_debug_traps() is necessary in order to allow any breakpoints | 
					
						
							|  |  |  |  *  or error conditions to be properly intercepted and reported to gdb. | 
					
						
							|  |  |  |  *  Two, a breakpoint needs to be generated to begin communication.  This | 
					
						
							|  |  |  |  *  is most easily accomplished by a call to breakpoint().  Breakpoint() | 
					
						
							|  |  |  |  *  simulates a breakpoint by executing a BREAK instruction. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *    The following gdb commands are supported: | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * command          function                               Return value | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *    g             return the value of the CPU registers  hex data or ENN | 
					
						
							|  |  |  |  *    G             set the value of the CPU registers     OK or ENN | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *    mAA..AA,LLLL  Read LLLL bytes at address AA..AA      hex data or ENN | 
					
						
							|  |  |  |  *    MAA..AA,LLLL: Write LLLL bytes at address AA.AA      OK or ENN | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *    c             Resume at current address              SNN   ( signal NN) | 
					
						
							|  |  |  |  *    cAA..AA       Continue at address AA..AA             SNN | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *    s             Step one instruction                   SNN | 
					
						
							|  |  |  |  *    sAA..AA       Step one instruction from AA..AA       SNN | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *    k             kill | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *    ?             What was the last sigval ?             SNN   (signal NN) | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *    bBB..BB	    Set baud rate to BB..BB		   OK or BNN, then sets | 
					
						
							|  |  |  |  *							   baud rate | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * All commands and responses are sent with a packet which includes a | 
					
						
							|  |  |  |  * checksum.  A packet consists of | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * $<packet info>#<checksum>. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * where | 
					
						
							|  |  |  |  * <packet info> :: <characters representing the command or response> | 
					
						
							|  |  |  |  * <checksum>    :: < two hex digits computed as modulo 256 sum of <packetinfo>> | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * When a packet is received, it is first acknowledged with either '+' or '-'. | 
					
						
							|  |  |  |  * '+' indicates a successful transfer.  '-' indicates a failed transfer. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Example: | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Host:                  Reply: | 
					
						
							|  |  |  |  * $m0,10#2a               +$00010203040506070809101112131415#42 | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *  ============== | 
					
						
							|  |  |  |  *  MORE EXAMPLES: | 
					
						
							|  |  |  |  *  ============== | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *  For reference -- the following are the steps that one | 
					
						
							|  |  |  |  *  company took (RidgeRun Inc) to get remote gdb debugging | 
					
						
							|  |  |  |  *  going. In this scenario the host machine was a PC and the | 
					
						
							|  |  |  |  *  target platform was a Galileo EVB64120A MIPS evaluation | 
					
						
							|  |  |  |  *  board. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *  Step 1: | 
					
						
							|  |  |  |  *  First download gdb-5.0.tar.gz from the internet. | 
					
						
							|  |  |  |  *  and then build/install the package. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *  Example: | 
					
						
							|  |  |  |  *    $ tar zxf gdb-5.0.tar.gz | 
					
						
							|  |  |  |  *    $ cd gdb-5.0 | 
					
						
							|  |  |  |  *    $ ./configure --target=am33_2.0-linux-gnu | 
					
						
							|  |  |  |  *    $ make | 
					
						
							|  |  |  |  *    $ install | 
					
						
							|  |  |  |  *    am33_2.0-linux-gnu-gdb | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *  Step 2: | 
					
						
							|  |  |  |  *  Configure linux for remote debugging and build it. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *  Example: | 
					
						
							|  |  |  |  *    $ cd ~/linux | 
					
						
							|  |  |  |  *    $ make menuconfig <go to "Kernel Hacking" and turn on remote debugging> | 
					
						
							|  |  |  |  *    $ make dep; make vmlinux | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *  Step 3: | 
					
						
							|  |  |  |  *  Download the kernel to the remote target and start | 
					
						
							|  |  |  |  *  the kernel running. It will promptly halt and wait | 
					
						
							|  |  |  |  *  for the host gdb session to connect. It does this | 
					
						
							|  |  |  |  *  since the "Kernel Hacking" option has defined | 
					
						
							|  |  |  |  *  CONFIG_REMOTE_DEBUG which in turn enables your calls | 
					
						
							|  |  |  |  *  to: | 
					
						
							|  |  |  |  *     set_debug_traps(); | 
					
						
							|  |  |  |  *     breakpoint(); | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *  Step 4: | 
					
						
							|  |  |  |  *  Start the gdb session on the host. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *  Example: | 
					
						
							|  |  |  |  *    $ am33_2.0-linux-gnu-gdb vmlinux | 
					
						
							|  |  |  |  *    (gdb) set remotebaud 115200 | 
					
						
							|  |  |  |  *    (gdb) target remote /dev/ttyS1 | 
					
						
							|  |  |  |  *    ...at this point you are connected to | 
					
						
							|  |  |  |  *       the remote target and can use gdb | 
					
						
							|  |  |  |  *       in the normal fasion. Setting | 
					
						
							|  |  |  |  *       breakpoints, single stepping, | 
					
						
							|  |  |  |  *       printing variables, etc. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <linux/string.h>
 | 
					
						
							|  |  |  | #include <linux/kernel.h>
 | 
					
						
							|  |  |  | #include <linux/signal.h>
 | 
					
						
							|  |  |  | #include <linux/sched.h>
 | 
					
						
							|  |  |  | #include <linux/mm.h>
 | 
					
						
							|  |  |  | #include <linux/console.h>
 | 
					
						
							|  |  |  | #include <linux/init.h>
 | 
					
						
							|  |  |  | #include <linux/bug.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <asm/pgtable.h>
 | 
					
						
							|  |  |  | #include <asm/gdb-stub.h>
 | 
					
						
							|  |  |  | #include <asm/exceptions.h>
 | 
					
						
							| 
									
										
										
										
											2011-03-18 16:54:30 +00:00
										 |  |  | #include <asm/debugger.h>
 | 
					
						
							| 
									
										
										
										
											2008-02-08 04:19:31 -08:00
										 |  |  | #include <asm/serial-regs.h>
 | 
					
						
							|  |  |  | #include <asm/busctl-regs.h>
 | 
					
						
							| 
									
										
										
										
											2009-04-10 14:33:48 +01:00
										 |  |  | #include <unit/leds.h>
 | 
					
						
							|  |  |  | #include <unit/serial.h>
 | 
					
						
							| 
									
										
										
										
											2008-02-08 04:19:31 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  | /* define to use F7F7 rather than FF which is subverted by JTAG debugger */ | 
					
						
							|  |  |  | #undef GDBSTUB_USE_F7F7_AS_BREAKPOINT
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * BUFMAX defines the maximum number of characters in inbound/outbound buffers | 
					
						
							|  |  |  |  * at least NUMREGBYTES*2 are needed for register packets | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | #define BUFMAX 2048
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static const char gdbstub_banner[] = | 
					
						
							|  |  |  | 	"Linux/MN10300 GDB Stub (c) RedHat 2007\n"; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | u8	gdbstub_rx_buffer[PAGE_SIZE] __attribute__((aligned(PAGE_SIZE))); | 
					
						
							|  |  |  | u32	gdbstub_rx_inp; | 
					
						
							|  |  |  | u32	gdbstub_rx_outp; | 
					
						
							|  |  |  | u8	gdbstub_busy; | 
					
						
							|  |  |  | u8	gdbstub_rx_overflow; | 
					
						
							|  |  |  | u8	gdbstub_rx_unget; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static u8	gdbstub_flush_caches; | 
					
						
							|  |  |  | static char	input_buffer[BUFMAX]; | 
					
						
							|  |  |  | static char	output_buffer[BUFMAX]; | 
					
						
							|  |  |  | static char	trans_buffer[BUFMAX]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | struct gdbstub_bkpt { | 
					
						
							|  |  |  | 	u8	*addr;		/* address of breakpoint */ | 
					
						
							|  |  |  | 	u8	len;		/* size of breakpoint */ | 
					
						
							|  |  |  | 	u8	origbytes[7];	/* original bytes */ | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct gdbstub_bkpt gdbstub_bkpts[256]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * local prototypes | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static void getpacket(char *buffer); | 
					
						
							|  |  |  | static int putpacket(char *buffer); | 
					
						
							|  |  |  | static int computeSignal(enum exception_code excep); | 
					
						
							|  |  |  | static int hex(unsigned char ch); | 
					
						
							|  |  |  | static int hexToInt(char **ptr, int *intValue); | 
					
						
							|  |  |  | static unsigned char *mem2hex(const void *mem, char *buf, int count, | 
					
						
							|  |  |  | 			      int may_fault); | 
					
						
							|  |  |  | static const char *hex2mem(const char *buf, void *_mem, int count, | 
					
						
							|  |  |  | 			   int may_fault); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * Convert ch from a hex digit to an int | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static int hex(unsigned char ch) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	if (ch >= 'a' && ch <= 'f') | 
					
						
							|  |  |  | 		return ch - 'a' + 10; | 
					
						
							|  |  |  | 	if (ch >= '0' && ch <= '9') | 
					
						
							|  |  |  | 		return ch - '0'; | 
					
						
							|  |  |  | 	if (ch >= 'A' && ch <= 'F') | 
					
						
							|  |  |  | 		return ch - 'A' + 10; | 
					
						
							|  |  |  | 	return -1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #ifdef CONFIG_GDBSTUB_DEBUGGING
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void debug_to_serial(const char *p, int n) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	__debug_to_serial(p, n); | 
					
						
							|  |  |  | 	/* gdbstub_console_write(NULL, p, n); */ | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void gdbstub_printk(const char *fmt, ...) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	va_list args; | 
					
						
							|  |  |  | 	int len; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Emit the output into the temporary buffer */ | 
					
						
							|  |  |  | 	va_start(args, fmt); | 
					
						
							|  |  |  | 	len = vsnprintf(trans_buffer, sizeof(trans_buffer), fmt, args); | 
					
						
							|  |  |  | 	va_end(args); | 
					
						
							|  |  |  | 	debug_to_serial(trans_buffer, len); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static inline char *gdbstub_strcpy(char *dst, const char *src) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int loop = 0; | 
					
						
							|  |  |  | 	while ((dst[loop] = src[loop])) | 
					
						
							|  |  |  | 	       loop++; | 
					
						
							|  |  |  | 	return dst; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * scan for the sequence $<data>#<checksum> | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static void getpacket(char *buffer) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	unsigned char checksum; | 
					
						
							|  |  |  | 	unsigned char xmitcsum; | 
					
						
							|  |  |  | 	unsigned char ch; | 
					
						
							|  |  |  | 	int count, i, ret, error; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for (;;) { | 
					
						
							|  |  |  | 		/*
 | 
					
						
							|  |  |  | 		 * wait around for the start character, | 
					
						
							|  |  |  | 		 * ignore all other characters | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		do { | 
					
						
							|  |  |  | 			gdbstub_io_rx_char(&ch, 0); | 
					
						
							|  |  |  | 		} while (ch != '$'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		checksum = 0; | 
					
						
							|  |  |  | 		xmitcsum = -1; | 
					
						
							|  |  |  | 		count = 0; | 
					
						
							|  |  |  | 		error = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/*
 | 
					
						
							|  |  |  | 		 * now, read until a # or end of buffer is found | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		while (count < BUFMAX) { | 
					
						
							|  |  |  | 			ret = gdbstub_io_rx_char(&ch, 0); | 
					
						
							|  |  |  | 			if (ret < 0) | 
					
						
							|  |  |  | 				error = ret; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if (ch == '#') | 
					
						
							|  |  |  | 				break; | 
					
						
							|  |  |  | 			checksum += ch; | 
					
						
							|  |  |  | 			buffer[count] = ch; | 
					
						
							|  |  |  | 			count++; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (error == -EIO) { | 
					
						
							|  |  |  | 			gdbstub_proto("### GDB Rx Error - Skipping packet" | 
					
						
							|  |  |  | 				      " ###\n"); | 
					
						
							|  |  |  | 			gdbstub_proto("### GDB Tx NAK\n"); | 
					
						
							|  |  |  | 			gdbstub_io_tx_char('-'); | 
					
						
							|  |  |  | 			continue; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (count >= BUFMAX || error) | 
					
						
							|  |  |  | 			continue; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		buffer[count] = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/* read the checksum */ | 
					
						
							|  |  |  | 		ret = gdbstub_io_rx_char(&ch, 0); | 
					
						
							|  |  |  | 		if (ret < 0) | 
					
						
							|  |  |  | 			error = ret; | 
					
						
							|  |  |  | 		xmitcsum = hex(ch) << 4; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		ret = gdbstub_io_rx_char(&ch, 0); | 
					
						
							|  |  |  | 		if (ret < 0) | 
					
						
							|  |  |  | 			error = ret; | 
					
						
							|  |  |  | 		xmitcsum |= hex(ch); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (error) { | 
					
						
							|  |  |  | 			if (error == -EIO) | 
					
						
							|  |  |  | 				gdbstub_io("### GDB Rx Error -" | 
					
						
							|  |  |  | 					   " Skipping packet\n"); | 
					
						
							|  |  |  | 			gdbstub_io("### GDB Tx NAK\n"); | 
					
						
							|  |  |  | 			gdbstub_io_tx_char('-'); | 
					
						
							|  |  |  | 			continue; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/* check the checksum */ | 
					
						
							|  |  |  | 		if (checksum != xmitcsum) { | 
					
						
							|  |  |  | 			gdbstub_io("### GDB Tx NAK\n"); | 
					
						
							|  |  |  | 			gdbstub_io_tx_char('-');	/* failed checksum */ | 
					
						
							|  |  |  | 			continue; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		gdbstub_proto("### GDB Rx '$%s#%02x' ###\n", buffer, checksum); | 
					
						
							|  |  |  | 		gdbstub_io("### GDB Tx ACK\n"); | 
					
						
							|  |  |  | 		gdbstub_io_tx_char('+'); /* successful transfer */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/*
 | 
					
						
							|  |  |  | 		 * if a sequence char is present, | 
					
						
							|  |  |  | 		 * reply the sequence ID | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		if (buffer[2] == ':') { | 
					
						
							|  |  |  | 			gdbstub_io_tx_char(buffer[0]); | 
					
						
							|  |  |  | 			gdbstub_io_tx_char(buffer[1]); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			/*
 | 
					
						
							|  |  |  | 			 * remove sequence chars from buffer | 
					
						
							|  |  |  | 			 */ | 
					
						
							|  |  |  | 			count = 0; | 
					
						
							|  |  |  | 			while (buffer[count]) | 
					
						
							|  |  |  | 				count++; | 
					
						
							|  |  |  | 			for (i = 3; i <= count; i++) | 
					
						
							|  |  |  | 				buffer[i - 3] = buffer[i]; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * send the packet in buffer. | 
					
						
							|  |  |  |  * - return 0 if successfully ACK'd | 
					
						
							|  |  |  |  * - return 1 if abandoned due to new incoming packet | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static int putpacket(char *buffer) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	unsigned char checksum; | 
					
						
							|  |  |  | 	unsigned char ch; | 
					
						
							|  |  |  | 	int count; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/*
 | 
					
						
							|  |  |  | 	 * $<packet info>#<checksum>. | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	gdbstub_proto("### GDB Tx $'%s'#?? ###\n", buffer); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	do { | 
					
						
							|  |  |  | 		gdbstub_io_tx_char('$'); | 
					
						
							|  |  |  | 		checksum = 0; | 
					
						
							|  |  |  | 		count = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		while ((ch = buffer[count]) != 0) { | 
					
						
							|  |  |  | 			gdbstub_io_tx_char(ch); | 
					
						
							|  |  |  | 			checksum += ch; | 
					
						
							|  |  |  | 			count += 1; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		gdbstub_io_tx_char('#'); | 
					
						
							| 
									
										
										
										
											2008-07-25 19:45:20 -07:00
										 |  |  | 		gdbstub_io_tx_char(hex_asc_hi(checksum)); | 
					
						
							|  |  |  | 		gdbstub_io_tx_char(hex_asc_lo(checksum)); | 
					
						
							| 
									
										
										
										
											2008-02-08 04:19:31 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	} while (gdbstub_io_rx_char(&ch, 0), | 
					
						
							|  |  |  | 		 ch == '-' && (gdbstub_io("### GDB Rx NAK\n"), 0), | 
					
						
							|  |  |  | 		 ch != '-' && ch != '+' && | 
					
						
							|  |  |  | 		 (gdbstub_io("### GDB Rx ??? %02x\n", ch), 0), | 
					
						
							|  |  |  | 		 ch != '+' && ch != '$'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (ch == '+') { | 
					
						
							|  |  |  | 		gdbstub_io("### GDB Rx ACK\n"); | 
					
						
							|  |  |  | 		return 0; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	gdbstub_io("### GDB Tx Abandoned\n"); | 
					
						
							|  |  |  | 	gdbstub_rx_unget = ch; | 
					
						
							|  |  |  | 	return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * While we find nice hex chars, build an int. | 
					
						
							|  |  |  |  * Return number of chars processed. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static int hexToInt(char **ptr, int *intValue) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int numChars = 0; | 
					
						
							|  |  |  | 	int hexValue; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	*intValue = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	while (**ptr) { | 
					
						
							|  |  |  | 		hexValue = hex(**ptr); | 
					
						
							|  |  |  | 		if (hexValue < 0) | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		*intValue = (*intValue << 4) | hexValue; | 
					
						
							|  |  |  | 		numChars++; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		(*ptr)++; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return (numChars); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-03-18 16:54:29 +00:00
										 |  |  | #ifdef CONFIG_GDBSTUB_ALLOW_SINGLE_STEP
 | 
					
						
							| 
									
										
										
										
											2008-02-08 04:19:31 -08:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * We single-step by setting breakpoints. When an exception | 
					
						
							|  |  |  |  * is handled, we need to restore the instructions hoisted | 
					
						
							|  |  |  |  * when the breakpoints were set. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This is where we save the original instructions. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static struct gdb_bp_save { | 
					
						
							|  |  |  | 	u8	*addr; | 
					
						
							|  |  |  | 	u8	opcode[2]; | 
					
						
							|  |  |  | } step_bp[2]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static const unsigned char gdbstub_insn_sizes[256] = | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	/* 1  2  3  4  5  6  7  8  9  a  b  c  d  e  f */ | 
					
						
							|  |  |  | 	1, 3, 3, 3, 1, 3, 3, 3, 1, 3, 3, 3, 1, 3, 3, 3,	/* 0 */ | 
					
						
							|  |  |  | 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 1 */ | 
					
						
							|  |  |  | 	2, 2, 2, 2, 3, 3, 3, 3, 2, 2, 2, 2, 3, 3, 3, 3, /* 2 */ | 
					
						
							|  |  |  | 	3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 1, 1, 1, /* 3 */ | 
					
						
							|  |  |  | 	1, 1, 2, 2, 1, 1, 2, 2, 1, 1, 2, 2, 1, 1, 2, 2, /* 4 */ | 
					
						
							|  |  |  | 	1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, /* 5 */ | 
					
						
							|  |  |  | 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 6 */ | 
					
						
							|  |  |  | 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 7 */ | 
					
						
							|  |  |  | 	2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, /* 8 */ | 
					
						
							|  |  |  | 	2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, /* 9 */ | 
					
						
							|  |  |  | 	2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, /* a */ | 
					
						
							|  |  |  | 	2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, /* b */ | 
					
						
							|  |  |  | 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 2, 2, /* c */ | 
					
						
							|  |  |  | 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* d */ | 
					
						
							|  |  |  | 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* e */ | 
					
						
							|  |  |  | 	0, 2, 2, 2, 2, 2, 2, 4, 0, 3, 0, 4, 0, 6, 7, 1  /* f */ | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int __gdbstub_mark_bp(u8 *addr, int ix) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2010-10-27 17:28:55 +01:00
										 |  |  | 	/* vmalloc area */ | 
					
						
							|  |  |  | 	if (((u8 *) VMALLOC_START <= addr) && (addr < (u8 *) VMALLOC_END)) | 
					
						
							| 
									
										
										
										
											2008-02-08 04:19:31 -08:00
										 |  |  | 		goto okay; | 
					
						
							| 
									
										
										
										
											2010-10-27 17:28:55 +01:00
										 |  |  | 	/* SRAM, SDRAM */ | 
					
						
							|  |  |  | 	if (((u8 *) 0x80000000UL <= addr) && (addr < (u8 *) 0xa0000000UL)) | 
					
						
							| 
									
										
										
										
											2008-02-08 04:19:31 -08:00
										 |  |  | 		goto okay; | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | okay: | 
					
						
							|  |  |  | 	if (gdbstub_read_byte(addr + 0, &step_bp[ix].opcode[0]) < 0 || | 
					
						
							|  |  |  | 	    gdbstub_read_byte(addr + 1, &step_bp[ix].opcode[1]) < 0) | 
					
						
							|  |  |  | 		return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	step_bp[ix].addr = addr; | 
					
						
							|  |  |  | 	return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static inline void __gdbstub_restore_bp(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | #ifdef GDBSTUB_USE_F7F7_AS_BREAKPOINT
 | 
					
						
							|  |  |  | 	if (step_bp[0].addr) { | 
					
						
							|  |  |  | 		gdbstub_write_byte(step_bp[0].opcode[0], step_bp[0].addr + 0); | 
					
						
							|  |  |  | 		gdbstub_write_byte(step_bp[0].opcode[1], step_bp[0].addr + 1); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if (step_bp[1].addr) { | 
					
						
							|  |  |  | 		gdbstub_write_byte(step_bp[1].opcode[0], step_bp[1].addr + 0); | 
					
						
							|  |  |  | 		gdbstub_write_byte(step_bp[1].opcode[1], step_bp[1].addr + 1); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | #else
 | 
					
						
							|  |  |  | 	if (step_bp[0].addr) | 
					
						
							|  |  |  | 		gdbstub_write_byte(step_bp[0].opcode[0], step_bp[0].addr + 0); | 
					
						
							|  |  |  | 	if (step_bp[1].addr) | 
					
						
							|  |  |  | 		gdbstub_write_byte(step_bp[1].opcode[0], step_bp[1].addr + 0); | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	gdbstub_flush_caches = 1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	step_bp[0].addr		= NULL; | 
					
						
							|  |  |  | 	step_bp[0].opcode[0]	= 0; | 
					
						
							|  |  |  | 	step_bp[0].opcode[1]	= 0; | 
					
						
							|  |  |  | 	step_bp[1].addr		= NULL; | 
					
						
							|  |  |  | 	step_bp[1].opcode[0]	= 0; | 
					
						
							|  |  |  | 	step_bp[1].opcode[1]	= 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * emulate single stepping by means of breakpoint instructions | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static int gdbstub_single_step(struct pt_regs *regs) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	unsigned size; | 
					
						
							|  |  |  | 	uint32_t x; | 
					
						
							|  |  |  | 	uint8_t cur, *pc, *sp; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	step_bp[0].addr		= NULL; | 
					
						
							|  |  |  | 	step_bp[0].opcode[0]	= 0; | 
					
						
							|  |  |  | 	step_bp[0].opcode[1]	= 0; | 
					
						
							|  |  |  | 	step_bp[1].addr		= NULL; | 
					
						
							|  |  |  | 	step_bp[1].opcode[0]	= 0; | 
					
						
							|  |  |  | 	step_bp[1].opcode[1]	= 0; | 
					
						
							|  |  |  | 	x = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	pc = (u8 *) regs->pc; | 
					
						
							|  |  |  | 	sp = (u8 *) (regs + 1); | 
					
						
							|  |  |  | 	if (gdbstub_read_byte(pc, &cur) < 0) | 
					
						
							|  |  |  | 		return -EFAULT; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	gdbstub_bkpt("Single Step from %p { %02x }\n", pc, cur); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	gdbstub_flush_caches = 1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	size = gdbstub_insn_sizes[cur]; | 
					
						
							|  |  |  | 	if (size > 0) { | 
					
						
							|  |  |  | 		if (!__gdbstub_mark_bp(pc + size, 0)) | 
					
						
							|  |  |  | 			goto fault; | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		switch (cur) { | 
					
						
							|  |  |  | 			/* Bxx (d8,PC) */ | 
					
						
							| 
									
										
										
										
											2008-11-28 11:48:37 +00:00
										 |  |  | 		case 0xc0 ... 0xca: | 
					
						
							| 
									
										
										
										
											2008-02-08 04:19:31 -08:00
										 |  |  | 			if (gdbstub_read_byte(pc + 1, (u8 *) &x) < 0) | 
					
						
							|  |  |  | 				goto fault; | 
					
						
							|  |  |  | 			if (!__gdbstub_mark_bp(pc + 2, 0)) | 
					
						
							|  |  |  | 				goto fault; | 
					
						
							|  |  |  | 			if ((x < 0 || x > 2) && | 
					
						
							|  |  |  | 			    !__gdbstub_mark_bp(pc + (s8) x, 1)) | 
					
						
							|  |  |  | 				goto fault; | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			/* LXX (d8,PC) */ | 
					
						
							| 
									
										
										
										
											2008-11-28 11:48:37 +00:00
										 |  |  | 		case 0xd0 ... 0xda: | 
					
						
							| 
									
										
										
										
											2008-02-08 04:19:31 -08:00
										 |  |  | 			if (!__gdbstub_mark_bp(pc + 1, 0)) | 
					
						
							|  |  |  | 				goto fault; | 
					
						
							|  |  |  | 			if (regs->pc != regs->lar && | 
					
						
							|  |  |  | 			    !__gdbstub_mark_bp((u8 *) regs->lar, 1)) | 
					
						
							|  |  |  | 				goto fault; | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			/* SETLB - loads the next for bytes into the LIR
 | 
					
						
							|  |  |  | 			 * register */ | 
					
						
							|  |  |  | 		case 0xdb: | 
					
						
							|  |  |  | 			if (!__gdbstub_mark_bp(pc + 1, 0)) | 
					
						
							|  |  |  | 				goto fault; | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			/* JMP (d16,PC) or CALL (d16,PC) */ | 
					
						
							|  |  |  | 		case 0xcc: | 
					
						
							|  |  |  | 		case 0xcd: | 
					
						
							|  |  |  | 			if (gdbstub_read_byte(pc + 1, ((u8 *) &x) + 0) < 0 || | 
					
						
							|  |  |  | 			    gdbstub_read_byte(pc + 2, ((u8 *) &x) + 1) < 0) | 
					
						
							|  |  |  | 				goto fault; | 
					
						
							|  |  |  | 			if (!__gdbstub_mark_bp(pc + (s16) x, 0)) | 
					
						
							|  |  |  | 				goto fault; | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			/* JMP (d32,PC) or CALL (d32,PC) */ | 
					
						
							|  |  |  | 		case 0xdc: | 
					
						
							|  |  |  | 		case 0xdd: | 
					
						
							|  |  |  | 			if (gdbstub_read_byte(pc + 1, ((u8 *) &x) + 0) < 0 || | 
					
						
							|  |  |  | 			    gdbstub_read_byte(pc + 2, ((u8 *) &x) + 1) < 0 || | 
					
						
							|  |  |  | 			    gdbstub_read_byte(pc + 3, ((u8 *) &x) + 2) < 0 || | 
					
						
							|  |  |  | 			    gdbstub_read_byte(pc + 4, ((u8 *) &x) + 3) < 0) | 
					
						
							|  |  |  | 				goto fault; | 
					
						
							|  |  |  | 			if (!__gdbstub_mark_bp(pc + (s32) x, 0)) | 
					
						
							|  |  |  | 				goto fault; | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			/* RETF */ | 
					
						
							|  |  |  | 		case 0xde: | 
					
						
							|  |  |  | 			if (!__gdbstub_mark_bp((u8 *) regs->mdr, 0)) | 
					
						
							|  |  |  | 				goto fault; | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			/* RET */ | 
					
						
							|  |  |  | 		case 0xdf: | 
					
						
							|  |  |  | 			if (gdbstub_read_byte(pc + 2, (u8 *) &x) < 0) | 
					
						
							|  |  |  | 				goto fault; | 
					
						
							|  |  |  | 			sp += (s8)x; | 
					
						
							|  |  |  | 			if (gdbstub_read_byte(sp + 0, ((u8 *) &x) + 0) < 0 || | 
					
						
							|  |  |  | 			    gdbstub_read_byte(sp + 1, ((u8 *) &x) + 1) < 0 || | 
					
						
							|  |  |  | 			    gdbstub_read_byte(sp + 2, ((u8 *) &x) + 2) < 0 || | 
					
						
							|  |  |  | 			    gdbstub_read_byte(sp + 3, ((u8 *) &x) + 3) < 0) | 
					
						
							|  |  |  | 				goto fault; | 
					
						
							|  |  |  | 			if (!__gdbstub_mark_bp((u8 *) x, 0)) | 
					
						
							|  |  |  | 				goto fault; | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		case 0xf0: | 
					
						
							|  |  |  | 			if (gdbstub_read_byte(pc + 1, &cur) < 0) | 
					
						
							|  |  |  | 				goto fault; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if (cur >= 0xf0 && cur <= 0xf7) { | 
					
						
							|  |  |  | 				/* JMP (An) / CALLS (An) */ | 
					
						
							|  |  |  | 				switch (cur & 3) { | 
					
						
							|  |  |  | 				case 0: x = regs->a0; break; | 
					
						
							|  |  |  | 				case 1: x = regs->a1; break; | 
					
						
							|  |  |  | 				case 2: x = regs->a2; break; | 
					
						
							|  |  |  | 				case 3: x = regs->a3; break; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				if (!__gdbstub_mark_bp((u8 *) x, 0)) | 
					
						
							|  |  |  | 					goto fault; | 
					
						
							|  |  |  | 			} else if (cur == 0xfc) { | 
					
						
							|  |  |  | 				/* RETS */ | 
					
						
							|  |  |  | 				if (gdbstub_read_byte( | 
					
						
							|  |  |  | 					    sp + 0, ((u8 *) &x) + 0) < 0 || | 
					
						
							|  |  |  | 				    gdbstub_read_byte( | 
					
						
							|  |  |  | 					    sp + 1, ((u8 *) &x) + 1) < 0 || | 
					
						
							|  |  |  | 				    gdbstub_read_byte( | 
					
						
							|  |  |  | 					    sp + 2, ((u8 *) &x) + 2) < 0 || | 
					
						
							|  |  |  | 				    gdbstub_read_byte( | 
					
						
							|  |  |  | 					    sp + 3, ((u8 *) &x) + 3) < 0) | 
					
						
							|  |  |  | 					goto fault; | 
					
						
							|  |  |  | 				if (!__gdbstub_mark_bp((u8 *) x, 0)) | 
					
						
							|  |  |  | 					goto fault; | 
					
						
							|  |  |  | 			} else if (cur == 0xfd) { | 
					
						
							|  |  |  | 				/* RTI */ | 
					
						
							|  |  |  | 				if (gdbstub_read_byte( | 
					
						
							|  |  |  | 					    sp + 4, ((u8 *) &x) + 0) < 0 || | 
					
						
							|  |  |  | 				    gdbstub_read_byte( | 
					
						
							|  |  |  | 					    sp + 5, ((u8 *) &x) + 1) < 0 || | 
					
						
							|  |  |  | 				    gdbstub_read_byte( | 
					
						
							|  |  |  | 					    sp + 6, ((u8 *) &x) + 2) < 0 || | 
					
						
							|  |  |  | 				    gdbstub_read_byte( | 
					
						
							|  |  |  | 					    sp + 7, ((u8 *) &x) + 3) < 0) | 
					
						
							|  |  |  | 					goto fault; | 
					
						
							|  |  |  | 				if (!__gdbstub_mark_bp((u8 *) x, 0)) | 
					
						
							|  |  |  | 					goto fault; | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				if (!__gdbstub_mark_bp(pc + 2, 0)) | 
					
						
							|  |  |  | 					goto fault; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			/* potential 3-byte conditional branches */ | 
					
						
							|  |  |  | 		case 0xf8: | 
					
						
							|  |  |  | 			if (gdbstub_read_byte(pc + 1, &cur) < 0) | 
					
						
							|  |  |  | 				goto fault; | 
					
						
							|  |  |  | 			if (!__gdbstub_mark_bp(pc + 3, 0)) | 
					
						
							|  |  |  | 				goto fault; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if (cur >= 0xe8 && cur <= 0xeb) { | 
					
						
							|  |  |  | 				if (gdbstub_read_byte( | 
					
						
							|  |  |  | 					    pc + 2, ((u8 *) &x) + 0) < 0) | 
					
						
							|  |  |  | 					goto fault; | 
					
						
							|  |  |  | 				if ((x < 0 || x > 3) && | 
					
						
							|  |  |  | 				    !__gdbstub_mark_bp(pc + (s8) x, 1)) | 
					
						
							|  |  |  | 					goto fault; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		case 0xfa: | 
					
						
							|  |  |  | 			if (gdbstub_read_byte(pc + 1, &cur) < 0) | 
					
						
							|  |  |  | 				goto fault; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if (cur == 0xff) { | 
					
						
							|  |  |  | 				/* CALLS (d16,PC) */ | 
					
						
							|  |  |  | 				if (gdbstub_read_byte( | 
					
						
							|  |  |  | 					    pc + 2, ((u8 *) &x) + 0) < 0 || | 
					
						
							|  |  |  | 				    gdbstub_read_byte( | 
					
						
							|  |  |  | 					    pc + 3, ((u8 *) &x) + 1) < 0) | 
					
						
							|  |  |  | 					goto fault; | 
					
						
							|  |  |  | 				if (!__gdbstub_mark_bp(pc + (s16) x, 0)) | 
					
						
							|  |  |  | 					goto fault; | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				if (!__gdbstub_mark_bp(pc + 4, 0)) | 
					
						
							|  |  |  | 					goto fault; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		case 0xfc: | 
					
						
							|  |  |  | 			if (gdbstub_read_byte(pc + 1, &cur) < 0) | 
					
						
							|  |  |  | 				goto fault; | 
					
						
							|  |  |  | 			if (cur == 0xff) { | 
					
						
							|  |  |  | 				/* CALLS (d32,PC) */ | 
					
						
							|  |  |  | 				if (gdbstub_read_byte( | 
					
						
							|  |  |  | 					    pc + 2, ((u8 *) &x) + 0) < 0 || | 
					
						
							|  |  |  | 				    gdbstub_read_byte( | 
					
						
							|  |  |  | 					    pc + 3, ((u8 *) &x) + 1) < 0 || | 
					
						
							|  |  |  | 				    gdbstub_read_byte( | 
					
						
							|  |  |  | 					    pc + 4, ((u8 *) &x) + 2) < 0 || | 
					
						
							|  |  |  | 				    gdbstub_read_byte( | 
					
						
							|  |  |  | 					    pc + 5, ((u8 *) &x) + 3) < 0) | 
					
						
							|  |  |  | 					goto fault; | 
					
						
							|  |  |  | 				if (!__gdbstub_mark_bp( | 
					
						
							|  |  |  | 					    pc + (s32) x, 0)) | 
					
						
							|  |  |  | 					goto fault; | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				if (!__gdbstub_mark_bp( | 
					
						
							|  |  |  | 					    pc + 6, 0)) | 
					
						
							|  |  |  | 					goto fault; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	gdbstub_bkpt("Step: %02x at %p; %02x at %p\n", | 
					
						
							|  |  |  | 		     step_bp[0].opcode[0], step_bp[0].addr, | 
					
						
							|  |  |  | 		     step_bp[1].opcode[0], step_bp[1].addr); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (step_bp[0].addr) { | 
					
						
							|  |  |  | #ifdef GDBSTUB_USE_F7F7_AS_BREAKPOINT
 | 
					
						
							|  |  |  | 		if (gdbstub_write_byte(0xF7, step_bp[0].addr + 0) < 0 || | 
					
						
							|  |  |  | 		    gdbstub_write_byte(0xF7, step_bp[0].addr + 1) < 0) | 
					
						
							|  |  |  | 			goto fault; | 
					
						
							|  |  |  | #else
 | 
					
						
							|  |  |  | 		if (gdbstub_write_byte(0xFF, step_bp[0].addr + 0) < 0) | 
					
						
							|  |  |  | 			goto fault; | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (step_bp[1].addr) { | 
					
						
							|  |  |  | #ifdef GDBSTUB_USE_F7F7_AS_BREAKPOINT
 | 
					
						
							|  |  |  | 		if (gdbstub_write_byte(0xF7, step_bp[1].addr + 0) < 0 || | 
					
						
							|  |  |  | 		    gdbstub_write_byte(0xF7, step_bp[1].addr + 1) < 0) | 
					
						
							|  |  |  | 			goto fault; | 
					
						
							|  |  |  | #else
 | 
					
						
							|  |  |  | 		if (gdbstub_write_byte(0xFF, step_bp[1].addr + 0) < 0) | 
					
						
							|  |  |  | 			goto fault; | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |  fault: | 
					
						
							|  |  |  | 	/* uh-oh - silly address alert, try and restore things */ | 
					
						
							|  |  |  | 	__gdbstub_restore_bp(); | 
					
						
							|  |  |  | 	return -EFAULT; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2011-03-18 16:54:29 +00:00
										 |  |  | #endif /* CONFIG_GDBSTUB_ALLOW_SINGLE_STEP */
 | 
					
						
							| 
									
										
										
										
											2008-02-08 04:19:31 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  | #ifdef CONFIG_GDBSTUB_CONSOLE
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void gdbstub_console_write(struct console *con, const char *p, unsigned n) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	static const char gdbstub_cr[] = { 0x0d }; | 
					
						
							|  |  |  | 	char outbuf[26]; | 
					
						
							|  |  |  | 	int qty; | 
					
						
							|  |  |  | 	u8 busy; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	busy = gdbstub_busy; | 
					
						
							|  |  |  | 	gdbstub_busy = 1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	outbuf[0] = 'O'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	while (n > 0) { | 
					
						
							|  |  |  | 		qty = 1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		while (n > 0 && qty < 20) { | 
					
						
							|  |  |  | 			mem2hex(p, outbuf + qty, 2, 0); | 
					
						
							|  |  |  | 			qty += 2; | 
					
						
							|  |  |  | 			if (*p == 0x0a) { | 
					
						
							|  |  |  | 				mem2hex(gdbstub_cr, outbuf + qty, 2, 0); | 
					
						
							|  |  |  | 				qty += 2; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			p++; | 
					
						
							|  |  |  | 			n--; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		outbuf[qty] = 0; | 
					
						
							|  |  |  | 		putpacket(outbuf); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	gdbstub_busy = busy; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static kdev_t gdbstub_console_dev(struct console *con) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return MKDEV(1, 3); /* /dev/null */ | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct console gdbstub_console = { | 
					
						
							|  |  |  | 	.name	= "gdb", | 
					
						
							|  |  |  | 	.write	= gdbstub_console_write, | 
					
						
							|  |  |  | 	.device	= gdbstub_console_dev, | 
					
						
							|  |  |  | 	.flags	= CON_PRINTBUFFER, | 
					
						
							|  |  |  | 	.index	= -1, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * Convert the memory pointed to by mem into hex, placing result in buf. | 
					
						
							|  |  |  |  * - if successful, return a pointer to the last char put in buf (NUL) | 
					
						
							|  |  |  |  * - in case of mem fault, return NULL | 
					
						
							|  |  |  |  * may_fault is non-zero if we are reading from arbitrary memory, but is | 
					
						
							|  |  |  |  * currently not used. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static | 
					
						
							|  |  |  | unsigned char *mem2hex(const void *_mem, char *buf, int count, int may_fault) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	const u8 *mem = _mem; | 
					
						
							|  |  |  | 	u8 ch[4]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if ((u32) mem & 1 && count >= 1) { | 
					
						
							|  |  |  | 		if (gdbstub_read_byte(mem, ch) != 0) | 
					
						
							|  |  |  | 			return 0; | 
					
						
							| 
									
										
										
										
											2011-10-31 17:12:51 -07:00
										 |  |  | 		buf = hex_byte_pack(buf, ch[0]); | 
					
						
							| 
									
										
										
										
											2008-02-08 04:19:31 -08:00
										 |  |  | 		mem++; | 
					
						
							|  |  |  | 		count--; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if ((u32) mem & 3 && count >= 2) { | 
					
						
							|  |  |  | 		if (gdbstub_read_word(mem, ch) != 0) | 
					
						
							|  |  |  | 			return 0; | 
					
						
							| 
									
										
										
										
											2011-10-31 17:12:51 -07:00
										 |  |  | 		buf = hex_byte_pack(buf, ch[0]); | 
					
						
							|  |  |  | 		buf = hex_byte_pack(buf, ch[1]); | 
					
						
							| 
									
										
										
										
											2008-02-08 04:19:31 -08:00
										 |  |  | 		mem += 2; | 
					
						
							|  |  |  | 		count -= 2; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	while (count >= 4) { | 
					
						
							|  |  |  | 		if (gdbstub_read_dword(mem, ch) != 0) | 
					
						
							|  |  |  | 			return 0; | 
					
						
							| 
									
										
										
										
											2011-10-31 17:12:51 -07:00
										 |  |  | 		buf = hex_byte_pack(buf, ch[0]); | 
					
						
							|  |  |  | 		buf = hex_byte_pack(buf, ch[1]); | 
					
						
							|  |  |  | 		buf = hex_byte_pack(buf, ch[2]); | 
					
						
							|  |  |  | 		buf = hex_byte_pack(buf, ch[3]); | 
					
						
							| 
									
										
										
										
											2008-02-08 04:19:31 -08:00
										 |  |  | 		mem += 4; | 
					
						
							|  |  |  | 		count -= 4; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (count >= 2) { | 
					
						
							|  |  |  | 		if (gdbstub_read_word(mem, ch) != 0) | 
					
						
							|  |  |  | 			return 0; | 
					
						
							| 
									
										
										
										
											2011-10-31 17:12:51 -07:00
										 |  |  | 		buf = hex_byte_pack(buf, ch[0]); | 
					
						
							|  |  |  | 		buf = hex_byte_pack(buf, ch[1]); | 
					
						
							| 
									
										
										
										
											2008-02-08 04:19:31 -08:00
										 |  |  | 		mem += 2; | 
					
						
							|  |  |  | 		count -= 2; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (count >= 1) { | 
					
						
							|  |  |  | 		if (gdbstub_read_byte(mem, ch) != 0) | 
					
						
							|  |  |  | 			return 0; | 
					
						
							| 
									
										
										
										
											2011-10-31 17:12:51 -07:00
										 |  |  | 		buf = hex_byte_pack(buf, ch[0]); | 
					
						
							| 
									
										
										
										
											2008-02-08 04:19:31 -08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	*buf = 0; | 
					
						
							|  |  |  | 	return buf; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * convert the hex array pointed to by buf into binary to be placed in mem | 
					
						
							|  |  |  |  * return a pointer to the character AFTER the last byte written | 
					
						
							|  |  |  |  * may_fault is non-zero if we are reading from arbitrary memory, but is | 
					
						
							|  |  |  |  * currently not used. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static | 
					
						
							|  |  |  | const char *hex2mem(const char *buf, void *_mem, int count, int may_fault) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	u8 *mem = _mem; | 
					
						
							|  |  |  | 	union { | 
					
						
							|  |  |  | 		u32 val; | 
					
						
							|  |  |  | 		u8 b[4]; | 
					
						
							|  |  |  | 	} ch; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if ((u32) mem & 1 && count >= 1) { | 
					
						
							|  |  |  | 		ch.b[0]  = hex(*buf++) << 4; | 
					
						
							|  |  |  | 		ch.b[0] |= hex(*buf++); | 
					
						
							|  |  |  | 		if (gdbstub_write_byte(ch.val, mem) != 0) | 
					
						
							|  |  |  | 			return 0; | 
					
						
							|  |  |  | 		mem++; | 
					
						
							|  |  |  | 		count--; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if ((u32) mem & 3 && count >= 2) { | 
					
						
							|  |  |  | 		ch.b[0]  = hex(*buf++) << 4; | 
					
						
							|  |  |  | 		ch.b[0] |= hex(*buf++); | 
					
						
							|  |  |  | 		ch.b[1]  = hex(*buf++) << 4; | 
					
						
							|  |  |  | 		ch.b[1] |= hex(*buf++); | 
					
						
							|  |  |  | 		if (gdbstub_write_word(ch.val, mem) != 0) | 
					
						
							|  |  |  | 			return 0; | 
					
						
							|  |  |  | 		mem += 2; | 
					
						
							|  |  |  | 		count -= 2; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	while (count >= 4) { | 
					
						
							|  |  |  | 		ch.b[0]  = hex(*buf++) << 4; | 
					
						
							|  |  |  | 		ch.b[0] |= hex(*buf++); | 
					
						
							|  |  |  | 		ch.b[1]  = hex(*buf++) << 4; | 
					
						
							|  |  |  | 		ch.b[1] |= hex(*buf++); | 
					
						
							|  |  |  | 		ch.b[2]  = hex(*buf++) << 4; | 
					
						
							|  |  |  | 		ch.b[2] |= hex(*buf++); | 
					
						
							|  |  |  | 		ch.b[3]  = hex(*buf++) << 4; | 
					
						
							|  |  |  | 		ch.b[3] |= hex(*buf++); | 
					
						
							|  |  |  | 		if (gdbstub_write_dword(ch.val, mem) != 0) | 
					
						
							|  |  |  | 			return 0; | 
					
						
							|  |  |  | 		mem += 4; | 
					
						
							|  |  |  | 		count -= 4; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (count >= 2) { | 
					
						
							|  |  |  | 		ch.b[0]  = hex(*buf++) << 4; | 
					
						
							|  |  |  | 		ch.b[0] |= hex(*buf++); | 
					
						
							|  |  |  | 		ch.b[1]  = hex(*buf++) << 4; | 
					
						
							|  |  |  | 		ch.b[1] |= hex(*buf++); | 
					
						
							|  |  |  | 		if (gdbstub_write_word(ch.val, mem) != 0) | 
					
						
							|  |  |  | 			return 0; | 
					
						
							|  |  |  | 		mem += 2; | 
					
						
							|  |  |  | 		count -= 2; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (count >= 1) { | 
					
						
							|  |  |  | 		ch.b[0]  = hex(*buf++) << 4; | 
					
						
							|  |  |  | 		ch.b[0] |= hex(*buf++); | 
					
						
							|  |  |  | 		if (gdbstub_write_byte(ch.val, mem) != 0) | 
					
						
							|  |  |  | 			return 0; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return buf; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * This table contains the mapping between MN10300 exception codes, and | 
					
						
							|  |  |  |  * signals, which are primarily what GDB understands.  It also indicates | 
					
						
							|  |  |  |  * which hardware traps we need to commandeer when initializing the stub. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static const struct excep_to_sig_map { | 
					
						
							|  |  |  | 	enum exception_code	excep;	/* MN10300 exception code */ | 
					
						
							|  |  |  | 	unsigned char		signo;	/* Signal that we map this into */ | 
					
						
							|  |  |  | } excep_to_sig_map[] = { | 
					
						
							|  |  |  | 	{ EXCEP_ITLBMISS,	SIGSEGV		}, | 
					
						
							|  |  |  | 	{ EXCEP_DTLBMISS,	SIGSEGV		}, | 
					
						
							|  |  |  | 	{ EXCEP_TRAP,		SIGTRAP		}, | 
					
						
							|  |  |  | 	{ EXCEP_ISTEP,		SIGTRAP		}, | 
					
						
							|  |  |  | 	{ EXCEP_IBREAK,		SIGTRAP		}, | 
					
						
							|  |  |  | 	{ EXCEP_OBREAK,		SIGTRAP		}, | 
					
						
							|  |  |  | 	{ EXCEP_UNIMPINS,	SIGILL		}, | 
					
						
							|  |  |  | 	{ EXCEP_UNIMPEXINS,	SIGILL		}, | 
					
						
							|  |  |  | 	{ EXCEP_MEMERR,		SIGSEGV		}, | 
					
						
							|  |  |  | 	{ EXCEP_MISALIGN,	SIGSEGV		}, | 
					
						
							|  |  |  | 	{ EXCEP_BUSERROR,	SIGBUS		}, | 
					
						
							|  |  |  | 	{ EXCEP_ILLINSACC,	SIGSEGV		}, | 
					
						
							|  |  |  | 	{ EXCEP_ILLDATACC,	SIGSEGV		}, | 
					
						
							|  |  |  | 	{ EXCEP_IOINSACC,	SIGSEGV		}, | 
					
						
							|  |  |  | 	{ EXCEP_PRIVINSACC,	SIGSEGV		}, | 
					
						
							|  |  |  | 	{ EXCEP_PRIVDATACC,	SIGSEGV		}, | 
					
						
							|  |  |  | 	{ EXCEP_FPU_DISABLED,	SIGFPE		}, | 
					
						
							|  |  |  | 	{ EXCEP_FPU_UNIMPINS,	SIGFPE		}, | 
					
						
							|  |  |  | 	{ EXCEP_FPU_OPERATION,	SIGFPE		}, | 
					
						
							|  |  |  | 	{ EXCEP_WDT,		SIGALRM		}, | 
					
						
							|  |  |  | 	{ EXCEP_NMI,		SIGQUIT		}, | 
					
						
							|  |  |  | 	{ EXCEP_IRQ_LEVEL0,	SIGINT		}, | 
					
						
							|  |  |  | 	{ EXCEP_IRQ_LEVEL1,	SIGINT		}, | 
					
						
							|  |  |  | 	{ EXCEP_IRQ_LEVEL2,	SIGINT		}, | 
					
						
							|  |  |  | 	{ EXCEP_IRQ_LEVEL3,	SIGINT		}, | 
					
						
							|  |  |  | 	{ EXCEP_IRQ_LEVEL4,	SIGINT		}, | 
					
						
							|  |  |  | 	{ EXCEP_IRQ_LEVEL5,	SIGINT		}, | 
					
						
							|  |  |  | 	{ EXCEP_IRQ_LEVEL6,	SIGINT		}, | 
					
						
							|  |  |  | 	{ 0, 0} | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * convert the MN10300 exception code into a UNIX signal number | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static int computeSignal(enum exception_code excep) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	const struct excep_to_sig_map *map; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for (map = excep_to_sig_map; map->signo; map++) | 
					
						
							|  |  |  | 		if (map->excep == excep) | 
					
						
							|  |  |  | 			return map->signo; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return SIGHUP; /* default for things we don't know about */ | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static u32 gdbstub_fpcr, gdbstub_fpufs_array[32]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static void gdbstub_store_fpu(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | #ifdef CONFIG_FPU
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	asm volatile( | 
					
						
							|  |  |  | 		"or %2,epsw\n" | 
					
						
							|  |  |  | #ifdef CONFIG_MN10300_PROC_MN103E010
 | 
					
						
							|  |  |  | 		"nop\n" | 
					
						
							|  |  |  | 		"nop\n" | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 		"mov %1, a1\n" | 
					
						
							|  |  |  | 		"fmov fs0,  (a1+)\n" | 
					
						
							|  |  |  | 		"fmov fs1,  (a1+)\n" | 
					
						
							|  |  |  | 		"fmov fs2,  (a1+)\n" | 
					
						
							|  |  |  | 		"fmov fs3,  (a1+)\n" | 
					
						
							|  |  |  | 		"fmov fs4,  (a1+)\n" | 
					
						
							|  |  |  | 		"fmov fs5,  (a1+)\n" | 
					
						
							|  |  |  | 		"fmov fs6,  (a1+)\n" | 
					
						
							|  |  |  | 		"fmov fs7,  (a1+)\n" | 
					
						
							|  |  |  | 		"fmov fs8,  (a1+)\n" | 
					
						
							|  |  |  | 		"fmov fs9,  (a1+)\n" | 
					
						
							|  |  |  | 		"fmov fs10, (a1+)\n" | 
					
						
							|  |  |  | 		"fmov fs11, (a1+)\n" | 
					
						
							|  |  |  | 		"fmov fs12, (a1+)\n" | 
					
						
							|  |  |  | 		"fmov fs13, (a1+)\n" | 
					
						
							|  |  |  | 		"fmov fs14, (a1+)\n" | 
					
						
							|  |  |  | 		"fmov fs15, (a1+)\n" | 
					
						
							|  |  |  | 		"fmov fs16, (a1+)\n" | 
					
						
							|  |  |  | 		"fmov fs17, (a1+)\n" | 
					
						
							|  |  |  | 		"fmov fs18, (a1+)\n" | 
					
						
							|  |  |  | 		"fmov fs19, (a1+)\n" | 
					
						
							|  |  |  | 		"fmov fs20, (a1+)\n" | 
					
						
							|  |  |  | 		"fmov fs21, (a1+)\n" | 
					
						
							|  |  |  | 		"fmov fs22, (a1+)\n" | 
					
						
							|  |  |  | 		"fmov fs23, (a1+)\n" | 
					
						
							|  |  |  | 		"fmov fs24, (a1+)\n" | 
					
						
							|  |  |  | 		"fmov fs25, (a1+)\n" | 
					
						
							|  |  |  | 		"fmov fs26, (a1+)\n" | 
					
						
							|  |  |  | 		"fmov fs27, (a1+)\n" | 
					
						
							|  |  |  | 		"fmov fs28, (a1+)\n" | 
					
						
							|  |  |  | 		"fmov fs29, (a1+)\n" | 
					
						
							|  |  |  | 		"fmov fs30, (a1+)\n" | 
					
						
							|  |  |  | 		"fmov fs31, (a1+)\n" | 
					
						
							|  |  |  | 		"fmov fpcr, %0\n" | 
					
						
							|  |  |  | 		: "=d"(gdbstub_fpcr) | 
					
						
							|  |  |  | 		: "g" (&gdbstub_fpufs_array), "i"(EPSW_FE) | 
					
						
							|  |  |  | 		: "a1" | 
					
						
							|  |  |  | 		); | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static void gdbstub_load_fpu(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | #ifdef CONFIG_FPU
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	asm volatile( | 
					
						
							|  |  |  | 		"or %1,epsw\n" | 
					
						
							|  |  |  | #ifdef CONFIG_MN10300_PROC_MN103E010
 | 
					
						
							|  |  |  | 		"nop\n" | 
					
						
							|  |  |  | 		"nop\n" | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 		"mov %0, a1\n" | 
					
						
							|  |  |  | 		"fmov (a1+), fs0\n" | 
					
						
							|  |  |  | 		"fmov (a1+), fs1\n" | 
					
						
							|  |  |  | 		"fmov (a1+), fs2\n" | 
					
						
							|  |  |  | 		"fmov (a1+), fs3\n" | 
					
						
							|  |  |  | 		"fmov (a1+), fs4\n" | 
					
						
							|  |  |  | 		"fmov (a1+), fs5\n" | 
					
						
							|  |  |  | 		"fmov (a1+), fs6\n" | 
					
						
							|  |  |  | 		"fmov (a1+), fs7\n" | 
					
						
							|  |  |  | 		"fmov (a1+), fs8\n" | 
					
						
							|  |  |  | 		"fmov (a1+), fs9\n" | 
					
						
							|  |  |  | 		"fmov (a1+), fs10\n" | 
					
						
							|  |  |  | 		"fmov (a1+), fs11\n" | 
					
						
							|  |  |  | 		"fmov (a1+), fs12\n" | 
					
						
							|  |  |  | 		"fmov (a1+), fs13\n" | 
					
						
							|  |  |  | 		"fmov (a1+), fs14\n" | 
					
						
							|  |  |  | 		"fmov (a1+), fs15\n" | 
					
						
							|  |  |  | 		"fmov (a1+), fs16\n" | 
					
						
							|  |  |  | 		"fmov (a1+), fs17\n" | 
					
						
							|  |  |  | 		"fmov (a1+), fs18\n" | 
					
						
							|  |  |  | 		"fmov (a1+), fs19\n" | 
					
						
							|  |  |  | 		"fmov (a1+), fs20\n" | 
					
						
							|  |  |  | 		"fmov (a1+), fs21\n" | 
					
						
							|  |  |  | 		"fmov (a1+), fs22\n" | 
					
						
							|  |  |  | 		"fmov (a1+), fs23\n" | 
					
						
							|  |  |  | 		"fmov (a1+), fs24\n" | 
					
						
							|  |  |  | 		"fmov (a1+), fs25\n" | 
					
						
							|  |  |  | 		"fmov (a1+), fs26\n" | 
					
						
							|  |  |  | 		"fmov (a1+), fs27\n" | 
					
						
							|  |  |  | 		"fmov (a1+), fs28\n" | 
					
						
							|  |  |  | 		"fmov (a1+), fs29\n" | 
					
						
							|  |  |  | 		"fmov (a1+), fs30\n" | 
					
						
							|  |  |  | 		"fmov (a1+), fs31\n" | 
					
						
							|  |  |  | 		"fmov %2, fpcr\n" | 
					
						
							|  |  |  | 		: | 
					
						
							|  |  |  | 		: "g" (&gdbstub_fpufs_array), "i"(EPSW_FE), "d"(gdbstub_fpcr) | 
					
						
							|  |  |  | 		: "a1" | 
					
						
							|  |  |  | 	); | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * set a software breakpoint | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | int gdbstub_set_breakpoint(u8 *addr, int len) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int bkpt, loop, xloop; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #ifdef GDBSTUB_USE_F7F7_AS_BREAKPOINT
 | 
					
						
							|  |  |  | 	len = (len + 1) & ~1; | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	gdbstub_bkpt("setbkpt(%p,%d)\n", addr, len); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for (bkpt = 255; bkpt >= 0; bkpt--) | 
					
						
							|  |  |  | 		if (!gdbstub_bkpts[bkpt].addr) | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 	if (bkpt < 0) | 
					
						
							|  |  |  | 		return -ENOSPC; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for (loop = 0; loop < len; loop++) | 
					
						
							|  |  |  | 		if (gdbstub_read_byte(&addr[loop], | 
					
						
							|  |  |  | 				      &gdbstub_bkpts[bkpt].origbytes[loop] | 
					
						
							|  |  |  | 				      ) < 0) | 
					
						
							|  |  |  | 			return -EFAULT; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	gdbstub_flush_caches = 1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #ifdef GDBSTUB_USE_F7F7_AS_BREAKPOINT
 | 
					
						
							|  |  |  | 	for (loop = 0; loop < len; loop++) | 
					
						
							|  |  |  | 		if (gdbstub_write_byte(0xF7, &addr[loop]) < 0) | 
					
						
							|  |  |  | 			goto restore; | 
					
						
							|  |  |  | #else
 | 
					
						
							|  |  |  | 	for (loop = 0; loop < len; loop++) | 
					
						
							|  |  |  | 		if (gdbstub_write_byte(0xFF, &addr[loop]) < 0) | 
					
						
							|  |  |  | 			goto restore; | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	gdbstub_bkpts[bkpt].addr = addr; | 
					
						
							|  |  |  | 	gdbstub_bkpts[bkpt].len = len; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	gdbstub_bkpt("Set BKPT[%02x]: %p-%p {%02x%02x%02x%02x%02x%02x%02x}\n", | 
					
						
							|  |  |  | 		     bkpt, | 
					
						
							|  |  |  | 		     gdbstub_bkpts[bkpt].addr, | 
					
						
							|  |  |  | 		     gdbstub_bkpts[bkpt].addr + gdbstub_bkpts[bkpt].len - 1, | 
					
						
							|  |  |  | 		     gdbstub_bkpts[bkpt].origbytes[0], | 
					
						
							|  |  |  | 		     gdbstub_bkpts[bkpt].origbytes[1], | 
					
						
							|  |  |  | 		     gdbstub_bkpts[bkpt].origbytes[2], | 
					
						
							|  |  |  | 		     gdbstub_bkpts[bkpt].origbytes[3], | 
					
						
							|  |  |  | 		     gdbstub_bkpts[bkpt].origbytes[4], | 
					
						
							|  |  |  | 		     gdbstub_bkpts[bkpt].origbytes[5], | 
					
						
							|  |  |  | 		     gdbstub_bkpts[bkpt].origbytes[6] | 
					
						
							|  |  |  | 		     ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | restore: | 
					
						
							|  |  |  | 	for (xloop = 0; xloop < loop; xloop++) | 
					
						
							|  |  |  | 		gdbstub_write_byte(gdbstub_bkpts[bkpt].origbytes[xloop], | 
					
						
							|  |  |  | 				   addr + xloop); | 
					
						
							|  |  |  | 	return -EFAULT; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * clear a software breakpoint | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | int gdbstub_clear_breakpoint(u8 *addr, int len) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int bkpt, loop; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #ifdef GDBSTUB_USE_F7F7_AS_BREAKPOINT
 | 
					
						
							|  |  |  | 	len = (len + 1) & ~1; | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	gdbstub_bkpt("clearbkpt(%p,%d)\n", addr, len); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for (bkpt = 255; bkpt >= 0; bkpt--) | 
					
						
							|  |  |  | 		if (gdbstub_bkpts[bkpt].addr == addr && | 
					
						
							|  |  |  | 		    gdbstub_bkpts[bkpt].len == len) | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 	if (bkpt < 0) | 
					
						
							|  |  |  | 		return -ENOENT; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	gdbstub_bkpts[bkpt].addr = NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	gdbstub_flush_caches = 1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for (loop = 0; loop < len; loop++) | 
					
						
							|  |  |  | 		if (gdbstub_write_byte(gdbstub_bkpts[bkpt].origbytes[loop], | 
					
						
							|  |  |  | 				       addr + loop) < 0) | 
					
						
							|  |  |  | 			return -EFAULT; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * This function does all command processing for interfacing to gdb | 
					
						
							| 
									
										
										
										
											2011-03-18 16:54:30 +00:00
										 |  |  |  * - returns 0 if the exception should be skipped, -ERROR otherwise. | 
					
						
							| 
									
										
										
										
											2008-02-08 04:19:31 -08:00
										 |  |  |  */ | 
					
						
							|  |  |  | static int gdbstub(struct pt_regs *regs, enum exception_code excep) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	unsigned long *stack; | 
					
						
							|  |  |  | 	unsigned long epsw, mdr; | 
					
						
							|  |  |  | 	uint32_t zero, ssp; | 
					
						
							|  |  |  | 	uint8_t broke; | 
					
						
							|  |  |  | 	char *ptr; | 
					
						
							|  |  |  | 	int sigval; | 
					
						
							|  |  |  | 	int addr; | 
					
						
							|  |  |  | 	int length; | 
					
						
							|  |  |  | 	int loop; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (excep == EXCEP_FPU_DISABLED) | 
					
						
							| 
									
										
										
										
											2011-03-18 16:54:30 +00:00
										 |  |  | 		return -ENOTSUPP; | 
					
						
							| 
									
										
										
										
											2008-02-08 04:19:31 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	gdbstub_flush_caches = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	mn10300_set_gdbleds(1); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	asm volatile("mov mdr,%0" : "=d"(mdr)); | 
					
						
							| 
									
										
										
										
											2010-10-27 17:28:55 +01:00
										 |  |  | 	local_save_flags(epsw); | 
					
						
							| 
									
										
										
										
											2010-12-07 17:41:40 +00:00
										 |  |  | 	arch_local_change_intr_mask_level( | 
					
						
							| 
									
										
										
										
											2011-03-18 16:54:30 +00:00
										 |  |  | 		NUM2EPSW_IM(CONFIG_DEBUGGER_IRQ_LEVEL + 1)); | 
					
						
							| 
									
										
										
										
											2008-02-08 04:19:31 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	gdbstub_store_fpu(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #ifdef CONFIG_GDBSTUB_IMMEDIATE
 | 
					
						
							|  |  |  | 	/* skip the initial pause loop */ | 
					
						
							|  |  |  | 	if (regs->pc == (unsigned long) __gdbstub_pause) | 
					
						
							|  |  |  | 		regs->pc = (unsigned long) start_kernel; | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* if we were single stepping, restore the opcodes hoisted for the
 | 
					
						
							|  |  |  | 	 * breakpoint[s] */ | 
					
						
							|  |  |  | 	broke = 0; | 
					
						
							| 
									
										
										
										
											2011-03-18 16:54:29 +00:00
										 |  |  | #ifdef CONFIG_GDBSTUB_ALLOW_SINGLE_STEP
 | 
					
						
							| 
									
										
										
										
											2008-02-08 04:19:31 -08:00
										 |  |  | 	if ((step_bp[0].addr && step_bp[0].addr == (u8 *) regs->pc) || | 
					
						
							|  |  |  | 	    (step_bp[1].addr && step_bp[1].addr == (u8 *) regs->pc)) | 
					
						
							|  |  |  | 		broke = 1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	__gdbstub_restore_bp(); | 
					
						
							| 
									
										
										
										
											2011-03-18 16:54:29 +00:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2008-02-08 04:19:31 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (gdbstub_rx_unget) { | 
					
						
							|  |  |  | 		sigval = SIGINT; | 
					
						
							|  |  |  | 		if (gdbstub_rx_unget != 3) | 
					
						
							|  |  |  | 			goto packet_waiting; | 
					
						
							|  |  |  | 		gdbstub_rx_unget = 0; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	stack = (unsigned long *) regs->sp; | 
					
						
							|  |  |  | 	sigval = broke ? SIGTRAP : computeSignal(excep); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* send information about a BUG() */ | 
					
						
							|  |  |  | 	if (!user_mode(regs) && excep == EXCEP_SYSCALL15) { | 
					
						
							|  |  |  | 		const struct bug_entry *bug; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		bug = find_bug(regs->pc); | 
					
						
							|  |  |  | 		if (bug) | 
					
						
							|  |  |  | 			goto found_bug; | 
					
						
							|  |  |  | 		length = snprintf(trans_buffer, sizeof(trans_buffer), | 
					
						
							|  |  |  | 				  "BUG() at address %lx\n", regs->pc); | 
					
						
							|  |  |  | 		goto send_bug_pkt; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	found_bug: | 
					
						
							|  |  |  | 		length = snprintf(trans_buffer, sizeof(trans_buffer), | 
					
						
							|  |  |  | 				  "BUG() at address %lx (%s:%d)\n", | 
					
						
							|  |  |  | 				  regs->pc, bug->file, bug->line); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	send_bug_pkt: | 
					
						
							|  |  |  | 		ptr = output_buffer; | 
					
						
							|  |  |  | 		*ptr++ = 'O'; | 
					
						
							|  |  |  | 		ptr = mem2hex(trans_buffer, ptr, length, 0); | 
					
						
							|  |  |  | 		*ptr = 0; | 
					
						
							|  |  |  | 		putpacket(output_buffer); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		regs->pc -= 2; | 
					
						
							|  |  |  | 		sigval = SIGABRT; | 
					
						
							|  |  |  | 	} else if (regs->pc == (unsigned long) __gdbstub_bug_trap) { | 
					
						
							|  |  |  | 		regs->pc = regs->mdr; | 
					
						
							|  |  |  | 		sigval = SIGABRT; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/*
 | 
					
						
							|  |  |  | 	 * send a message to the debugger's user saying what happened if it may | 
					
						
							|  |  |  | 	 * not be clear cut (we can't map exceptions onto signals properly) | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	if (sigval != SIGINT && sigval != SIGTRAP && sigval != SIGILL) { | 
					
						
							|  |  |  | 		static const char title[] = "Excep ", tbcberr[] = "BCBERR "; | 
					
						
							|  |  |  | 		static const char crlf[] = "\r\n"; | 
					
						
							|  |  |  | 		char hx; | 
					
						
							|  |  |  | 		u32 bcberr = BCBERR; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		ptr = output_buffer; | 
					
						
							|  |  |  | 		*ptr++ = 'O'; | 
					
						
							|  |  |  | 		ptr = mem2hex(title, ptr, sizeof(title) - 1, 0); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-07-25 19:45:20 -07:00
										 |  |  | 		hx = hex_asc_hi(excep >> 8); | 
					
						
							| 
									
										
										
										
											2011-10-31 17:12:51 -07:00
										 |  |  | 		ptr = hex_byte_pack(ptr, hx); | 
					
						
							| 
									
										
										
										
											2008-07-25 19:45:20 -07:00
										 |  |  | 		hx = hex_asc_lo(excep >> 8); | 
					
						
							| 
									
										
										
										
											2011-10-31 17:12:51 -07:00
										 |  |  | 		ptr = hex_byte_pack(ptr, hx); | 
					
						
							| 
									
										
										
										
											2008-07-25 19:45:20 -07:00
										 |  |  | 		hx = hex_asc_hi(excep); | 
					
						
							| 
									
										
										
										
											2011-10-31 17:12:51 -07:00
										 |  |  | 		ptr = hex_byte_pack(ptr, hx); | 
					
						
							| 
									
										
										
										
											2008-07-25 19:45:20 -07:00
										 |  |  | 		hx = hex_asc_lo(excep); | 
					
						
							| 
									
										
										
										
											2011-10-31 17:12:51 -07:00
										 |  |  | 		ptr = hex_byte_pack(ptr, hx); | 
					
						
							| 
									
										
										
										
											2008-02-08 04:19:31 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		ptr = mem2hex(crlf, ptr, sizeof(crlf) - 1, 0); | 
					
						
							|  |  |  | 		*ptr = 0; | 
					
						
							|  |  |  | 		putpacket(output_buffer);	/* send it off... */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/* BCBERR */ | 
					
						
							|  |  |  | 		ptr = output_buffer; | 
					
						
							|  |  |  | 		*ptr++ = 'O'; | 
					
						
							|  |  |  | 		ptr = mem2hex(tbcberr, ptr, sizeof(tbcberr) - 1, 0); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-07-25 19:45:20 -07:00
										 |  |  | 		hx = hex_asc_hi(bcberr >> 24); | 
					
						
							| 
									
										
										
										
											2011-10-31 17:12:51 -07:00
										 |  |  | 		ptr = hex_byte_pack(ptr, hx); | 
					
						
							| 
									
										
										
										
											2008-07-25 19:45:20 -07:00
										 |  |  | 		hx = hex_asc_lo(bcberr >> 24); | 
					
						
							| 
									
										
										
										
											2011-10-31 17:12:51 -07:00
										 |  |  | 		ptr = hex_byte_pack(ptr, hx); | 
					
						
							| 
									
										
										
										
											2008-07-25 19:45:20 -07:00
										 |  |  | 		hx = hex_asc_hi(bcberr >> 16); | 
					
						
							| 
									
										
										
										
											2011-10-31 17:12:51 -07:00
										 |  |  | 		ptr = hex_byte_pack(ptr, hx); | 
					
						
							| 
									
										
										
										
											2008-07-25 19:45:20 -07:00
										 |  |  | 		hx = hex_asc_lo(bcberr >> 16); | 
					
						
							| 
									
										
										
										
											2011-10-31 17:12:51 -07:00
										 |  |  | 		ptr = hex_byte_pack(ptr, hx); | 
					
						
							| 
									
										
										
										
											2008-07-25 19:45:20 -07:00
										 |  |  | 		hx = hex_asc_hi(bcberr >> 8); | 
					
						
							| 
									
										
										
										
											2011-10-31 17:12:51 -07:00
										 |  |  | 		ptr = hex_byte_pack(ptr, hx); | 
					
						
							| 
									
										
										
										
											2008-07-25 19:45:20 -07:00
										 |  |  | 		hx = hex_asc_lo(bcberr >> 8); | 
					
						
							| 
									
										
										
										
											2011-10-31 17:12:51 -07:00
										 |  |  | 		ptr = hex_byte_pack(ptr, hx); | 
					
						
							| 
									
										
										
										
											2008-07-25 19:45:20 -07:00
										 |  |  | 		hx = hex_asc_hi(bcberr); | 
					
						
							| 
									
										
										
										
											2011-10-31 17:12:51 -07:00
										 |  |  | 		ptr = hex_byte_pack(ptr, hx); | 
					
						
							| 
									
										
										
										
											2008-07-25 19:45:20 -07:00
										 |  |  | 		hx = hex_asc_lo(bcberr); | 
					
						
							| 
									
										
										
										
											2011-10-31 17:12:51 -07:00
										 |  |  | 		ptr = hex_byte_pack(ptr, hx); | 
					
						
							| 
									
										
										
										
											2008-02-08 04:19:31 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		ptr = mem2hex(crlf, ptr, sizeof(crlf) - 1, 0); | 
					
						
							|  |  |  | 		*ptr = 0; | 
					
						
							|  |  |  | 		putpacket(output_buffer);	/* send it off... */ | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/*
 | 
					
						
							|  |  |  | 	 * tell the debugger that an exception has occurred | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	ptr = output_buffer; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/*
 | 
					
						
							|  |  |  | 	 * Send trap type (converted to signal) | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	*ptr++ = 'T'; | 
					
						
							| 
									
										
										
										
											2011-10-31 17:12:51 -07:00
										 |  |  | 	ptr = hex_byte_pack(ptr, sigval); | 
					
						
							| 
									
										
										
										
											2008-02-08 04:19:31 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/*
 | 
					
						
							|  |  |  | 	 * Send Error PC | 
					
						
							|  |  |  | 	 */ | 
					
						
							| 
									
										
										
										
											2011-10-31 17:12:51 -07:00
										 |  |  | 	ptr = hex_byte_pack(ptr, GDB_REGID_PC); | 
					
						
							| 
									
										
										
										
											2008-02-08 04:19:31 -08:00
										 |  |  | 	*ptr++ = ':'; | 
					
						
							|  |  |  | 	ptr = mem2hex(®s->pc, ptr, 4, 0); | 
					
						
							|  |  |  | 	*ptr++ = ';'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/*
 | 
					
						
							|  |  |  | 	 * Send frame pointer | 
					
						
							|  |  |  | 	 */ | 
					
						
							| 
									
										
										
										
											2011-10-31 17:12:51 -07:00
										 |  |  | 	ptr = hex_byte_pack(ptr, GDB_REGID_FP); | 
					
						
							| 
									
										
										
										
											2008-02-08 04:19:31 -08:00
										 |  |  | 	*ptr++ = ':'; | 
					
						
							|  |  |  | 	ptr = mem2hex(®s->a3, ptr, 4, 0); | 
					
						
							|  |  |  | 	*ptr++ = ';'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/*
 | 
					
						
							|  |  |  | 	 * Send stack pointer | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	ssp = (unsigned long) (regs + 1); | 
					
						
							| 
									
										
										
										
											2011-10-31 17:12:51 -07:00
										 |  |  | 	ptr = hex_byte_pack(ptr, GDB_REGID_SP); | 
					
						
							| 
									
										
										
										
											2008-02-08 04:19:31 -08:00
										 |  |  | 	*ptr++ = ':'; | 
					
						
							|  |  |  | 	ptr = mem2hex(&ssp, ptr, 4, 0); | 
					
						
							|  |  |  | 	*ptr++ = ';'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	*ptr++ = 0; | 
					
						
							|  |  |  | 	putpacket(output_buffer);	/* send it off... */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | packet_waiting: | 
					
						
							|  |  |  | 	/*
 | 
					
						
							|  |  |  | 	 * Wait for input from remote GDB | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	while (1) { | 
					
						
							|  |  |  | 		output_buffer[0] = 0; | 
					
						
							|  |  |  | 		getpacket(input_buffer); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		switch (input_buffer[0]) { | 
					
						
							|  |  |  | 			/* request repeat of last signal number */ | 
					
						
							|  |  |  | 		case '?': | 
					
						
							|  |  |  | 			output_buffer[0] = 'S'; | 
					
						
							| 
									
										
										
										
											2008-07-25 19:45:20 -07:00
										 |  |  | 			output_buffer[1] = hex_asc_hi(sigval); | 
					
						
							|  |  |  | 			output_buffer[2] = hex_asc_lo(sigval); | 
					
						
							| 
									
										
										
										
											2008-02-08 04:19:31 -08:00
										 |  |  | 			output_buffer[3] = 0; | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		case 'd': | 
					
						
							|  |  |  | 			/* toggle debug flag */ | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			/*
 | 
					
						
							|  |  |  | 			 * Return the value of the CPU registers | 
					
						
							|  |  |  | 			 */ | 
					
						
							|  |  |  | 		case 'g': | 
					
						
							|  |  |  | 			zero = 0; | 
					
						
							|  |  |  | 			ssp = (u32) (regs + 1); | 
					
						
							|  |  |  | 			ptr = output_buffer; | 
					
						
							|  |  |  | 			ptr = mem2hex(®s->d0, ptr, 4, 0); | 
					
						
							|  |  |  | 			ptr = mem2hex(®s->d1, ptr, 4, 0); | 
					
						
							|  |  |  | 			ptr = mem2hex(®s->d2, ptr, 4, 0); | 
					
						
							|  |  |  | 			ptr = mem2hex(®s->d3, ptr, 4, 0); | 
					
						
							|  |  |  | 			ptr = mem2hex(®s->a0, ptr, 4, 0); | 
					
						
							|  |  |  | 			ptr = mem2hex(®s->a1, ptr, 4, 0); | 
					
						
							|  |  |  | 			ptr = mem2hex(®s->a2, ptr, 4, 0); | 
					
						
							|  |  |  | 			ptr = mem2hex(®s->a3, ptr, 4, 0); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			ptr = mem2hex(&ssp, ptr, 4, 0);		/* 8 */ | 
					
						
							|  |  |  | 			ptr = mem2hex(®s->pc, ptr, 4, 0); | 
					
						
							|  |  |  | 			ptr = mem2hex(®s->mdr, ptr, 4, 0); | 
					
						
							|  |  |  | 			ptr = mem2hex(®s->epsw, ptr, 4, 0); | 
					
						
							|  |  |  | 			ptr = mem2hex(®s->lir, ptr, 4, 0); | 
					
						
							|  |  |  | 			ptr = mem2hex(®s->lar, ptr, 4, 0); | 
					
						
							|  |  |  | 			ptr = mem2hex(®s->mdrq, ptr, 4, 0); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			ptr = mem2hex(®s->e0, ptr, 4, 0);	/* 15 */ | 
					
						
							|  |  |  | 			ptr = mem2hex(®s->e1, ptr, 4, 0); | 
					
						
							|  |  |  | 			ptr = mem2hex(®s->e2, ptr, 4, 0); | 
					
						
							|  |  |  | 			ptr = mem2hex(®s->e3, ptr, 4, 0); | 
					
						
							|  |  |  | 			ptr = mem2hex(®s->e4, ptr, 4, 0); | 
					
						
							|  |  |  | 			ptr = mem2hex(®s->e5, ptr, 4, 0); | 
					
						
							|  |  |  | 			ptr = mem2hex(®s->e6, ptr, 4, 0); | 
					
						
							|  |  |  | 			ptr = mem2hex(®s->e7, ptr, 4, 0); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			ptr = mem2hex(&ssp, ptr, 4, 0); | 
					
						
							|  |  |  | 			ptr = mem2hex(®s, ptr, 4, 0); | 
					
						
							|  |  |  | 			ptr = mem2hex(®s->sp, ptr, 4, 0); | 
					
						
							|  |  |  | 			ptr = mem2hex(®s->mcrh, ptr, 4, 0);	/* 26 */ | 
					
						
							|  |  |  | 			ptr = mem2hex(®s->mcrl, ptr, 4, 0); | 
					
						
							|  |  |  | 			ptr = mem2hex(®s->mcvf, ptr, 4, 0); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			ptr = mem2hex(&gdbstub_fpcr, ptr, 4, 0); /* 29 - FPCR */ | 
					
						
							|  |  |  | 			ptr = mem2hex(&zero, ptr, 4, 0); | 
					
						
							|  |  |  | 			ptr = mem2hex(&zero, ptr, 4, 0); | 
					
						
							|  |  |  | 			for (loop = 0; loop < 32; loop++) | 
					
						
							|  |  |  | 				ptr = mem2hex(&gdbstub_fpufs_array[loop], | 
					
						
							|  |  |  | 					      ptr, 4, 0); /* 32 - FS0-31 */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			/*
 | 
					
						
							|  |  |  | 			 * set the value of the CPU registers - return OK | 
					
						
							|  |  |  | 			 */ | 
					
						
							|  |  |  | 		case 'G': | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			const char *ptr; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			ptr = &input_buffer[1]; | 
					
						
							|  |  |  | 			ptr = hex2mem(ptr, ®s->d0, 4, 0); | 
					
						
							|  |  |  | 			ptr = hex2mem(ptr, ®s->d1, 4, 0); | 
					
						
							|  |  |  | 			ptr = hex2mem(ptr, ®s->d2, 4, 0); | 
					
						
							|  |  |  | 			ptr = hex2mem(ptr, ®s->d3, 4, 0); | 
					
						
							|  |  |  | 			ptr = hex2mem(ptr, ®s->a0, 4, 0); | 
					
						
							|  |  |  | 			ptr = hex2mem(ptr, ®s->a1, 4, 0); | 
					
						
							|  |  |  | 			ptr = hex2mem(ptr, ®s->a2, 4, 0); | 
					
						
							|  |  |  | 			ptr = hex2mem(ptr, ®s->a3, 4, 0); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			ptr = hex2mem(ptr, &ssp, 4, 0);		/* 8 */ | 
					
						
							|  |  |  | 			ptr = hex2mem(ptr, ®s->pc, 4, 0); | 
					
						
							|  |  |  | 			ptr = hex2mem(ptr, ®s->mdr, 4, 0); | 
					
						
							|  |  |  | 			ptr = hex2mem(ptr, ®s->epsw, 4, 0); | 
					
						
							|  |  |  | 			ptr = hex2mem(ptr, ®s->lir, 4, 0); | 
					
						
							|  |  |  | 			ptr = hex2mem(ptr, ®s->lar, 4, 0); | 
					
						
							|  |  |  | 			ptr = hex2mem(ptr, ®s->mdrq, 4, 0); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			ptr = hex2mem(ptr, ®s->e0, 4, 0);	/* 15 */ | 
					
						
							|  |  |  | 			ptr = hex2mem(ptr, ®s->e1, 4, 0); | 
					
						
							|  |  |  | 			ptr = hex2mem(ptr, ®s->e2, 4, 0); | 
					
						
							|  |  |  | 			ptr = hex2mem(ptr, ®s->e3, 4, 0); | 
					
						
							|  |  |  | 			ptr = hex2mem(ptr, ®s->e4, 4, 0); | 
					
						
							|  |  |  | 			ptr = hex2mem(ptr, ®s->e5, 4, 0); | 
					
						
							|  |  |  | 			ptr = hex2mem(ptr, ®s->e6, 4, 0); | 
					
						
							|  |  |  | 			ptr = hex2mem(ptr, ®s->e7, 4, 0); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			ptr = hex2mem(ptr, &ssp, 4, 0); | 
					
						
							|  |  |  | 			ptr = hex2mem(ptr, &zero, 4, 0); | 
					
						
							|  |  |  | 			ptr = hex2mem(ptr, ®s->sp, 4, 0); | 
					
						
							|  |  |  | 			ptr = hex2mem(ptr, ®s->mcrh, 4, 0);	/* 26 */ | 
					
						
							|  |  |  | 			ptr = hex2mem(ptr, ®s->mcrl, 4, 0); | 
					
						
							|  |  |  | 			ptr = hex2mem(ptr, ®s->mcvf, 4, 0); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			ptr = hex2mem(ptr, &zero, 4, 0);	/* 29 - FPCR */ | 
					
						
							|  |  |  | 			ptr = hex2mem(ptr, &zero, 4, 0); | 
					
						
							|  |  |  | 			ptr = hex2mem(ptr, &zero, 4, 0); | 
					
						
							|  |  |  | 			for (loop = 0; loop < 32; loop++)     /* 32 - FS0-31 */ | 
					
						
							|  |  |  | 				ptr = hex2mem(ptr, &zero, 4, 0); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #if 0
 | 
					
						
							|  |  |  | 			/*
 | 
					
						
							|  |  |  | 			 * See if the stack pointer has moved. If so, then copy | 
					
						
							|  |  |  | 			 * the saved locals and ins to the new location. | 
					
						
							|  |  |  | 			 */ | 
					
						
							|  |  |  | 			unsigned long *newsp = (unsigned long *) registers[SP]; | 
					
						
							|  |  |  | 			if (sp != newsp) | 
					
						
							|  |  |  | 				sp = memcpy(newsp, sp, 16 * 4); | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			gdbstub_strcpy(output_buffer, "OK"); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/*
 | 
					
						
							|  |  |  | 		 * mAA..AA,LLLL  Read LLLL bytes at address AA..AA | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		case 'm': | 
					
						
							|  |  |  | 			ptr = &input_buffer[1]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if (hexToInt(&ptr, &addr) && | 
					
						
							|  |  |  | 			    *ptr++ == ',' && | 
					
						
							|  |  |  | 			    hexToInt(&ptr, &length) | 
					
						
							|  |  |  | 			    ) { | 
					
						
							|  |  |  | 				if (mem2hex((char *) addr, output_buffer, | 
					
						
							|  |  |  | 					    length, 1)) | 
					
						
							|  |  |  | 					break; | 
					
						
							|  |  |  | 				gdbstub_strcpy(output_buffer, "E03"); | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				gdbstub_strcpy(output_buffer, "E01"); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			/*
 | 
					
						
							|  |  |  | 			 * MAA..AA,LLLL: Write LLLL bytes at address AA.AA | 
					
						
							|  |  |  | 			 * return OK | 
					
						
							|  |  |  | 			 */ | 
					
						
							|  |  |  | 		case 'M': | 
					
						
							|  |  |  | 			ptr = &input_buffer[1]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if (hexToInt(&ptr, &addr) && | 
					
						
							|  |  |  | 			    *ptr++ == ',' && | 
					
						
							|  |  |  | 			    hexToInt(&ptr, &length) && | 
					
						
							|  |  |  | 			    *ptr++ == ':' | 
					
						
							|  |  |  | 			    ) { | 
					
						
							|  |  |  | 				if (hex2mem(ptr, (char *) addr, length, 1)) | 
					
						
							|  |  |  | 					gdbstub_strcpy(output_buffer, "OK"); | 
					
						
							|  |  |  | 				else | 
					
						
							|  |  |  | 					gdbstub_strcpy(output_buffer, "E03"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				gdbstub_flush_caches = 1; | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				gdbstub_strcpy(output_buffer, "E02"); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			/*
 | 
					
						
							|  |  |  | 			 * cAA..AA    Continue at address AA..AA(optional) | 
					
						
							|  |  |  | 			 */ | 
					
						
							|  |  |  | 		case 'c': | 
					
						
							|  |  |  | 			/* try to read optional parameter, pc unchanged if no
 | 
					
						
							|  |  |  | 			 * parm */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			ptr = &input_buffer[1]; | 
					
						
							|  |  |  | 			if (hexToInt(&ptr, &addr)) | 
					
						
							|  |  |  | 				regs->pc = addr; | 
					
						
							|  |  |  | 			goto done; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			/*
 | 
					
						
							|  |  |  | 			 * kill the program | 
					
						
							|  |  |  | 			 */ | 
					
						
							|  |  |  | 		case 'k' : | 
					
						
							|  |  |  | 			goto done;	/* just continue */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			/*
 | 
					
						
							|  |  |  | 			 * Reset the whole machine (FIXME: system dependent) | 
					
						
							|  |  |  | 			 */ | 
					
						
							|  |  |  | 		case 'r': | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			/*
 | 
					
						
							|  |  |  | 			 * Step to next instruction | 
					
						
							|  |  |  | 			 */ | 
					
						
							|  |  |  | 		case 's': | 
					
						
							| 
									
										
										
										
											2011-03-18 16:54:29 +00:00
										 |  |  | 			/* Using the T flag doesn't seem to perform single
 | 
					
						
							| 
									
										
										
										
											2008-02-08 04:19:31 -08:00
										 |  |  | 			 * stepping (it seems to wind up being caught by the | 
					
						
							|  |  |  | 			 * JTAG unit), so we have to use breakpoints and | 
					
						
							|  |  |  | 			 * continue instead. | 
					
						
							|  |  |  | 			 */ | 
					
						
							| 
									
										
										
										
											2011-03-18 16:54:29 +00:00
										 |  |  | #ifdef CONFIG_GDBSTUB_ALLOW_SINGLE_STEP
 | 
					
						
							| 
									
										
										
										
											2008-02-08 04:19:31 -08:00
										 |  |  | 			if (gdbstub_single_step(regs) < 0) | 
					
						
							|  |  |  | 				/* ignore any fault error for now */ | 
					
						
							|  |  |  | 				gdbstub_printk("unable to set single-step" | 
					
						
							|  |  |  | 					       " bp\n"); | 
					
						
							|  |  |  | 			goto done; | 
					
						
							| 
									
										
										
										
											2011-03-18 16:54:29 +00:00
										 |  |  | #else
 | 
					
						
							|  |  |  | 			gdbstub_strcpy(output_buffer, "E01"); | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2008-02-08 04:19:31 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			/*
 | 
					
						
							|  |  |  | 			 * Set baud rate (bBB) | 
					
						
							|  |  |  | 			 */ | 
					
						
							|  |  |  | 		case 'b': | 
					
						
							|  |  |  | 			do { | 
					
						
							|  |  |  | 				int baudrate; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				ptr = &input_buffer[1]; | 
					
						
							|  |  |  | 				if (!hexToInt(&ptr, &baudrate)) { | 
					
						
							|  |  |  | 					gdbstub_strcpy(output_buffer, "B01"); | 
					
						
							|  |  |  | 					break; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				if (baudrate) { | 
					
						
							|  |  |  | 					/* ACK before changing speed */ | 
					
						
							|  |  |  | 					putpacket("OK"); | 
					
						
							|  |  |  | 					gdbstub_io_set_baud(baudrate); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} while (0); | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			/*
 | 
					
						
							|  |  |  | 			 * Set breakpoint | 
					
						
							|  |  |  | 			 */ | 
					
						
							|  |  |  | 		case 'Z': | 
					
						
							|  |  |  | 			ptr = &input_buffer[1]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if (!hexToInt(&ptr, &loop) || *ptr++ != ',' || | 
					
						
							|  |  |  | 			    !hexToInt(&ptr, &addr) || *ptr++ != ',' || | 
					
						
							|  |  |  | 			    !hexToInt(&ptr, &length) | 
					
						
							|  |  |  | 			    ) { | 
					
						
							|  |  |  | 				gdbstub_strcpy(output_buffer, "E01"); | 
					
						
							|  |  |  | 				break; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			/* only support software breakpoints */ | 
					
						
							|  |  |  | 			gdbstub_strcpy(output_buffer, "E03"); | 
					
						
							|  |  |  | 			if (loop != 0 || | 
					
						
							|  |  |  | 			    length < 1 || | 
					
						
							|  |  |  | 			    length > 7 || | 
					
						
							|  |  |  | 			    (unsigned long) addr < 4096) | 
					
						
							|  |  |  | 				break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if (gdbstub_set_breakpoint((u8 *) addr, length) < 0) | 
					
						
							|  |  |  | 				break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			gdbstub_strcpy(output_buffer, "OK"); | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			/*
 | 
					
						
							|  |  |  | 			 * Clear breakpoint | 
					
						
							|  |  |  | 			 */ | 
					
						
							|  |  |  | 		case 'z': | 
					
						
							|  |  |  | 			ptr = &input_buffer[1]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if (!hexToInt(&ptr, &loop) || *ptr++ != ',' || | 
					
						
							|  |  |  | 			    !hexToInt(&ptr, &addr) || *ptr++ != ',' || | 
					
						
							|  |  |  | 			    !hexToInt(&ptr, &length) | 
					
						
							|  |  |  | 			    ) { | 
					
						
							|  |  |  | 				gdbstub_strcpy(output_buffer, "E01"); | 
					
						
							|  |  |  | 				break; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			/* only support software breakpoints */ | 
					
						
							|  |  |  | 			gdbstub_strcpy(output_buffer, "E03"); | 
					
						
							|  |  |  | 			if (loop != 0 || | 
					
						
							|  |  |  | 			    length < 1 || | 
					
						
							|  |  |  | 			    length > 7 || | 
					
						
							|  |  |  | 			    (unsigned long) addr < 4096) | 
					
						
							|  |  |  | 				break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if (gdbstub_clear_breakpoint((u8 *) addr, length) < 0) | 
					
						
							|  |  |  | 				break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			gdbstub_strcpy(output_buffer, "OK"); | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		default: | 
					
						
							|  |  |  | 			gdbstub_proto("### GDB Unsupported Cmd '%s'\n", | 
					
						
							|  |  |  | 				      input_buffer); | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/* reply to the request */ | 
					
						
							|  |  |  | 		putpacket(output_buffer); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | done: | 
					
						
							|  |  |  | 	/*
 | 
					
						
							|  |  |  | 	 * Need to flush the instruction cache here, as we may | 
					
						
							|  |  |  | 	 * have deposited a breakpoint, and the icache probably | 
					
						
							|  |  |  | 	 * has no way of knowing that a data ref to some location | 
					
						
							|  |  |  | 	 * may have changed something that is in the instruction | 
					
						
							|  |  |  | 	 * cache. | 
					
						
							|  |  |  | 	 * NB: We flush both caches, just to be sure... | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	if (gdbstub_flush_caches) | 
					
						
							| 
									
										
										
										
											2011-03-18 16:54:30 +00:00
										 |  |  | 		debugger_local_cache_flushinv(); | 
					
						
							| 
									
										
										
										
											2008-02-08 04:19:31 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	gdbstub_load_fpu(); | 
					
						
							|  |  |  | 	mn10300_set_gdbleds(0); | 
					
						
							|  |  |  | 	if (excep == EXCEP_NMI) | 
					
						
							|  |  |  | 		NMICR = NMICR_NMIF; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	touch_softlockup_watchdog(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	local_irq_restore(epsw); | 
					
						
							| 
									
										
										
										
											2011-03-18 16:54:30 +00:00
										 |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * Determine if we hit a debugger special breakpoint that needs skipping over | 
					
						
							|  |  |  |  * automatically. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | int at_debugger_breakpoint(struct pt_regs *regs) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return 0; | 
					
						
							| 
									
										
										
										
											2008-02-08 04:19:31 -08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * handle event interception | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2011-03-18 16:54:30 +00:00
										 |  |  | asmlinkage int debugger_intercept(enum exception_code excep, | 
					
						
							|  |  |  | 				  int signo, int si_code, struct pt_regs *regs) | 
					
						
							| 
									
										
										
										
											2008-02-08 04:19:31 -08:00
										 |  |  | { | 
					
						
							|  |  |  | 	static u8 notfirst = 1; | 
					
						
							|  |  |  | 	int ret; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (gdbstub_busy) | 
					
						
							|  |  |  | 		gdbstub_printk("--> gdbstub reentered itself\n"); | 
					
						
							|  |  |  | 	gdbstub_busy = 1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (notfirst) { | 
					
						
							|  |  |  | 		unsigned long mdr; | 
					
						
							|  |  |  | 		asm("mov mdr,%0" : "=d"(mdr)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		gdbstub_entry( | 
					
						
							| 
									
										
										
										
											2011-03-18 16:54:30 +00:00
										 |  |  | 			"--> debugger_intercept(%p,%04x) [MDR=%lx PC=%lx]\n", | 
					
						
							| 
									
										
										
										
											2008-02-08 04:19:31 -08:00
										 |  |  | 			regs, excep, mdr, regs->pc); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		gdbstub_entry( | 
					
						
							|  |  |  | 			"PC:  %08lx EPSW:  %08lx  SSP: %08lx mode: %s\n", | 
					
						
							|  |  |  | 			regs->pc, regs->epsw, (unsigned long) &ret, | 
					
						
							|  |  |  | 			user_mode(regs) ? "User" : "Super"); | 
					
						
							|  |  |  | 		gdbstub_entry( | 
					
						
							|  |  |  | 			"d0:  %08lx   d1:  %08lx   d2: %08lx   d3: %08lx\n", | 
					
						
							|  |  |  | 			regs->d0, regs->d1, regs->d2, regs->d3); | 
					
						
							|  |  |  | 		gdbstub_entry( | 
					
						
							|  |  |  | 			"a0:  %08lx   a1:  %08lx   a2: %08lx   a3: %08lx\n", | 
					
						
							|  |  |  | 			regs->a0, regs->a1, regs->a2, regs->a3); | 
					
						
							|  |  |  | 		gdbstub_entry( | 
					
						
							|  |  |  | 			"e0:  %08lx   e1:  %08lx   e2: %08lx   e3: %08lx\n", | 
					
						
							|  |  |  | 			regs->e0, regs->e1, regs->e2, regs->e3); | 
					
						
							|  |  |  | 		gdbstub_entry( | 
					
						
							|  |  |  | 			"e4:  %08lx   e5:  %08lx   e6: %08lx   e7: %08lx\n", | 
					
						
							|  |  |  | 			regs->e4, regs->e5, regs->e6, regs->e7); | 
					
						
							|  |  |  | 		gdbstub_entry( | 
					
						
							|  |  |  | 			"lar: %08lx   lir: %08lx  mdr: %08lx  usp: %08lx\n", | 
					
						
							|  |  |  | 			regs->lar, regs->lir, regs->mdr, regs->sp); | 
					
						
							|  |  |  | 		gdbstub_entry( | 
					
						
							|  |  |  | 			"cvf: %08lx   crl: %08lx  crh: %08lx  drq: %08lx\n", | 
					
						
							|  |  |  | 			regs->mcvf, regs->mcrl, regs->mcrh, regs->mdrq); | 
					
						
							|  |  |  | 		gdbstub_entry( | 
					
						
							|  |  |  | 			"threadinfo=%p task=%p)\n", | 
					
						
							|  |  |  | 			current_thread_info(), current); | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		notfirst = 1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ret = gdbstub(regs, excep); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-03-18 16:54:30 +00:00
										 |  |  | 	gdbstub_entry("<-- debugger_intercept()\n"); | 
					
						
							| 
									
										
										
										
											2008-02-08 04:19:31 -08:00
										 |  |  | 	gdbstub_busy = 0; | 
					
						
							|  |  |  | 	return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * handle the GDB stub itself causing an exception | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | asmlinkage void gdbstub_exception(struct pt_regs *regs, | 
					
						
							|  |  |  | 				  enum exception_code excep) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	unsigned long mdr; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	asm("mov mdr,%0" : "=d"(mdr)); | 
					
						
							|  |  |  | 	gdbstub_entry("--> gdbstub exception({%p},%04x) [MDR=%lx]\n", | 
					
						
							|  |  |  | 		      regs, excep, mdr); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	while ((unsigned long) regs == 0xffffffff) {} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* handle guarded memory accesses where we know it might fault */ | 
					
						
							|  |  |  | 	if (regs->pc == (unsigned) gdbstub_read_byte_guard) { | 
					
						
							|  |  |  | 		regs->pc = (unsigned) gdbstub_read_byte_cont; | 
					
						
							|  |  |  | 		goto fault; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (regs->pc == (unsigned) gdbstub_read_word_guard) { | 
					
						
							|  |  |  | 		regs->pc = (unsigned) gdbstub_read_word_cont; | 
					
						
							|  |  |  | 		goto fault; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (regs->pc == (unsigned) gdbstub_read_dword_guard) { | 
					
						
							|  |  |  | 		regs->pc = (unsigned) gdbstub_read_dword_cont; | 
					
						
							|  |  |  | 		goto fault; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (regs->pc == (unsigned) gdbstub_write_byte_guard) { | 
					
						
							|  |  |  | 		regs->pc = (unsigned) gdbstub_write_byte_cont; | 
					
						
							|  |  |  | 		goto fault; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (regs->pc == (unsigned) gdbstub_write_word_guard) { | 
					
						
							|  |  |  | 		regs->pc = (unsigned) gdbstub_write_word_cont; | 
					
						
							|  |  |  | 		goto fault; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (regs->pc == (unsigned) gdbstub_write_dword_guard) { | 
					
						
							|  |  |  | 		regs->pc = (unsigned) gdbstub_write_dword_cont; | 
					
						
							|  |  |  | 		goto fault; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	gdbstub_printk("\n### GDB stub caused an exception ###\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* something went horribly wrong */ | 
					
						
							|  |  |  | 	console_verbose(); | 
					
						
							|  |  |  | 	show_registers(regs); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	panic("GDB Stub caused an unexpected exception - can't continue\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* we caught an attempt by the stub to access silly memory */ | 
					
						
							|  |  |  | fault: | 
					
						
							|  |  |  | 	gdbstub_entry("<-- gdbstub exception() = EFAULT\n"); | 
					
						
							|  |  |  | 	regs->d0 = -EFAULT; | 
					
						
							|  |  |  | 	return; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * send an exit message to GDB | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | void gdbstub_exit(int status) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	unsigned char checksum; | 
					
						
							|  |  |  | 	unsigned char ch; | 
					
						
							|  |  |  | 	int count; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	gdbstub_busy = 1; | 
					
						
							|  |  |  | 	output_buffer[0] = 'W'; | 
					
						
							| 
									
										
										
										
											2008-07-25 19:45:20 -07:00
										 |  |  | 	output_buffer[1] = hex_asc_hi(status); | 
					
						
							|  |  |  | 	output_buffer[2] = hex_asc_lo(status); | 
					
						
							| 
									
										
										
										
											2008-02-08 04:19:31 -08:00
										 |  |  | 	output_buffer[3] = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	gdbstub_io_tx_char('$'); | 
					
						
							|  |  |  | 	checksum = 0; | 
					
						
							|  |  |  | 	count = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	while ((ch = output_buffer[count]) != 0) { | 
					
						
							|  |  |  | 		gdbstub_io_tx_char(ch); | 
					
						
							|  |  |  | 		checksum += ch; | 
					
						
							|  |  |  | 		count += 1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	gdbstub_io_tx_char('#'); | 
					
						
							| 
									
										
										
										
											2008-07-25 19:45:20 -07:00
										 |  |  | 	gdbstub_io_tx_char(hex_asc_hi(checksum)); | 
					
						
							|  |  |  | 	gdbstub_io_tx_char(hex_asc_lo(checksum)); | 
					
						
							| 
									
										
										
										
											2008-02-08 04:19:31 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* make sure the output is flushed, or else RedBoot might clobber it */ | 
					
						
							|  |  |  | 	gdbstub_io_tx_flush(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	gdbstub_busy = 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * initialise the GDB stub | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | asmlinkage void __init gdbstub_init(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | #ifdef CONFIG_GDBSTUB_IMMEDIATE
 | 
					
						
							|  |  |  | 	unsigned char ch; | 
					
						
							|  |  |  | 	int ret; | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	gdbstub_busy = 1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	printk(KERN_INFO "%s", gdbstub_banner); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	gdbstub_io_init(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	gdbstub_entry("--> gdbstub_init\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* try to talk to GDB (or anyone insane enough to want to type GDB
 | 
					
						
							|  |  |  | 	 * protocol by hand) */ | 
					
						
							|  |  |  | 	gdbstub_io("### GDB Tx ACK\n"); | 
					
						
							|  |  |  | 	gdbstub_io_tx_char('+'); /* 'hello world' */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #ifdef CONFIG_GDBSTUB_IMMEDIATE
 | 
					
						
							|  |  |  | 	gdbstub_printk("GDB Stub waiting for packet\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* in case GDB is started before us, ACK any packets that are already
 | 
					
						
							|  |  |  | 	 * sitting there (presumably "$?#xx") | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	do { gdbstub_io_rx_char(&ch, 0); } while (ch != '$'); | 
					
						
							|  |  |  | 	do { gdbstub_io_rx_char(&ch, 0); } while (ch != '#'); | 
					
						
							|  |  |  | 	/* eat first csum byte */ | 
					
						
							|  |  |  | 	do { ret = gdbstub_io_rx_char(&ch, 0); } while (ret != 0); | 
					
						
							|  |  |  | 	/* eat second csum byte */ | 
					
						
							|  |  |  | 	do { ret = gdbstub_io_rx_char(&ch, 0); } while (ret != 0); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	gdbstub_io("### GDB Tx NAK\n"); | 
					
						
							|  |  |  | 	gdbstub_io_tx_char('-'); /* NAK it */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #else
 | 
					
						
							|  |  |  | 	printk("GDB Stub ready\n"); | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	gdbstub_busy = 0; | 
					
						
							|  |  |  | 	gdbstub_entry("<-- gdbstub_init\n"); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * register the console at a more appropriate time | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | #ifdef CONFIG_GDBSTUB_CONSOLE
 | 
					
						
							|  |  |  | static int __init gdbstub_postinit(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	printk(KERN_NOTICE "registering console\n"); | 
					
						
							|  |  |  | 	register_console(&gdbstub_console); | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | __initcall(gdbstub_postinit); | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * handle character reception on GDB serial port | 
					
						
							|  |  |  |  * - jump into the GDB stub if BREAK is detected on the serial line | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | asmlinkage void gdbstub_rx_irq(struct pt_regs *regs, enum exception_code excep) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	char ch; | 
					
						
							|  |  |  | 	int ret; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	gdbstub_entry("--> gdbstub_rx_irq\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	do { | 
					
						
							|  |  |  | 		ret = gdbstub_io_rx_char(&ch, 1); | 
					
						
							|  |  |  | 		if (ret != -EIO && ret != -EAGAIN) { | 
					
						
							|  |  |  | 			if (ret != -EINTR) | 
					
						
							|  |  |  | 				gdbstub_rx_unget = ch; | 
					
						
							|  |  |  | 			gdbstub(regs, excep); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} while (ret != -EAGAIN); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	gdbstub_entry("<-- gdbstub_rx_irq\n"); | 
					
						
							|  |  |  | } |