| David Howells | b920de1 | 2008-02-08 04:19:31 -0800 | [diff] [blame] | 1 | /* MN10300 GDB stub | 
|  | 2 | * | 
|  | 3 | * Originally written by Glenn Engel, Lake Stevens Instrument Division | 
|  | 4 | * | 
|  | 5 | * Contributed by HP Systems | 
|  | 6 | * | 
|  | 7 | * Modified for SPARC by Stu Grossman, Cygnus Support. | 
|  | 8 | * | 
|  | 9 | * Modified for Linux/MIPS (and MIPS in general) by Andreas Busse | 
|  | 10 | * Send complaints, suggestions etc. to <andy@waldorf-gmbh.de> | 
|  | 11 | * | 
|  | 12 | * Copyright (C) 1995 Andreas Busse | 
|  | 13 | * | 
|  | 14 | * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved. | 
|  | 15 | * Modified for Linux/mn10300 by David Howells <dhowells@redhat.com> | 
|  | 16 | */ | 
|  | 17 |  | 
|  | 18 | /* | 
|  | 19 | *  To enable debugger support, two things need to happen.  One, a | 
|  | 20 | *  call to set_debug_traps() is necessary in order to allow any breakpoints | 
|  | 21 | *  or error conditions to be properly intercepted and reported to gdb. | 
|  | 22 | *  Two, a breakpoint needs to be generated to begin communication.  This | 
|  | 23 | *  is most easily accomplished by a call to breakpoint().  Breakpoint() | 
|  | 24 | *  simulates a breakpoint by executing a BREAK instruction. | 
|  | 25 | * | 
|  | 26 | * | 
|  | 27 | *    The following gdb commands are supported: | 
|  | 28 | * | 
|  | 29 | * command          function                               Return value | 
|  | 30 | * | 
|  | 31 | *    g             return the value of the CPU registers  hex data or ENN | 
|  | 32 | *    G             set the value of the CPU registers     OK or ENN | 
|  | 33 | * | 
|  | 34 | *    mAA..AA,LLLL  Read LLLL bytes at address AA..AA      hex data or ENN | 
|  | 35 | *    MAA..AA,LLLL: Write LLLL bytes at address AA.AA      OK or ENN | 
|  | 36 | * | 
|  | 37 | *    c             Resume at current address              SNN   ( signal NN) | 
|  | 38 | *    cAA..AA       Continue at address AA..AA             SNN | 
|  | 39 | * | 
|  | 40 | *    s             Step one instruction                   SNN | 
|  | 41 | *    sAA..AA       Step one instruction from AA..AA       SNN | 
|  | 42 | * | 
|  | 43 | *    k             kill | 
|  | 44 | * | 
|  | 45 | *    ?             What was the last sigval ?             SNN   (signal NN) | 
|  | 46 | * | 
|  | 47 | *    bBB..BB	    Set baud rate to BB..BB		   OK or BNN, then sets | 
|  | 48 | *							   baud rate | 
|  | 49 | * | 
|  | 50 | * All commands and responses are sent with a packet which includes a | 
|  | 51 | * checksum.  A packet consists of | 
|  | 52 | * | 
|  | 53 | * $<packet info>#<checksum>. | 
|  | 54 | * | 
|  | 55 | * where | 
|  | 56 | * <packet info> :: <characters representing the command or response> | 
|  | 57 | * <checksum>    :: < two hex digits computed as modulo 256 sum of <packetinfo>> | 
|  | 58 | * | 
|  | 59 | * When a packet is received, it is first acknowledged with either '+' or '-'. | 
|  | 60 | * '+' indicates a successful transfer.  '-' indicates a failed transfer. | 
|  | 61 | * | 
|  | 62 | * Example: | 
|  | 63 | * | 
|  | 64 | * Host:                  Reply: | 
|  | 65 | * $m0,10#2a               +$00010203040506070809101112131415#42 | 
|  | 66 | * | 
|  | 67 | * | 
|  | 68 | *  ============== | 
|  | 69 | *  MORE EXAMPLES: | 
|  | 70 | *  ============== | 
|  | 71 | * | 
|  | 72 | *  For reference -- the following are the steps that one | 
|  | 73 | *  company took (RidgeRun Inc) to get remote gdb debugging | 
|  | 74 | *  going. In this scenario the host machine was a PC and the | 
|  | 75 | *  target platform was a Galileo EVB64120A MIPS evaluation | 
|  | 76 | *  board. | 
|  | 77 | * | 
|  | 78 | *  Step 1: | 
|  | 79 | *  First download gdb-5.0.tar.gz from the internet. | 
|  | 80 | *  and then build/install the package. | 
|  | 81 | * | 
|  | 82 | *  Example: | 
|  | 83 | *    $ tar zxf gdb-5.0.tar.gz | 
|  | 84 | *    $ cd gdb-5.0 | 
|  | 85 | *    $ ./configure --target=am33_2.0-linux-gnu | 
|  | 86 | *    $ make | 
|  | 87 | *    $ install | 
|  | 88 | *    am33_2.0-linux-gnu-gdb | 
|  | 89 | * | 
|  | 90 | *  Step 2: | 
|  | 91 | *  Configure linux for remote debugging and build it. | 
|  | 92 | * | 
|  | 93 | *  Example: | 
|  | 94 | *    $ cd ~/linux | 
|  | 95 | *    $ make menuconfig <go to "Kernel Hacking" and turn on remote debugging> | 
|  | 96 | *    $ make dep; make vmlinux | 
|  | 97 | * | 
|  | 98 | *  Step 3: | 
|  | 99 | *  Download the kernel to the remote target and start | 
|  | 100 | *  the kernel running. It will promptly halt and wait | 
|  | 101 | *  for the host gdb session to connect. It does this | 
|  | 102 | *  since the "Kernel Hacking" option has defined | 
|  | 103 | *  CONFIG_REMOTE_DEBUG which in turn enables your calls | 
|  | 104 | *  to: | 
|  | 105 | *     set_debug_traps(); | 
|  | 106 | *     breakpoint(); | 
|  | 107 | * | 
|  | 108 | *  Step 4: | 
|  | 109 | *  Start the gdb session on the host. | 
|  | 110 | * | 
|  | 111 | *  Example: | 
|  | 112 | *    $ am33_2.0-linux-gnu-gdb vmlinux | 
|  | 113 | *    (gdb) set remotebaud 115200 | 
|  | 114 | *    (gdb) target remote /dev/ttyS1 | 
|  | 115 | *    ...at this point you are connected to | 
|  | 116 | *       the remote target and can use gdb | 
|  | 117 | *       in the normal fasion. Setting | 
|  | 118 | *       breakpoints, single stepping, | 
|  | 119 | *       printing variables, etc. | 
|  | 120 | * | 
|  | 121 | */ | 
|  | 122 |  | 
|  | 123 | #include <linux/string.h> | 
|  | 124 | #include <linux/kernel.h> | 
|  | 125 | #include <linux/signal.h> | 
|  | 126 | #include <linux/sched.h> | 
|  | 127 | #include <linux/mm.h> | 
|  | 128 | #include <linux/console.h> | 
|  | 129 | #include <linux/init.h> | 
|  | 130 | #include <linux/bug.h> | 
|  | 131 |  | 
|  | 132 | #include <asm/pgtable.h> | 
|  | 133 | #include <asm/system.h> | 
|  | 134 | #include <asm/gdb-stub.h> | 
|  | 135 | #include <asm/exceptions.h> | 
|  | 136 | #include <asm/cacheflush.h> | 
|  | 137 | #include <asm/serial-regs.h> | 
|  | 138 | #include <asm/busctl-regs.h> | 
| David Howells | 2f2a213 | 2009-04-10 14:33:48 +0100 | [diff] [blame] | 139 | #include <unit/leds.h> | 
|  | 140 | #include <unit/serial.h> | 
| David Howells | b920de1 | 2008-02-08 04:19:31 -0800 | [diff] [blame] | 141 |  | 
|  | 142 | /* define to use F7F7 rather than FF which is subverted by JTAG debugger */ | 
|  | 143 | #undef GDBSTUB_USE_F7F7_AS_BREAKPOINT | 
|  | 144 |  | 
|  | 145 | /* | 
|  | 146 | * BUFMAX defines the maximum number of characters in inbound/outbound buffers | 
|  | 147 | * at least NUMREGBYTES*2 are needed for register packets | 
|  | 148 | */ | 
|  | 149 | #define BUFMAX 2048 | 
|  | 150 |  | 
|  | 151 | static const char gdbstub_banner[] = | 
|  | 152 | "Linux/MN10300 GDB Stub (c) RedHat 2007\n"; | 
|  | 153 |  | 
|  | 154 | u8	gdbstub_rx_buffer[PAGE_SIZE] __attribute__((aligned(PAGE_SIZE))); | 
|  | 155 | u32	gdbstub_rx_inp; | 
|  | 156 | u32	gdbstub_rx_outp; | 
|  | 157 | u8	gdbstub_busy; | 
|  | 158 | u8	gdbstub_rx_overflow; | 
|  | 159 | u8	gdbstub_rx_unget; | 
|  | 160 |  | 
|  | 161 | static u8	gdbstub_flush_caches; | 
|  | 162 | static char	input_buffer[BUFMAX]; | 
|  | 163 | static char	output_buffer[BUFMAX]; | 
|  | 164 | static char	trans_buffer[BUFMAX]; | 
|  | 165 |  | 
| David Howells | b920de1 | 2008-02-08 04:19:31 -0800 | [diff] [blame] | 166 | struct gdbstub_bkpt { | 
|  | 167 | u8	*addr;		/* address of breakpoint */ | 
|  | 168 | u8	len;		/* size of breakpoint */ | 
|  | 169 | u8	origbytes[7];	/* original bytes */ | 
|  | 170 | }; | 
|  | 171 |  | 
|  | 172 | static struct gdbstub_bkpt gdbstub_bkpts[256]; | 
|  | 173 |  | 
|  | 174 | /* | 
|  | 175 | * local prototypes | 
|  | 176 | */ | 
|  | 177 | static void getpacket(char *buffer); | 
|  | 178 | static int putpacket(char *buffer); | 
|  | 179 | static int computeSignal(enum exception_code excep); | 
|  | 180 | static int hex(unsigned char ch); | 
|  | 181 | static int hexToInt(char **ptr, int *intValue); | 
|  | 182 | static unsigned char *mem2hex(const void *mem, char *buf, int count, | 
|  | 183 | int may_fault); | 
|  | 184 | static const char *hex2mem(const char *buf, void *_mem, int count, | 
|  | 185 | int may_fault); | 
|  | 186 |  | 
|  | 187 | /* | 
|  | 188 | * Convert ch from a hex digit to an int | 
|  | 189 | */ | 
|  | 190 | static int hex(unsigned char ch) | 
|  | 191 | { | 
|  | 192 | if (ch >= 'a' && ch <= 'f') | 
|  | 193 | return ch - 'a' + 10; | 
|  | 194 | if (ch >= '0' && ch <= '9') | 
|  | 195 | return ch - '0'; | 
|  | 196 | if (ch >= 'A' && ch <= 'F') | 
|  | 197 | return ch - 'A' + 10; | 
|  | 198 | return -1; | 
|  | 199 | } | 
|  | 200 |  | 
|  | 201 | #ifdef CONFIG_GDBSTUB_DEBUGGING | 
|  | 202 |  | 
|  | 203 | void debug_to_serial(const char *p, int n) | 
|  | 204 | { | 
|  | 205 | __debug_to_serial(p, n); | 
|  | 206 | /* gdbstub_console_write(NULL, p, n); */ | 
|  | 207 | } | 
|  | 208 |  | 
|  | 209 | void gdbstub_printk(const char *fmt, ...) | 
|  | 210 | { | 
|  | 211 | va_list args; | 
|  | 212 | int len; | 
|  | 213 |  | 
|  | 214 | /* Emit the output into the temporary buffer */ | 
|  | 215 | va_start(args, fmt); | 
|  | 216 | len = vsnprintf(trans_buffer, sizeof(trans_buffer), fmt, args); | 
|  | 217 | va_end(args); | 
|  | 218 | debug_to_serial(trans_buffer, len); | 
|  | 219 | } | 
|  | 220 |  | 
|  | 221 | #endif | 
|  | 222 |  | 
|  | 223 | static inline char *gdbstub_strcpy(char *dst, const char *src) | 
|  | 224 | { | 
|  | 225 | int loop = 0; | 
|  | 226 | while ((dst[loop] = src[loop])) | 
|  | 227 | loop++; | 
|  | 228 | return dst; | 
|  | 229 | } | 
|  | 230 |  | 
|  | 231 | /* | 
|  | 232 | * scan for the sequence $<data>#<checksum> | 
|  | 233 | */ | 
|  | 234 | static void getpacket(char *buffer) | 
|  | 235 | { | 
|  | 236 | unsigned char checksum; | 
|  | 237 | unsigned char xmitcsum; | 
|  | 238 | unsigned char ch; | 
|  | 239 | int count, i, ret, error; | 
|  | 240 |  | 
|  | 241 | for (;;) { | 
|  | 242 | /* | 
|  | 243 | * wait around for the start character, | 
|  | 244 | * ignore all other characters | 
|  | 245 | */ | 
|  | 246 | do { | 
|  | 247 | gdbstub_io_rx_char(&ch, 0); | 
|  | 248 | } while (ch != '$'); | 
|  | 249 |  | 
|  | 250 | checksum = 0; | 
|  | 251 | xmitcsum = -1; | 
|  | 252 | count = 0; | 
|  | 253 | error = 0; | 
|  | 254 |  | 
|  | 255 | /* | 
|  | 256 | * now, read until a # or end of buffer is found | 
|  | 257 | */ | 
|  | 258 | while (count < BUFMAX) { | 
|  | 259 | ret = gdbstub_io_rx_char(&ch, 0); | 
|  | 260 | if (ret < 0) | 
|  | 261 | error = ret; | 
|  | 262 |  | 
|  | 263 | if (ch == '#') | 
|  | 264 | break; | 
|  | 265 | checksum += ch; | 
|  | 266 | buffer[count] = ch; | 
|  | 267 | count++; | 
|  | 268 | } | 
|  | 269 |  | 
|  | 270 | if (error == -EIO) { | 
|  | 271 | gdbstub_proto("### GDB Rx Error - Skipping packet" | 
|  | 272 | " ###\n"); | 
|  | 273 | gdbstub_proto("### GDB Tx NAK\n"); | 
|  | 274 | gdbstub_io_tx_char('-'); | 
|  | 275 | continue; | 
|  | 276 | } | 
|  | 277 |  | 
|  | 278 | if (count >= BUFMAX || error) | 
|  | 279 | continue; | 
|  | 280 |  | 
|  | 281 | buffer[count] = 0; | 
|  | 282 |  | 
|  | 283 | /* read the checksum */ | 
|  | 284 | ret = gdbstub_io_rx_char(&ch, 0); | 
|  | 285 | if (ret < 0) | 
|  | 286 | error = ret; | 
|  | 287 | xmitcsum = hex(ch) << 4; | 
|  | 288 |  | 
|  | 289 | ret = gdbstub_io_rx_char(&ch, 0); | 
|  | 290 | if (ret < 0) | 
|  | 291 | error = ret; | 
|  | 292 | xmitcsum |= hex(ch); | 
|  | 293 |  | 
|  | 294 | if (error) { | 
|  | 295 | if (error == -EIO) | 
|  | 296 | gdbstub_io("### GDB Rx Error -" | 
|  | 297 | " Skipping packet\n"); | 
|  | 298 | gdbstub_io("### GDB Tx NAK\n"); | 
|  | 299 | gdbstub_io_tx_char('-'); | 
|  | 300 | continue; | 
|  | 301 | } | 
|  | 302 |  | 
|  | 303 | /* check the checksum */ | 
|  | 304 | if (checksum != xmitcsum) { | 
|  | 305 | gdbstub_io("### GDB Tx NAK\n"); | 
|  | 306 | gdbstub_io_tx_char('-');	/* failed checksum */ | 
|  | 307 | continue; | 
|  | 308 | } | 
|  | 309 |  | 
|  | 310 | gdbstub_proto("### GDB Rx '$%s#%02x' ###\n", buffer, checksum); | 
|  | 311 | gdbstub_io("### GDB Tx ACK\n"); | 
|  | 312 | gdbstub_io_tx_char('+'); /* successful transfer */ | 
|  | 313 |  | 
|  | 314 | /* | 
|  | 315 | * if a sequence char is present, | 
|  | 316 | * reply the sequence ID | 
|  | 317 | */ | 
|  | 318 | if (buffer[2] == ':') { | 
|  | 319 | gdbstub_io_tx_char(buffer[0]); | 
|  | 320 | gdbstub_io_tx_char(buffer[1]); | 
|  | 321 |  | 
|  | 322 | /* | 
|  | 323 | * remove sequence chars from buffer | 
|  | 324 | */ | 
|  | 325 | count = 0; | 
|  | 326 | while (buffer[count]) | 
|  | 327 | count++; | 
|  | 328 | for (i = 3; i <= count; i++) | 
|  | 329 | buffer[i - 3] = buffer[i]; | 
|  | 330 | } | 
|  | 331 |  | 
|  | 332 | break; | 
|  | 333 | } | 
|  | 334 | } | 
|  | 335 |  | 
|  | 336 | /* | 
|  | 337 | * send the packet in buffer. | 
|  | 338 | * - return 0 if successfully ACK'd | 
|  | 339 | * - return 1 if abandoned due to new incoming packet | 
|  | 340 | */ | 
|  | 341 | static int putpacket(char *buffer) | 
|  | 342 | { | 
|  | 343 | unsigned char checksum; | 
|  | 344 | unsigned char ch; | 
|  | 345 | int count; | 
|  | 346 |  | 
|  | 347 | /* | 
|  | 348 | * $<packet info>#<checksum>. | 
|  | 349 | */ | 
|  | 350 | gdbstub_proto("### GDB Tx $'%s'#?? ###\n", buffer); | 
|  | 351 |  | 
|  | 352 | do { | 
|  | 353 | gdbstub_io_tx_char('$'); | 
|  | 354 | checksum = 0; | 
|  | 355 | count = 0; | 
|  | 356 |  | 
|  | 357 | while ((ch = buffer[count]) != 0) { | 
|  | 358 | gdbstub_io_tx_char(ch); | 
|  | 359 | checksum += ch; | 
|  | 360 | count += 1; | 
|  | 361 | } | 
|  | 362 |  | 
|  | 363 | gdbstub_io_tx_char('#'); | 
| Harvey Harrison | 2682497 | 2008-07-25 19:45:20 -0700 | [diff] [blame] | 364 | gdbstub_io_tx_char(hex_asc_hi(checksum)); | 
|  | 365 | gdbstub_io_tx_char(hex_asc_lo(checksum)); | 
| David Howells | b920de1 | 2008-02-08 04:19:31 -0800 | [diff] [blame] | 366 |  | 
|  | 367 | } while (gdbstub_io_rx_char(&ch, 0), | 
|  | 368 | ch == '-' && (gdbstub_io("### GDB Rx NAK\n"), 0), | 
|  | 369 | ch != '-' && ch != '+' && | 
|  | 370 | (gdbstub_io("### GDB Rx ??? %02x\n", ch), 0), | 
|  | 371 | ch != '+' && ch != '$'); | 
|  | 372 |  | 
|  | 373 | if (ch == '+') { | 
|  | 374 | gdbstub_io("### GDB Rx ACK\n"); | 
|  | 375 | return 0; | 
|  | 376 | } | 
|  | 377 |  | 
|  | 378 | gdbstub_io("### GDB Tx Abandoned\n"); | 
|  | 379 | gdbstub_rx_unget = ch; | 
|  | 380 | return 1; | 
|  | 381 | } | 
|  | 382 |  | 
|  | 383 | /* | 
|  | 384 | * While we find nice hex chars, build an int. | 
|  | 385 | * Return number of chars processed. | 
|  | 386 | */ | 
|  | 387 | static int hexToInt(char **ptr, int *intValue) | 
|  | 388 | { | 
|  | 389 | int numChars = 0; | 
|  | 390 | int hexValue; | 
|  | 391 |  | 
|  | 392 | *intValue = 0; | 
|  | 393 |  | 
|  | 394 | while (**ptr) { | 
|  | 395 | hexValue = hex(**ptr); | 
|  | 396 | if (hexValue < 0) | 
|  | 397 | break; | 
|  | 398 |  | 
|  | 399 | *intValue = (*intValue << 4) | hexValue; | 
|  | 400 | numChars++; | 
|  | 401 |  | 
|  | 402 | (*ptr)++; | 
|  | 403 | } | 
|  | 404 |  | 
|  | 405 | return (numChars); | 
|  | 406 | } | 
|  | 407 |  | 
|  | 408 | /* | 
|  | 409 | * We single-step by setting breakpoints. When an exception | 
|  | 410 | * is handled, we need to restore the instructions hoisted | 
|  | 411 | * when the breakpoints were set. | 
|  | 412 | * | 
|  | 413 | * This is where we save the original instructions. | 
|  | 414 | */ | 
|  | 415 | static struct gdb_bp_save { | 
|  | 416 | u8	*addr; | 
|  | 417 | u8	opcode[2]; | 
|  | 418 | } step_bp[2]; | 
|  | 419 |  | 
|  | 420 | static const unsigned char gdbstub_insn_sizes[256] = | 
|  | 421 | { | 
|  | 422 | /* 1  2  3  4  5  6  7  8  9  a  b  c  d  e  f */ | 
|  | 423 | 1, 3, 3, 3, 1, 3, 3, 3, 1, 3, 3, 3, 1, 3, 3, 3,	/* 0 */ | 
|  | 424 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 1 */ | 
|  | 425 | 2, 2, 2, 2, 3, 3, 3, 3, 2, 2, 2, 2, 3, 3, 3, 3, /* 2 */ | 
|  | 426 | 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 1, 1, 1, /* 3 */ | 
|  | 427 | 1, 1, 2, 2, 1, 1, 2, 2, 1, 1, 2, 2, 1, 1, 2, 2, /* 4 */ | 
|  | 428 | 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, /* 5 */ | 
|  | 429 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 6 */ | 
|  | 430 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 7 */ | 
|  | 431 | 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, /* 8 */ | 
|  | 432 | 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, /* 9 */ | 
|  | 433 | 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, /* a */ | 
|  | 434 | 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, /* b */ | 
|  | 435 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 2, 2, /* c */ | 
|  | 436 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* d */ | 
|  | 437 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* e */ | 
|  | 438 | 0, 2, 2, 2, 2, 2, 2, 4, 0, 3, 0, 4, 0, 6, 7, 1  /* f */ | 
|  | 439 | }; | 
|  | 440 |  | 
|  | 441 | static int __gdbstub_mark_bp(u8 *addr, int ix) | 
|  | 442 | { | 
|  | 443 | if (addr < (u8 *) 0x70000000UL) | 
|  | 444 | return 0; | 
|  | 445 | /* 70000000-7fffffff: vmalloc area */ | 
|  | 446 | if (addr < (u8 *) 0x80000000UL) | 
|  | 447 | goto okay; | 
|  | 448 | if (addr < (u8 *) 0x8c000000UL) | 
|  | 449 | return 0; | 
|  | 450 | /* 8c000000-93ffffff: SRAM, SDRAM */ | 
|  | 451 | if (addr < (u8 *) 0x94000000UL) | 
|  | 452 | goto okay; | 
|  | 453 | return 0; | 
|  | 454 |  | 
|  | 455 | okay: | 
|  | 456 | if (gdbstub_read_byte(addr + 0, &step_bp[ix].opcode[0]) < 0 || | 
|  | 457 | gdbstub_read_byte(addr + 1, &step_bp[ix].opcode[1]) < 0) | 
|  | 458 | return 0; | 
|  | 459 |  | 
|  | 460 | step_bp[ix].addr = addr; | 
|  | 461 | return 1; | 
|  | 462 | } | 
|  | 463 |  | 
|  | 464 | static inline void __gdbstub_restore_bp(void) | 
|  | 465 | { | 
|  | 466 | #ifdef GDBSTUB_USE_F7F7_AS_BREAKPOINT | 
|  | 467 | if (step_bp[0].addr) { | 
|  | 468 | gdbstub_write_byte(step_bp[0].opcode[0], step_bp[0].addr + 0); | 
|  | 469 | gdbstub_write_byte(step_bp[0].opcode[1], step_bp[0].addr + 1); | 
|  | 470 | } | 
|  | 471 | if (step_bp[1].addr) { | 
|  | 472 | gdbstub_write_byte(step_bp[1].opcode[0], step_bp[1].addr + 0); | 
|  | 473 | gdbstub_write_byte(step_bp[1].opcode[1], step_bp[1].addr + 1); | 
|  | 474 | } | 
|  | 475 | #else | 
|  | 476 | if (step_bp[0].addr) | 
|  | 477 | gdbstub_write_byte(step_bp[0].opcode[0], step_bp[0].addr + 0); | 
|  | 478 | if (step_bp[1].addr) | 
|  | 479 | gdbstub_write_byte(step_bp[1].opcode[0], step_bp[1].addr + 0); | 
|  | 480 | #endif | 
|  | 481 |  | 
|  | 482 | gdbstub_flush_caches = 1; | 
|  | 483 |  | 
|  | 484 | step_bp[0].addr		= NULL; | 
|  | 485 | step_bp[0].opcode[0]	= 0; | 
|  | 486 | step_bp[0].opcode[1]	= 0; | 
|  | 487 | step_bp[1].addr		= NULL; | 
|  | 488 | step_bp[1].opcode[0]	= 0; | 
|  | 489 | step_bp[1].opcode[1]	= 0; | 
|  | 490 | } | 
|  | 491 |  | 
|  | 492 | /* | 
|  | 493 | * emulate single stepping by means of breakpoint instructions | 
|  | 494 | */ | 
|  | 495 | static int gdbstub_single_step(struct pt_regs *regs) | 
|  | 496 | { | 
|  | 497 | unsigned size; | 
|  | 498 | uint32_t x; | 
|  | 499 | uint8_t cur, *pc, *sp; | 
|  | 500 |  | 
|  | 501 | step_bp[0].addr		= NULL; | 
|  | 502 | step_bp[0].opcode[0]	= 0; | 
|  | 503 | step_bp[0].opcode[1]	= 0; | 
|  | 504 | step_bp[1].addr		= NULL; | 
|  | 505 | step_bp[1].opcode[0]	= 0; | 
|  | 506 | step_bp[1].opcode[1]	= 0; | 
|  | 507 | x = 0; | 
|  | 508 |  | 
|  | 509 | pc = (u8 *) regs->pc; | 
|  | 510 | sp = (u8 *) (regs + 1); | 
|  | 511 | if (gdbstub_read_byte(pc, &cur) < 0) | 
|  | 512 | return -EFAULT; | 
|  | 513 |  | 
|  | 514 | gdbstub_bkpt("Single Step from %p { %02x }\n", pc, cur); | 
|  | 515 |  | 
|  | 516 | gdbstub_flush_caches = 1; | 
|  | 517 |  | 
|  | 518 | size = gdbstub_insn_sizes[cur]; | 
|  | 519 | if (size > 0) { | 
|  | 520 | if (!__gdbstub_mark_bp(pc + size, 0)) | 
|  | 521 | goto fault; | 
|  | 522 | } else { | 
|  | 523 | switch (cur) { | 
|  | 524 | /* Bxx (d8,PC) */ | 
| Robert P. J. Day | 499c59c | 2008-11-28 11:48:37 +0000 | [diff] [blame] | 525 | case 0xc0 ... 0xca: | 
| David Howells | b920de1 | 2008-02-08 04:19:31 -0800 | [diff] [blame] | 526 | if (gdbstub_read_byte(pc + 1, (u8 *) &x) < 0) | 
|  | 527 | goto fault; | 
|  | 528 | if (!__gdbstub_mark_bp(pc + 2, 0)) | 
|  | 529 | goto fault; | 
|  | 530 | if ((x < 0 || x > 2) && | 
|  | 531 | !__gdbstub_mark_bp(pc + (s8) x, 1)) | 
|  | 532 | goto fault; | 
|  | 533 | break; | 
|  | 534 |  | 
|  | 535 | /* LXX (d8,PC) */ | 
| Robert P. J. Day | 499c59c | 2008-11-28 11:48:37 +0000 | [diff] [blame] | 536 | case 0xd0 ... 0xda: | 
| David Howells | b920de1 | 2008-02-08 04:19:31 -0800 | [diff] [blame] | 537 | if (!__gdbstub_mark_bp(pc + 1, 0)) | 
|  | 538 | goto fault; | 
|  | 539 | if (regs->pc != regs->lar && | 
|  | 540 | !__gdbstub_mark_bp((u8 *) regs->lar, 1)) | 
|  | 541 | goto fault; | 
|  | 542 | break; | 
|  | 543 |  | 
|  | 544 | /* SETLB - loads the next for bytes into the LIR | 
|  | 545 | * register */ | 
|  | 546 | case 0xdb: | 
|  | 547 | if (!__gdbstub_mark_bp(pc + 1, 0)) | 
|  | 548 | goto fault; | 
|  | 549 | break; | 
|  | 550 |  | 
|  | 551 | /* JMP (d16,PC) or CALL (d16,PC) */ | 
|  | 552 | case 0xcc: | 
|  | 553 | case 0xcd: | 
|  | 554 | if (gdbstub_read_byte(pc + 1, ((u8 *) &x) + 0) < 0 || | 
|  | 555 | gdbstub_read_byte(pc + 2, ((u8 *) &x) + 1) < 0) | 
|  | 556 | goto fault; | 
|  | 557 | if (!__gdbstub_mark_bp(pc + (s16) x, 0)) | 
|  | 558 | goto fault; | 
|  | 559 | break; | 
|  | 560 |  | 
|  | 561 | /* JMP (d32,PC) or CALL (d32,PC) */ | 
|  | 562 | case 0xdc: | 
|  | 563 | case 0xdd: | 
|  | 564 | if (gdbstub_read_byte(pc + 1, ((u8 *) &x) + 0) < 0 || | 
|  | 565 | gdbstub_read_byte(pc + 2, ((u8 *) &x) + 1) < 0 || | 
|  | 566 | gdbstub_read_byte(pc + 3, ((u8 *) &x) + 2) < 0 || | 
|  | 567 | gdbstub_read_byte(pc + 4, ((u8 *) &x) + 3) < 0) | 
|  | 568 | goto fault; | 
|  | 569 | if (!__gdbstub_mark_bp(pc + (s32) x, 0)) | 
|  | 570 | goto fault; | 
|  | 571 | break; | 
|  | 572 |  | 
|  | 573 | /* RETF */ | 
|  | 574 | case 0xde: | 
|  | 575 | if (!__gdbstub_mark_bp((u8 *) regs->mdr, 0)) | 
|  | 576 | goto fault; | 
|  | 577 | break; | 
|  | 578 |  | 
|  | 579 | /* RET */ | 
|  | 580 | case 0xdf: | 
|  | 581 | if (gdbstub_read_byte(pc + 2, (u8 *) &x) < 0) | 
|  | 582 | goto fault; | 
|  | 583 | sp += (s8)x; | 
|  | 584 | if (gdbstub_read_byte(sp + 0, ((u8 *) &x) + 0) < 0 || | 
|  | 585 | gdbstub_read_byte(sp + 1, ((u8 *) &x) + 1) < 0 || | 
|  | 586 | gdbstub_read_byte(sp + 2, ((u8 *) &x) + 2) < 0 || | 
|  | 587 | gdbstub_read_byte(sp + 3, ((u8 *) &x) + 3) < 0) | 
|  | 588 | goto fault; | 
|  | 589 | if (!__gdbstub_mark_bp((u8 *) x, 0)) | 
|  | 590 | goto fault; | 
|  | 591 | break; | 
|  | 592 |  | 
|  | 593 | case 0xf0: | 
|  | 594 | if (gdbstub_read_byte(pc + 1, &cur) < 0) | 
|  | 595 | goto fault; | 
|  | 596 |  | 
|  | 597 | if (cur >= 0xf0 && cur <= 0xf7) { | 
|  | 598 | /* JMP (An) / CALLS (An) */ | 
|  | 599 | switch (cur & 3) { | 
|  | 600 | case 0: x = regs->a0; break; | 
|  | 601 | case 1: x = regs->a1; break; | 
|  | 602 | case 2: x = regs->a2; break; | 
|  | 603 | case 3: x = regs->a3; break; | 
|  | 604 | } | 
|  | 605 | if (!__gdbstub_mark_bp((u8 *) x, 0)) | 
|  | 606 | goto fault; | 
|  | 607 | } else if (cur == 0xfc) { | 
|  | 608 | /* RETS */ | 
|  | 609 | if (gdbstub_read_byte( | 
|  | 610 | sp + 0, ((u8 *) &x) + 0) < 0 || | 
|  | 611 | gdbstub_read_byte( | 
|  | 612 | sp + 1, ((u8 *) &x) + 1) < 0 || | 
|  | 613 | gdbstub_read_byte( | 
|  | 614 | sp + 2, ((u8 *) &x) + 2) < 0 || | 
|  | 615 | gdbstub_read_byte( | 
|  | 616 | sp + 3, ((u8 *) &x) + 3) < 0) | 
|  | 617 | goto fault; | 
|  | 618 | if (!__gdbstub_mark_bp((u8 *) x, 0)) | 
|  | 619 | goto fault; | 
|  | 620 | } else if (cur == 0xfd) { | 
|  | 621 | /* RTI */ | 
|  | 622 | if (gdbstub_read_byte( | 
|  | 623 | sp + 4, ((u8 *) &x) + 0) < 0 || | 
|  | 624 | gdbstub_read_byte( | 
|  | 625 | sp + 5, ((u8 *) &x) + 1) < 0 || | 
|  | 626 | gdbstub_read_byte( | 
|  | 627 | sp + 6, ((u8 *) &x) + 2) < 0 || | 
|  | 628 | gdbstub_read_byte( | 
|  | 629 | sp + 7, ((u8 *) &x) + 3) < 0) | 
|  | 630 | goto fault; | 
|  | 631 | if (!__gdbstub_mark_bp((u8 *) x, 0)) | 
|  | 632 | goto fault; | 
|  | 633 | } else { | 
|  | 634 | if (!__gdbstub_mark_bp(pc + 2, 0)) | 
|  | 635 | goto fault; | 
|  | 636 | } | 
|  | 637 |  | 
|  | 638 | break; | 
|  | 639 |  | 
|  | 640 | /* potential 3-byte conditional branches */ | 
|  | 641 | case 0xf8: | 
|  | 642 | if (gdbstub_read_byte(pc + 1, &cur) < 0) | 
|  | 643 | goto fault; | 
|  | 644 | if (!__gdbstub_mark_bp(pc + 3, 0)) | 
|  | 645 | goto fault; | 
|  | 646 |  | 
|  | 647 | if (cur >= 0xe8 && cur <= 0xeb) { | 
|  | 648 | if (gdbstub_read_byte( | 
|  | 649 | pc + 2, ((u8 *) &x) + 0) < 0) | 
|  | 650 | goto fault; | 
|  | 651 | if ((x < 0 || x > 3) && | 
|  | 652 | !__gdbstub_mark_bp(pc + (s8) x, 1)) | 
|  | 653 | goto fault; | 
|  | 654 | } | 
|  | 655 | break; | 
|  | 656 |  | 
|  | 657 | case 0xfa: | 
|  | 658 | if (gdbstub_read_byte(pc + 1, &cur) < 0) | 
|  | 659 | goto fault; | 
|  | 660 |  | 
|  | 661 | if (cur == 0xff) { | 
|  | 662 | /* CALLS (d16,PC) */ | 
|  | 663 | if (gdbstub_read_byte( | 
|  | 664 | pc + 2, ((u8 *) &x) + 0) < 0 || | 
|  | 665 | gdbstub_read_byte( | 
|  | 666 | pc + 3, ((u8 *) &x) + 1) < 0) | 
|  | 667 | goto fault; | 
|  | 668 | if (!__gdbstub_mark_bp(pc + (s16) x, 0)) | 
|  | 669 | goto fault; | 
|  | 670 | } else { | 
|  | 671 | if (!__gdbstub_mark_bp(pc + 4, 0)) | 
|  | 672 | goto fault; | 
|  | 673 | } | 
|  | 674 | break; | 
|  | 675 |  | 
|  | 676 | case 0xfc: | 
|  | 677 | if (gdbstub_read_byte(pc + 1, &cur) < 0) | 
|  | 678 | goto fault; | 
|  | 679 | if (cur == 0xff) { | 
|  | 680 | /* CALLS (d32,PC) */ | 
|  | 681 | if (gdbstub_read_byte( | 
|  | 682 | pc + 2, ((u8 *) &x) + 0) < 0 || | 
|  | 683 | gdbstub_read_byte( | 
|  | 684 | pc + 3, ((u8 *) &x) + 1) < 0 || | 
|  | 685 | gdbstub_read_byte( | 
|  | 686 | pc + 4, ((u8 *) &x) + 2) < 0 || | 
|  | 687 | gdbstub_read_byte( | 
|  | 688 | pc + 5, ((u8 *) &x) + 3) < 0) | 
|  | 689 | goto fault; | 
|  | 690 | if (!__gdbstub_mark_bp( | 
|  | 691 | pc + (s32) x, 0)) | 
|  | 692 | goto fault; | 
|  | 693 | } else { | 
|  | 694 | if (!__gdbstub_mark_bp( | 
|  | 695 | pc + 6, 0)) | 
|  | 696 | goto fault; | 
|  | 697 | } | 
|  | 698 | break; | 
|  | 699 |  | 
|  | 700 | } | 
|  | 701 | } | 
|  | 702 |  | 
|  | 703 | gdbstub_bkpt("Step: %02x at %p; %02x at %p\n", | 
|  | 704 | step_bp[0].opcode[0], step_bp[0].addr, | 
|  | 705 | step_bp[1].opcode[0], step_bp[1].addr); | 
|  | 706 |  | 
|  | 707 | if (step_bp[0].addr) { | 
|  | 708 | #ifdef GDBSTUB_USE_F7F7_AS_BREAKPOINT | 
|  | 709 | if (gdbstub_write_byte(0xF7, step_bp[0].addr + 0) < 0 || | 
|  | 710 | gdbstub_write_byte(0xF7, step_bp[0].addr + 1) < 0) | 
|  | 711 | goto fault; | 
|  | 712 | #else | 
|  | 713 | if (gdbstub_write_byte(0xFF, step_bp[0].addr + 0) < 0) | 
|  | 714 | goto fault; | 
|  | 715 | #endif | 
|  | 716 | } | 
|  | 717 |  | 
|  | 718 | if (step_bp[1].addr) { | 
|  | 719 | #ifdef GDBSTUB_USE_F7F7_AS_BREAKPOINT | 
|  | 720 | if (gdbstub_write_byte(0xF7, step_bp[1].addr + 0) < 0 || | 
|  | 721 | gdbstub_write_byte(0xF7, step_bp[1].addr + 1) < 0) | 
|  | 722 | goto fault; | 
|  | 723 | #else | 
|  | 724 | if (gdbstub_write_byte(0xFF, step_bp[1].addr + 0) < 0) | 
|  | 725 | goto fault; | 
|  | 726 | #endif | 
|  | 727 | } | 
|  | 728 |  | 
|  | 729 | return 0; | 
|  | 730 |  | 
|  | 731 | fault: | 
|  | 732 | /* uh-oh - silly address alert, try and restore things */ | 
|  | 733 | __gdbstub_restore_bp(); | 
|  | 734 | return -EFAULT; | 
|  | 735 | } | 
|  | 736 |  | 
|  | 737 | #ifdef CONFIG_GDBSTUB_CONSOLE | 
|  | 738 |  | 
|  | 739 | void gdbstub_console_write(struct console *con, const char *p, unsigned n) | 
|  | 740 | { | 
|  | 741 | static const char gdbstub_cr[] = { 0x0d }; | 
|  | 742 | char outbuf[26]; | 
|  | 743 | int qty; | 
|  | 744 | u8 busy; | 
|  | 745 |  | 
|  | 746 | busy = gdbstub_busy; | 
|  | 747 | gdbstub_busy = 1; | 
|  | 748 |  | 
|  | 749 | outbuf[0] = 'O'; | 
|  | 750 |  | 
|  | 751 | while (n > 0) { | 
|  | 752 | qty = 1; | 
|  | 753 |  | 
|  | 754 | while (n > 0 && qty < 20) { | 
|  | 755 | mem2hex(p, outbuf + qty, 2, 0); | 
|  | 756 | qty += 2; | 
|  | 757 | if (*p == 0x0a) { | 
|  | 758 | mem2hex(gdbstub_cr, outbuf + qty, 2, 0); | 
|  | 759 | qty += 2; | 
|  | 760 | } | 
|  | 761 | p++; | 
|  | 762 | n--; | 
|  | 763 | } | 
|  | 764 |  | 
|  | 765 | outbuf[qty] = 0; | 
|  | 766 | putpacket(outbuf); | 
|  | 767 | } | 
|  | 768 |  | 
|  | 769 | gdbstub_busy = busy; | 
|  | 770 | } | 
|  | 771 |  | 
|  | 772 | static kdev_t gdbstub_console_dev(struct console *con) | 
|  | 773 | { | 
|  | 774 | return MKDEV(1, 3); /* /dev/null */ | 
|  | 775 | } | 
|  | 776 |  | 
|  | 777 | static struct console gdbstub_console = { | 
|  | 778 | .name	= "gdb", | 
|  | 779 | .write	= gdbstub_console_write, | 
|  | 780 | .device	= gdbstub_console_dev, | 
|  | 781 | .flags	= CON_PRINTBUFFER, | 
|  | 782 | .index	= -1, | 
|  | 783 | }; | 
|  | 784 |  | 
|  | 785 | #endif | 
|  | 786 |  | 
|  | 787 | /* | 
|  | 788 | * Convert the memory pointed to by mem into hex, placing result in buf. | 
|  | 789 | * - if successful, return a pointer to the last char put in buf (NUL) | 
|  | 790 | * - in case of mem fault, return NULL | 
|  | 791 | * may_fault is non-zero if we are reading from arbitrary memory, but is | 
|  | 792 | * currently not used. | 
|  | 793 | */ | 
|  | 794 | static | 
|  | 795 | unsigned char *mem2hex(const void *_mem, char *buf, int count, int may_fault) | 
|  | 796 | { | 
|  | 797 | const u8 *mem = _mem; | 
|  | 798 | u8 ch[4]; | 
|  | 799 |  | 
|  | 800 | if ((u32) mem & 1 && count >= 1) { | 
|  | 801 | if (gdbstub_read_byte(mem, ch) != 0) | 
|  | 802 | return 0; | 
| Harvey Harrison | 2682497 | 2008-07-25 19:45:20 -0700 | [diff] [blame] | 803 | buf = pack_hex_byte(buf, ch[0]); | 
| David Howells | b920de1 | 2008-02-08 04:19:31 -0800 | [diff] [blame] | 804 | mem++; | 
|  | 805 | count--; | 
|  | 806 | } | 
|  | 807 |  | 
|  | 808 | if ((u32) mem & 3 && count >= 2) { | 
|  | 809 | if (gdbstub_read_word(mem, ch) != 0) | 
|  | 810 | return 0; | 
| Harvey Harrison | 2682497 | 2008-07-25 19:45:20 -0700 | [diff] [blame] | 811 | buf = pack_hex_byte(buf, ch[0]); | 
|  | 812 | buf = pack_hex_byte(buf, ch[1]); | 
| David Howells | b920de1 | 2008-02-08 04:19:31 -0800 | [diff] [blame] | 813 | mem += 2; | 
|  | 814 | count -= 2; | 
|  | 815 | } | 
|  | 816 |  | 
|  | 817 | while (count >= 4) { | 
|  | 818 | if (gdbstub_read_dword(mem, ch) != 0) | 
|  | 819 | return 0; | 
| Harvey Harrison | 2682497 | 2008-07-25 19:45:20 -0700 | [diff] [blame] | 820 | buf = pack_hex_byte(buf, ch[0]); | 
|  | 821 | buf = pack_hex_byte(buf, ch[1]); | 
|  | 822 | buf = pack_hex_byte(buf, ch[2]); | 
|  | 823 | buf = pack_hex_byte(buf, ch[3]); | 
| David Howells | b920de1 | 2008-02-08 04:19:31 -0800 | [diff] [blame] | 824 | mem += 4; | 
|  | 825 | count -= 4; | 
|  | 826 | } | 
|  | 827 |  | 
|  | 828 | if (count >= 2) { | 
|  | 829 | if (gdbstub_read_word(mem, ch) != 0) | 
|  | 830 | return 0; | 
| Harvey Harrison | 2682497 | 2008-07-25 19:45:20 -0700 | [diff] [blame] | 831 | buf = pack_hex_byte(buf, ch[0]); | 
|  | 832 | buf = pack_hex_byte(buf, ch[1]); | 
| David Howells | b920de1 | 2008-02-08 04:19:31 -0800 | [diff] [blame] | 833 | mem += 2; | 
|  | 834 | count -= 2; | 
|  | 835 | } | 
|  | 836 |  | 
|  | 837 | if (count >= 1) { | 
|  | 838 | if (gdbstub_read_byte(mem, ch) != 0) | 
|  | 839 | return 0; | 
| Harvey Harrison | 2682497 | 2008-07-25 19:45:20 -0700 | [diff] [blame] | 840 | buf = pack_hex_byte(buf, ch[0]); | 
| David Howells | b920de1 | 2008-02-08 04:19:31 -0800 | [diff] [blame] | 841 | } | 
|  | 842 |  | 
|  | 843 | *buf = 0; | 
|  | 844 | return buf; | 
|  | 845 | } | 
|  | 846 |  | 
|  | 847 | /* | 
|  | 848 | * convert the hex array pointed to by buf into binary to be placed in mem | 
|  | 849 | * return a pointer to the character AFTER the last byte written | 
|  | 850 | * may_fault is non-zero if we are reading from arbitrary memory, but is | 
|  | 851 | * currently not used. | 
|  | 852 | */ | 
|  | 853 | static | 
|  | 854 | const char *hex2mem(const char *buf, void *_mem, int count, int may_fault) | 
|  | 855 | { | 
|  | 856 | u8 *mem = _mem; | 
|  | 857 | union { | 
|  | 858 | u32 val; | 
|  | 859 | u8 b[4]; | 
|  | 860 | } ch; | 
|  | 861 |  | 
|  | 862 | if ((u32) mem & 1 && count >= 1) { | 
|  | 863 | ch.b[0]  = hex(*buf++) << 4; | 
|  | 864 | ch.b[0] |= hex(*buf++); | 
|  | 865 | if (gdbstub_write_byte(ch.val, mem) != 0) | 
|  | 866 | return 0; | 
|  | 867 | mem++; | 
|  | 868 | count--; | 
|  | 869 | } | 
|  | 870 |  | 
|  | 871 | if ((u32) mem & 3 && count >= 2) { | 
|  | 872 | ch.b[0]  = hex(*buf++) << 4; | 
|  | 873 | ch.b[0] |= hex(*buf++); | 
|  | 874 | ch.b[1]  = hex(*buf++) << 4; | 
|  | 875 | ch.b[1] |= hex(*buf++); | 
|  | 876 | if (gdbstub_write_word(ch.val, mem) != 0) | 
|  | 877 | return 0; | 
|  | 878 | mem += 2; | 
|  | 879 | count -= 2; | 
|  | 880 | } | 
|  | 881 |  | 
|  | 882 | while (count >= 4) { | 
|  | 883 | ch.b[0]  = hex(*buf++) << 4; | 
|  | 884 | ch.b[0] |= hex(*buf++); | 
|  | 885 | ch.b[1]  = hex(*buf++) << 4; | 
|  | 886 | ch.b[1] |= hex(*buf++); | 
|  | 887 | ch.b[2]  = hex(*buf++) << 4; | 
|  | 888 | ch.b[2] |= hex(*buf++); | 
|  | 889 | ch.b[3]  = hex(*buf++) << 4; | 
|  | 890 | ch.b[3] |= hex(*buf++); | 
|  | 891 | if (gdbstub_write_dword(ch.val, mem) != 0) | 
|  | 892 | return 0; | 
|  | 893 | mem += 4; | 
|  | 894 | count -= 4; | 
|  | 895 | } | 
|  | 896 |  | 
|  | 897 | if (count >= 2) { | 
|  | 898 | ch.b[0]  = hex(*buf++) << 4; | 
|  | 899 | ch.b[0] |= hex(*buf++); | 
|  | 900 | ch.b[1]  = hex(*buf++) << 4; | 
|  | 901 | ch.b[1] |= hex(*buf++); | 
|  | 902 | if (gdbstub_write_word(ch.val, mem) != 0) | 
|  | 903 | return 0; | 
|  | 904 | mem += 2; | 
|  | 905 | count -= 2; | 
|  | 906 | } | 
|  | 907 |  | 
|  | 908 | if (count >= 1) { | 
|  | 909 | ch.b[0]  = hex(*buf++) << 4; | 
|  | 910 | ch.b[0] |= hex(*buf++); | 
|  | 911 | if (gdbstub_write_byte(ch.val, mem) != 0) | 
|  | 912 | return 0; | 
|  | 913 | } | 
|  | 914 |  | 
|  | 915 | return buf; | 
|  | 916 | } | 
|  | 917 |  | 
|  | 918 | /* | 
|  | 919 | * This table contains the mapping between MN10300 exception codes, and | 
|  | 920 | * signals, which are primarily what GDB understands.  It also indicates | 
|  | 921 | * which hardware traps we need to commandeer when initializing the stub. | 
|  | 922 | */ | 
|  | 923 | static const struct excep_to_sig_map { | 
|  | 924 | enum exception_code	excep;	/* MN10300 exception code */ | 
|  | 925 | unsigned char		signo;	/* Signal that we map this into */ | 
|  | 926 | } excep_to_sig_map[] = { | 
|  | 927 | { EXCEP_ITLBMISS,	SIGSEGV		}, | 
|  | 928 | { EXCEP_DTLBMISS,	SIGSEGV		}, | 
|  | 929 | { EXCEP_TRAP,		SIGTRAP		}, | 
|  | 930 | { EXCEP_ISTEP,		SIGTRAP		}, | 
|  | 931 | { EXCEP_IBREAK,		SIGTRAP		}, | 
|  | 932 | { EXCEP_OBREAK,		SIGTRAP		}, | 
|  | 933 | { EXCEP_UNIMPINS,	SIGILL		}, | 
|  | 934 | { EXCEP_UNIMPEXINS,	SIGILL		}, | 
|  | 935 | { EXCEP_MEMERR,		SIGSEGV		}, | 
|  | 936 | { EXCEP_MISALIGN,	SIGSEGV		}, | 
|  | 937 | { EXCEP_BUSERROR,	SIGBUS		}, | 
|  | 938 | { EXCEP_ILLINSACC,	SIGSEGV		}, | 
|  | 939 | { EXCEP_ILLDATACC,	SIGSEGV		}, | 
|  | 940 | { EXCEP_IOINSACC,	SIGSEGV		}, | 
|  | 941 | { EXCEP_PRIVINSACC,	SIGSEGV		}, | 
|  | 942 | { EXCEP_PRIVDATACC,	SIGSEGV		}, | 
|  | 943 | { EXCEP_FPU_DISABLED,	SIGFPE		}, | 
|  | 944 | { EXCEP_FPU_UNIMPINS,	SIGFPE		}, | 
|  | 945 | { EXCEP_FPU_OPERATION,	SIGFPE		}, | 
|  | 946 | { EXCEP_WDT,		SIGALRM		}, | 
|  | 947 | { EXCEP_NMI,		SIGQUIT		}, | 
|  | 948 | { EXCEP_IRQ_LEVEL0,	SIGINT		}, | 
|  | 949 | { EXCEP_IRQ_LEVEL1,	SIGINT		}, | 
|  | 950 | { EXCEP_IRQ_LEVEL2,	SIGINT		}, | 
|  | 951 | { EXCEP_IRQ_LEVEL3,	SIGINT		}, | 
|  | 952 | { EXCEP_IRQ_LEVEL4,	SIGINT		}, | 
|  | 953 | { EXCEP_IRQ_LEVEL5,	SIGINT		}, | 
|  | 954 | { EXCEP_IRQ_LEVEL6,	SIGINT		}, | 
|  | 955 | { 0, 0} | 
|  | 956 | }; | 
|  | 957 |  | 
|  | 958 | /* | 
|  | 959 | * convert the MN10300 exception code into a UNIX signal number | 
|  | 960 | */ | 
|  | 961 | static int computeSignal(enum exception_code excep) | 
|  | 962 | { | 
|  | 963 | const struct excep_to_sig_map *map; | 
|  | 964 |  | 
|  | 965 | for (map = excep_to_sig_map; map->signo; map++) | 
|  | 966 | if (map->excep == excep) | 
|  | 967 | return map->signo; | 
|  | 968 |  | 
|  | 969 | return SIGHUP; /* default for things we don't know about */ | 
|  | 970 | } | 
|  | 971 |  | 
|  | 972 | static u32 gdbstub_fpcr, gdbstub_fpufs_array[32]; | 
|  | 973 |  | 
|  | 974 | /* | 
|  | 975 | * | 
|  | 976 | */ | 
|  | 977 | static void gdbstub_store_fpu(void) | 
|  | 978 | { | 
|  | 979 | #ifdef CONFIG_FPU | 
|  | 980 |  | 
|  | 981 | asm volatile( | 
|  | 982 | "or %2,epsw\n" | 
|  | 983 | #ifdef CONFIG_MN10300_PROC_MN103E010 | 
|  | 984 | "nop\n" | 
|  | 985 | "nop\n" | 
|  | 986 | #endif | 
|  | 987 | "mov %1, a1\n" | 
|  | 988 | "fmov fs0,  (a1+)\n" | 
|  | 989 | "fmov fs1,  (a1+)\n" | 
|  | 990 | "fmov fs2,  (a1+)\n" | 
|  | 991 | "fmov fs3,  (a1+)\n" | 
|  | 992 | "fmov fs4,  (a1+)\n" | 
|  | 993 | "fmov fs5,  (a1+)\n" | 
|  | 994 | "fmov fs6,  (a1+)\n" | 
|  | 995 | "fmov fs7,  (a1+)\n" | 
|  | 996 | "fmov fs8,  (a1+)\n" | 
|  | 997 | "fmov fs9,  (a1+)\n" | 
|  | 998 | "fmov fs10, (a1+)\n" | 
|  | 999 | "fmov fs11, (a1+)\n" | 
|  | 1000 | "fmov fs12, (a1+)\n" | 
|  | 1001 | "fmov fs13, (a1+)\n" | 
|  | 1002 | "fmov fs14, (a1+)\n" | 
|  | 1003 | "fmov fs15, (a1+)\n" | 
|  | 1004 | "fmov fs16, (a1+)\n" | 
|  | 1005 | "fmov fs17, (a1+)\n" | 
|  | 1006 | "fmov fs18, (a1+)\n" | 
|  | 1007 | "fmov fs19, (a1+)\n" | 
|  | 1008 | "fmov fs20, (a1+)\n" | 
|  | 1009 | "fmov fs21, (a1+)\n" | 
|  | 1010 | "fmov fs22, (a1+)\n" | 
|  | 1011 | "fmov fs23, (a1+)\n" | 
|  | 1012 | "fmov fs24, (a1+)\n" | 
|  | 1013 | "fmov fs25, (a1+)\n" | 
|  | 1014 | "fmov fs26, (a1+)\n" | 
|  | 1015 | "fmov fs27, (a1+)\n" | 
|  | 1016 | "fmov fs28, (a1+)\n" | 
|  | 1017 | "fmov fs29, (a1+)\n" | 
|  | 1018 | "fmov fs30, (a1+)\n" | 
|  | 1019 | "fmov fs31, (a1+)\n" | 
|  | 1020 | "fmov fpcr, %0\n" | 
|  | 1021 | : "=d"(gdbstub_fpcr) | 
|  | 1022 | : "g" (&gdbstub_fpufs_array), "i"(EPSW_FE) | 
|  | 1023 | : "a1" | 
|  | 1024 | ); | 
|  | 1025 | #endif | 
|  | 1026 | } | 
|  | 1027 |  | 
|  | 1028 | /* | 
|  | 1029 | * | 
|  | 1030 | */ | 
|  | 1031 | static void gdbstub_load_fpu(void) | 
|  | 1032 | { | 
|  | 1033 | #ifdef CONFIG_FPU | 
|  | 1034 |  | 
|  | 1035 | asm volatile( | 
|  | 1036 | "or %1,epsw\n" | 
|  | 1037 | #ifdef CONFIG_MN10300_PROC_MN103E010 | 
|  | 1038 | "nop\n" | 
|  | 1039 | "nop\n" | 
|  | 1040 | #endif | 
|  | 1041 | "mov %0, a1\n" | 
|  | 1042 | "fmov (a1+), fs0\n" | 
|  | 1043 | "fmov (a1+), fs1\n" | 
|  | 1044 | "fmov (a1+), fs2\n" | 
|  | 1045 | "fmov (a1+), fs3\n" | 
|  | 1046 | "fmov (a1+), fs4\n" | 
|  | 1047 | "fmov (a1+), fs5\n" | 
|  | 1048 | "fmov (a1+), fs6\n" | 
|  | 1049 | "fmov (a1+), fs7\n" | 
|  | 1050 | "fmov (a1+), fs8\n" | 
|  | 1051 | "fmov (a1+), fs9\n" | 
|  | 1052 | "fmov (a1+), fs10\n" | 
|  | 1053 | "fmov (a1+), fs11\n" | 
|  | 1054 | "fmov (a1+), fs12\n" | 
|  | 1055 | "fmov (a1+), fs13\n" | 
|  | 1056 | "fmov (a1+), fs14\n" | 
|  | 1057 | "fmov (a1+), fs15\n" | 
|  | 1058 | "fmov (a1+), fs16\n" | 
|  | 1059 | "fmov (a1+), fs17\n" | 
|  | 1060 | "fmov (a1+), fs18\n" | 
|  | 1061 | "fmov (a1+), fs19\n" | 
|  | 1062 | "fmov (a1+), fs20\n" | 
|  | 1063 | "fmov (a1+), fs21\n" | 
|  | 1064 | "fmov (a1+), fs22\n" | 
|  | 1065 | "fmov (a1+), fs23\n" | 
|  | 1066 | "fmov (a1+), fs24\n" | 
|  | 1067 | "fmov (a1+), fs25\n" | 
|  | 1068 | "fmov (a1+), fs26\n" | 
|  | 1069 | "fmov (a1+), fs27\n" | 
|  | 1070 | "fmov (a1+), fs28\n" | 
|  | 1071 | "fmov (a1+), fs29\n" | 
|  | 1072 | "fmov (a1+), fs30\n" | 
|  | 1073 | "fmov (a1+), fs31\n" | 
|  | 1074 | "fmov %2, fpcr\n" | 
|  | 1075 | : | 
|  | 1076 | : "g" (&gdbstub_fpufs_array), "i"(EPSW_FE), "d"(gdbstub_fpcr) | 
|  | 1077 | : "a1" | 
|  | 1078 | ); | 
|  | 1079 | #endif | 
|  | 1080 | } | 
|  | 1081 |  | 
|  | 1082 | /* | 
|  | 1083 | * set a software breakpoint | 
|  | 1084 | */ | 
|  | 1085 | int gdbstub_set_breakpoint(u8 *addr, int len) | 
|  | 1086 | { | 
|  | 1087 | int bkpt, loop, xloop; | 
|  | 1088 |  | 
|  | 1089 | #ifdef GDBSTUB_USE_F7F7_AS_BREAKPOINT | 
|  | 1090 | len = (len + 1) & ~1; | 
|  | 1091 | #endif | 
|  | 1092 |  | 
|  | 1093 | gdbstub_bkpt("setbkpt(%p,%d)\n", addr, len); | 
|  | 1094 |  | 
|  | 1095 | for (bkpt = 255; bkpt >= 0; bkpt--) | 
|  | 1096 | if (!gdbstub_bkpts[bkpt].addr) | 
|  | 1097 | break; | 
|  | 1098 | if (bkpt < 0) | 
|  | 1099 | return -ENOSPC; | 
|  | 1100 |  | 
|  | 1101 | for (loop = 0; loop < len; loop++) | 
|  | 1102 | if (gdbstub_read_byte(&addr[loop], | 
|  | 1103 | &gdbstub_bkpts[bkpt].origbytes[loop] | 
|  | 1104 | ) < 0) | 
|  | 1105 | return -EFAULT; | 
|  | 1106 |  | 
|  | 1107 | gdbstub_flush_caches = 1; | 
|  | 1108 |  | 
|  | 1109 | #ifdef GDBSTUB_USE_F7F7_AS_BREAKPOINT | 
|  | 1110 | for (loop = 0; loop < len; loop++) | 
|  | 1111 | if (gdbstub_write_byte(0xF7, &addr[loop]) < 0) | 
|  | 1112 | goto restore; | 
|  | 1113 | #else | 
|  | 1114 | for (loop = 0; loop < len; loop++) | 
|  | 1115 | if (gdbstub_write_byte(0xFF, &addr[loop]) < 0) | 
|  | 1116 | goto restore; | 
|  | 1117 | #endif | 
|  | 1118 |  | 
|  | 1119 | gdbstub_bkpts[bkpt].addr = addr; | 
|  | 1120 | gdbstub_bkpts[bkpt].len = len; | 
|  | 1121 |  | 
|  | 1122 | gdbstub_bkpt("Set BKPT[%02x]: %p-%p {%02x%02x%02x%02x%02x%02x%02x}\n", | 
|  | 1123 | bkpt, | 
|  | 1124 | gdbstub_bkpts[bkpt].addr, | 
|  | 1125 | gdbstub_bkpts[bkpt].addr + gdbstub_bkpts[bkpt].len - 1, | 
|  | 1126 | gdbstub_bkpts[bkpt].origbytes[0], | 
|  | 1127 | gdbstub_bkpts[bkpt].origbytes[1], | 
|  | 1128 | gdbstub_bkpts[bkpt].origbytes[2], | 
|  | 1129 | gdbstub_bkpts[bkpt].origbytes[3], | 
|  | 1130 | gdbstub_bkpts[bkpt].origbytes[4], | 
|  | 1131 | gdbstub_bkpts[bkpt].origbytes[5], | 
|  | 1132 | gdbstub_bkpts[bkpt].origbytes[6] | 
|  | 1133 | ); | 
|  | 1134 |  | 
|  | 1135 | return 0; | 
|  | 1136 |  | 
|  | 1137 | restore: | 
|  | 1138 | for (xloop = 0; xloop < loop; xloop++) | 
|  | 1139 | gdbstub_write_byte(gdbstub_bkpts[bkpt].origbytes[xloop], | 
|  | 1140 | addr + xloop); | 
|  | 1141 | return -EFAULT; | 
|  | 1142 | } | 
|  | 1143 |  | 
|  | 1144 | /* | 
|  | 1145 | * clear a software breakpoint | 
|  | 1146 | */ | 
|  | 1147 | int gdbstub_clear_breakpoint(u8 *addr, int len) | 
|  | 1148 | { | 
|  | 1149 | int bkpt, loop; | 
|  | 1150 |  | 
|  | 1151 | #ifdef GDBSTUB_USE_F7F7_AS_BREAKPOINT | 
|  | 1152 | len = (len + 1) & ~1; | 
|  | 1153 | #endif | 
|  | 1154 |  | 
|  | 1155 | gdbstub_bkpt("clearbkpt(%p,%d)\n", addr, len); | 
|  | 1156 |  | 
|  | 1157 | for (bkpt = 255; bkpt >= 0; bkpt--) | 
|  | 1158 | if (gdbstub_bkpts[bkpt].addr == addr && | 
|  | 1159 | gdbstub_bkpts[bkpt].len == len) | 
|  | 1160 | break; | 
|  | 1161 | if (bkpt < 0) | 
|  | 1162 | return -ENOENT; | 
|  | 1163 |  | 
|  | 1164 | gdbstub_bkpts[bkpt].addr = NULL; | 
|  | 1165 |  | 
|  | 1166 | gdbstub_flush_caches = 1; | 
|  | 1167 |  | 
|  | 1168 | for (loop = 0; loop < len; loop++) | 
|  | 1169 | if (gdbstub_write_byte(gdbstub_bkpts[bkpt].origbytes[loop], | 
|  | 1170 | addr + loop) < 0) | 
|  | 1171 | return -EFAULT; | 
|  | 1172 |  | 
|  | 1173 | return 0; | 
|  | 1174 | } | 
|  | 1175 |  | 
|  | 1176 | /* | 
|  | 1177 | * This function does all command processing for interfacing to gdb | 
|  | 1178 | * - returns 1 if the exception should be skipped, 0 otherwise. | 
|  | 1179 | */ | 
|  | 1180 | static int gdbstub(struct pt_regs *regs, enum exception_code excep) | 
|  | 1181 | { | 
|  | 1182 | unsigned long *stack; | 
|  | 1183 | unsigned long epsw, mdr; | 
|  | 1184 | uint32_t zero, ssp; | 
|  | 1185 | uint8_t broke; | 
|  | 1186 | char *ptr; | 
|  | 1187 | int sigval; | 
|  | 1188 | int addr; | 
|  | 1189 | int length; | 
|  | 1190 | int loop; | 
|  | 1191 |  | 
|  | 1192 | if (excep == EXCEP_FPU_DISABLED) | 
|  | 1193 | return 0; | 
|  | 1194 |  | 
|  | 1195 | gdbstub_flush_caches = 0; | 
|  | 1196 |  | 
|  | 1197 | mn10300_set_gdbleds(1); | 
|  | 1198 |  | 
|  | 1199 | asm volatile("mov mdr,%0" : "=d"(mdr)); | 
|  | 1200 | asm volatile("mov epsw,%0" : "=d"(epsw)); | 
|  | 1201 | asm volatile("mov %0,epsw" | 
|  | 1202 | :: "d"((epsw & ~EPSW_IM) | EPSW_IE | EPSW_IM_1)); | 
|  | 1203 |  | 
|  | 1204 | gdbstub_store_fpu(); | 
|  | 1205 |  | 
|  | 1206 | #ifdef CONFIG_GDBSTUB_IMMEDIATE | 
|  | 1207 | /* skip the initial pause loop */ | 
|  | 1208 | if (regs->pc == (unsigned long) __gdbstub_pause) | 
|  | 1209 | regs->pc = (unsigned long) start_kernel; | 
|  | 1210 | #endif | 
|  | 1211 |  | 
|  | 1212 | /* if we were single stepping, restore the opcodes hoisted for the | 
|  | 1213 | * breakpoint[s] */ | 
|  | 1214 | broke = 0; | 
|  | 1215 | if ((step_bp[0].addr && step_bp[0].addr == (u8 *) regs->pc) || | 
|  | 1216 | (step_bp[1].addr && step_bp[1].addr == (u8 *) regs->pc)) | 
|  | 1217 | broke = 1; | 
|  | 1218 |  | 
|  | 1219 | __gdbstub_restore_bp(); | 
|  | 1220 |  | 
|  | 1221 | if (gdbstub_rx_unget) { | 
|  | 1222 | sigval = SIGINT; | 
|  | 1223 | if (gdbstub_rx_unget != 3) | 
|  | 1224 | goto packet_waiting; | 
|  | 1225 | gdbstub_rx_unget = 0; | 
|  | 1226 | } | 
|  | 1227 |  | 
|  | 1228 | stack = (unsigned long *) regs->sp; | 
|  | 1229 | sigval = broke ? SIGTRAP : computeSignal(excep); | 
|  | 1230 |  | 
|  | 1231 | /* send information about a BUG() */ | 
|  | 1232 | if (!user_mode(regs) && excep == EXCEP_SYSCALL15) { | 
|  | 1233 | const struct bug_entry *bug; | 
|  | 1234 |  | 
|  | 1235 | bug = find_bug(regs->pc); | 
|  | 1236 | if (bug) | 
|  | 1237 | goto found_bug; | 
|  | 1238 | length = snprintf(trans_buffer, sizeof(trans_buffer), | 
|  | 1239 | "BUG() at address %lx\n", regs->pc); | 
|  | 1240 | goto send_bug_pkt; | 
|  | 1241 |  | 
|  | 1242 | found_bug: | 
|  | 1243 | length = snprintf(trans_buffer, sizeof(trans_buffer), | 
|  | 1244 | "BUG() at address %lx (%s:%d)\n", | 
|  | 1245 | regs->pc, bug->file, bug->line); | 
|  | 1246 |  | 
|  | 1247 | send_bug_pkt: | 
|  | 1248 | ptr = output_buffer; | 
|  | 1249 | *ptr++ = 'O'; | 
|  | 1250 | ptr = mem2hex(trans_buffer, ptr, length, 0); | 
|  | 1251 | *ptr = 0; | 
|  | 1252 | putpacket(output_buffer); | 
|  | 1253 |  | 
|  | 1254 | regs->pc -= 2; | 
|  | 1255 | sigval = SIGABRT; | 
|  | 1256 | } else if (regs->pc == (unsigned long) __gdbstub_bug_trap) { | 
|  | 1257 | regs->pc = regs->mdr; | 
|  | 1258 | sigval = SIGABRT; | 
|  | 1259 | } | 
|  | 1260 |  | 
|  | 1261 | /* | 
|  | 1262 | * send a message to the debugger's user saying what happened if it may | 
|  | 1263 | * not be clear cut (we can't map exceptions onto signals properly) | 
|  | 1264 | */ | 
|  | 1265 | if (sigval != SIGINT && sigval != SIGTRAP && sigval != SIGILL) { | 
|  | 1266 | static const char title[] = "Excep ", tbcberr[] = "BCBERR "; | 
|  | 1267 | static const char crlf[] = "\r\n"; | 
|  | 1268 | char hx; | 
|  | 1269 | u32 bcberr = BCBERR; | 
|  | 1270 |  | 
|  | 1271 | ptr = output_buffer; | 
|  | 1272 | *ptr++ = 'O'; | 
|  | 1273 | ptr = mem2hex(title, ptr, sizeof(title) - 1, 0); | 
|  | 1274 |  | 
| Harvey Harrison | 2682497 | 2008-07-25 19:45:20 -0700 | [diff] [blame] | 1275 | hx = hex_asc_hi(excep >> 8); | 
|  | 1276 | ptr = pack_hex_byte(ptr, hx); | 
|  | 1277 | hx = hex_asc_lo(excep >> 8); | 
|  | 1278 | ptr = pack_hex_byte(ptr, hx); | 
|  | 1279 | hx = hex_asc_hi(excep); | 
|  | 1280 | ptr = pack_hex_byte(ptr, hx); | 
|  | 1281 | hx = hex_asc_lo(excep); | 
|  | 1282 | ptr = pack_hex_byte(ptr, hx); | 
| David Howells | b920de1 | 2008-02-08 04:19:31 -0800 | [diff] [blame] | 1283 |  | 
|  | 1284 | ptr = mem2hex(crlf, ptr, sizeof(crlf) - 1, 0); | 
|  | 1285 | *ptr = 0; | 
|  | 1286 | putpacket(output_buffer);	/* send it off... */ | 
|  | 1287 |  | 
|  | 1288 | /* BCBERR */ | 
|  | 1289 | ptr = output_buffer; | 
|  | 1290 | *ptr++ = 'O'; | 
|  | 1291 | ptr = mem2hex(tbcberr, ptr, sizeof(tbcberr) - 1, 0); | 
|  | 1292 |  | 
| Harvey Harrison | 2682497 | 2008-07-25 19:45:20 -0700 | [diff] [blame] | 1293 | hx = hex_asc_hi(bcberr >> 24); | 
|  | 1294 | ptr = pack_hex_byte(ptr, hx); | 
|  | 1295 | hx = hex_asc_lo(bcberr >> 24); | 
|  | 1296 | ptr = pack_hex_byte(ptr, hx); | 
|  | 1297 | hx = hex_asc_hi(bcberr >> 16); | 
|  | 1298 | ptr = pack_hex_byte(ptr, hx); | 
|  | 1299 | hx = hex_asc_lo(bcberr >> 16); | 
|  | 1300 | ptr = pack_hex_byte(ptr, hx); | 
|  | 1301 | hx = hex_asc_hi(bcberr >> 8); | 
|  | 1302 | ptr = pack_hex_byte(ptr, hx); | 
|  | 1303 | hx = hex_asc_lo(bcberr >> 8); | 
|  | 1304 | ptr = pack_hex_byte(ptr, hx); | 
|  | 1305 | hx = hex_asc_hi(bcberr); | 
|  | 1306 | ptr = pack_hex_byte(ptr, hx); | 
|  | 1307 | hx = hex_asc_lo(bcberr); | 
|  | 1308 | ptr = pack_hex_byte(ptr, hx); | 
| David Howells | b920de1 | 2008-02-08 04:19:31 -0800 | [diff] [blame] | 1309 |  | 
|  | 1310 | ptr = mem2hex(crlf, ptr, sizeof(crlf) - 1, 0); | 
|  | 1311 | *ptr = 0; | 
|  | 1312 | putpacket(output_buffer);	/* send it off... */ | 
|  | 1313 | } | 
|  | 1314 |  | 
|  | 1315 | /* | 
|  | 1316 | * tell the debugger that an exception has occurred | 
|  | 1317 | */ | 
|  | 1318 | ptr = output_buffer; | 
|  | 1319 |  | 
|  | 1320 | /* | 
|  | 1321 | * Send trap type (converted to signal) | 
|  | 1322 | */ | 
|  | 1323 | *ptr++ = 'T'; | 
| Harvey Harrison | 2682497 | 2008-07-25 19:45:20 -0700 | [diff] [blame] | 1324 | ptr = pack_hex_byte(ptr, sigval); | 
| David Howells | b920de1 | 2008-02-08 04:19:31 -0800 | [diff] [blame] | 1325 |  | 
|  | 1326 | /* | 
|  | 1327 | * Send Error PC | 
|  | 1328 | */ | 
| Harvey Harrison | 2682497 | 2008-07-25 19:45:20 -0700 | [diff] [blame] | 1329 | ptr = pack_hex_byte(ptr, GDB_REGID_PC); | 
| David Howells | b920de1 | 2008-02-08 04:19:31 -0800 | [diff] [blame] | 1330 | *ptr++ = ':'; | 
|  | 1331 | ptr = mem2hex(®s->pc, ptr, 4, 0); | 
|  | 1332 | *ptr++ = ';'; | 
|  | 1333 |  | 
|  | 1334 | /* | 
|  | 1335 | * Send frame pointer | 
|  | 1336 | */ | 
| Harvey Harrison | 2682497 | 2008-07-25 19:45:20 -0700 | [diff] [blame] | 1337 | ptr = pack_hex_byte(ptr, GDB_REGID_FP); | 
| David Howells | b920de1 | 2008-02-08 04:19:31 -0800 | [diff] [blame] | 1338 | *ptr++ = ':'; | 
|  | 1339 | ptr = mem2hex(®s->a3, ptr, 4, 0); | 
|  | 1340 | *ptr++ = ';'; | 
|  | 1341 |  | 
|  | 1342 | /* | 
|  | 1343 | * Send stack pointer | 
|  | 1344 | */ | 
|  | 1345 | ssp = (unsigned long) (regs + 1); | 
| Harvey Harrison | 2682497 | 2008-07-25 19:45:20 -0700 | [diff] [blame] | 1346 | ptr = pack_hex_byte(ptr, GDB_REGID_SP); | 
| David Howells | b920de1 | 2008-02-08 04:19:31 -0800 | [diff] [blame] | 1347 | *ptr++ = ':'; | 
|  | 1348 | ptr = mem2hex(&ssp, ptr, 4, 0); | 
|  | 1349 | *ptr++ = ';'; | 
|  | 1350 |  | 
|  | 1351 | *ptr++ = 0; | 
|  | 1352 | putpacket(output_buffer);	/* send it off... */ | 
|  | 1353 |  | 
|  | 1354 | packet_waiting: | 
|  | 1355 | /* | 
|  | 1356 | * Wait for input from remote GDB | 
|  | 1357 | */ | 
|  | 1358 | while (1) { | 
|  | 1359 | output_buffer[0] = 0; | 
|  | 1360 | getpacket(input_buffer); | 
|  | 1361 |  | 
|  | 1362 | switch (input_buffer[0]) { | 
|  | 1363 | /* request repeat of last signal number */ | 
|  | 1364 | case '?': | 
|  | 1365 | output_buffer[0] = 'S'; | 
| Harvey Harrison | 2682497 | 2008-07-25 19:45:20 -0700 | [diff] [blame] | 1366 | output_buffer[1] = hex_asc_hi(sigval); | 
|  | 1367 | output_buffer[2] = hex_asc_lo(sigval); | 
| David Howells | b920de1 | 2008-02-08 04:19:31 -0800 | [diff] [blame] | 1368 | output_buffer[3] = 0; | 
|  | 1369 | break; | 
|  | 1370 |  | 
|  | 1371 | case 'd': | 
|  | 1372 | /* toggle debug flag */ | 
|  | 1373 | break; | 
|  | 1374 |  | 
|  | 1375 | /* | 
|  | 1376 | * Return the value of the CPU registers | 
|  | 1377 | */ | 
|  | 1378 | case 'g': | 
|  | 1379 | zero = 0; | 
|  | 1380 | ssp = (u32) (regs + 1); | 
|  | 1381 | ptr = output_buffer; | 
|  | 1382 | ptr = mem2hex(®s->d0, ptr, 4, 0); | 
|  | 1383 | ptr = mem2hex(®s->d1, ptr, 4, 0); | 
|  | 1384 | ptr = mem2hex(®s->d2, ptr, 4, 0); | 
|  | 1385 | ptr = mem2hex(®s->d3, ptr, 4, 0); | 
|  | 1386 | ptr = mem2hex(®s->a0, ptr, 4, 0); | 
|  | 1387 | ptr = mem2hex(®s->a1, ptr, 4, 0); | 
|  | 1388 | ptr = mem2hex(®s->a2, ptr, 4, 0); | 
|  | 1389 | ptr = mem2hex(®s->a3, ptr, 4, 0); | 
|  | 1390 |  | 
|  | 1391 | ptr = mem2hex(&ssp, ptr, 4, 0);		/* 8 */ | 
|  | 1392 | ptr = mem2hex(®s->pc, ptr, 4, 0); | 
|  | 1393 | ptr = mem2hex(®s->mdr, ptr, 4, 0); | 
|  | 1394 | ptr = mem2hex(®s->epsw, ptr, 4, 0); | 
|  | 1395 | ptr = mem2hex(®s->lir, ptr, 4, 0); | 
|  | 1396 | ptr = mem2hex(®s->lar, ptr, 4, 0); | 
|  | 1397 | ptr = mem2hex(®s->mdrq, ptr, 4, 0); | 
|  | 1398 |  | 
|  | 1399 | ptr = mem2hex(®s->e0, ptr, 4, 0);	/* 15 */ | 
|  | 1400 | ptr = mem2hex(®s->e1, ptr, 4, 0); | 
|  | 1401 | ptr = mem2hex(®s->e2, ptr, 4, 0); | 
|  | 1402 | ptr = mem2hex(®s->e3, ptr, 4, 0); | 
|  | 1403 | ptr = mem2hex(®s->e4, ptr, 4, 0); | 
|  | 1404 | ptr = mem2hex(®s->e5, ptr, 4, 0); | 
|  | 1405 | ptr = mem2hex(®s->e6, ptr, 4, 0); | 
|  | 1406 | ptr = mem2hex(®s->e7, ptr, 4, 0); | 
|  | 1407 |  | 
|  | 1408 | ptr = mem2hex(&ssp, ptr, 4, 0); | 
|  | 1409 | ptr = mem2hex(®s, ptr, 4, 0); | 
|  | 1410 | ptr = mem2hex(®s->sp, ptr, 4, 0); | 
|  | 1411 | ptr = mem2hex(®s->mcrh, ptr, 4, 0);	/* 26 */ | 
|  | 1412 | ptr = mem2hex(®s->mcrl, ptr, 4, 0); | 
|  | 1413 | ptr = mem2hex(®s->mcvf, ptr, 4, 0); | 
|  | 1414 |  | 
|  | 1415 | ptr = mem2hex(&gdbstub_fpcr, ptr, 4, 0); /* 29 - FPCR */ | 
|  | 1416 | ptr = mem2hex(&zero, ptr, 4, 0); | 
|  | 1417 | ptr = mem2hex(&zero, ptr, 4, 0); | 
|  | 1418 | for (loop = 0; loop < 32; loop++) | 
|  | 1419 | ptr = mem2hex(&gdbstub_fpufs_array[loop], | 
|  | 1420 | ptr, 4, 0); /* 32 - FS0-31 */ | 
|  | 1421 |  | 
|  | 1422 | break; | 
|  | 1423 |  | 
|  | 1424 | /* | 
|  | 1425 | * set the value of the CPU registers - return OK | 
|  | 1426 | */ | 
|  | 1427 | case 'G': | 
|  | 1428 | { | 
|  | 1429 | const char *ptr; | 
|  | 1430 |  | 
|  | 1431 | ptr = &input_buffer[1]; | 
|  | 1432 | ptr = hex2mem(ptr, ®s->d0, 4, 0); | 
|  | 1433 | ptr = hex2mem(ptr, ®s->d1, 4, 0); | 
|  | 1434 | ptr = hex2mem(ptr, ®s->d2, 4, 0); | 
|  | 1435 | ptr = hex2mem(ptr, ®s->d3, 4, 0); | 
|  | 1436 | ptr = hex2mem(ptr, ®s->a0, 4, 0); | 
|  | 1437 | ptr = hex2mem(ptr, ®s->a1, 4, 0); | 
|  | 1438 | ptr = hex2mem(ptr, ®s->a2, 4, 0); | 
|  | 1439 | ptr = hex2mem(ptr, ®s->a3, 4, 0); | 
|  | 1440 |  | 
|  | 1441 | ptr = hex2mem(ptr, &ssp, 4, 0);		/* 8 */ | 
|  | 1442 | ptr = hex2mem(ptr, ®s->pc, 4, 0); | 
|  | 1443 | ptr = hex2mem(ptr, ®s->mdr, 4, 0); | 
|  | 1444 | ptr = hex2mem(ptr, ®s->epsw, 4, 0); | 
|  | 1445 | ptr = hex2mem(ptr, ®s->lir, 4, 0); | 
|  | 1446 | ptr = hex2mem(ptr, ®s->lar, 4, 0); | 
|  | 1447 | ptr = hex2mem(ptr, ®s->mdrq, 4, 0); | 
|  | 1448 |  | 
|  | 1449 | ptr = hex2mem(ptr, ®s->e0, 4, 0);	/* 15 */ | 
|  | 1450 | ptr = hex2mem(ptr, ®s->e1, 4, 0); | 
|  | 1451 | ptr = hex2mem(ptr, ®s->e2, 4, 0); | 
|  | 1452 | ptr = hex2mem(ptr, ®s->e3, 4, 0); | 
|  | 1453 | ptr = hex2mem(ptr, ®s->e4, 4, 0); | 
|  | 1454 | ptr = hex2mem(ptr, ®s->e5, 4, 0); | 
|  | 1455 | ptr = hex2mem(ptr, ®s->e6, 4, 0); | 
|  | 1456 | ptr = hex2mem(ptr, ®s->e7, 4, 0); | 
|  | 1457 |  | 
|  | 1458 | ptr = hex2mem(ptr, &ssp, 4, 0); | 
|  | 1459 | ptr = hex2mem(ptr, &zero, 4, 0); | 
|  | 1460 | ptr = hex2mem(ptr, ®s->sp, 4, 0); | 
|  | 1461 | ptr = hex2mem(ptr, ®s->mcrh, 4, 0);	/* 26 */ | 
|  | 1462 | ptr = hex2mem(ptr, ®s->mcrl, 4, 0); | 
|  | 1463 | ptr = hex2mem(ptr, ®s->mcvf, 4, 0); | 
|  | 1464 |  | 
|  | 1465 | ptr = hex2mem(ptr, &zero, 4, 0);	/* 29 - FPCR */ | 
|  | 1466 | ptr = hex2mem(ptr, &zero, 4, 0); | 
|  | 1467 | ptr = hex2mem(ptr, &zero, 4, 0); | 
|  | 1468 | for (loop = 0; loop < 32; loop++)     /* 32 - FS0-31 */ | 
|  | 1469 | ptr = hex2mem(ptr, &zero, 4, 0); | 
|  | 1470 |  | 
|  | 1471 | #if 0 | 
|  | 1472 | /* | 
|  | 1473 | * See if the stack pointer has moved. If so, then copy | 
|  | 1474 | * the saved locals and ins to the new location. | 
|  | 1475 | */ | 
|  | 1476 | unsigned long *newsp = (unsigned long *) registers[SP]; | 
|  | 1477 | if (sp != newsp) | 
|  | 1478 | sp = memcpy(newsp, sp, 16 * 4); | 
|  | 1479 | #endif | 
|  | 1480 |  | 
|  | 1481 | gdbstub_strcpy(output_buffer, "OK"); | 
|  | 1482 | } | 
|  | 1483 | break; | 
|  | 1484 |  | 
|  | 1485 | /* | 
|  | 1486 | * mAA..AA,LLLL  Read LLLL bytes at address AA..AA | 
|  | 1487 | */ | 
|  | 1488 | case 'm': | 
|  | 1489 | ptr = &input_buffer[1]; | 
|  | 1490 |  | 
|  | 1491 | if (hexToInt(&ptr, &addr) && | 
|  | 1492 | *ptr++ == ',' && | 
|  | 1493 | hexToInt(&ptr, &length) | 
|  | 1494 | ) { | 
|  | 1495 | if (mem2hex((char *) addr, output_buffer, | 
|  | 1496 | length, 1)) | 
|  | 1497 | break; | 
|  | 1498 | gdbstub_strcpy(output_buffer, "E03"); | 
|  | 1499 | } else { | 
|  | 1500 | gdbstub_strcpy(output_buffer, "E01"); | 
|  | 1501 | } | 
|  | 1502 | break; | 
|  | 1503 |  | 
|  | 1504 | /* | 
|  | 1505 | * MAA..AA,LLLL: Write LLLL bytes at address AA.AA | 
|  | 1506 | * return OK | 
|  | 1507 | */ | 
|  | 1508 | case 'M': | 
|  | 1509 | ptr = &input_buffer[1]; | 
|  | 1510 |  | 
|  | 1511 | if (hexToInt(&ptr, &addr) && | 
|  | 1512 | *ptr++ == ',' && | 
|  | 1513 | hexToInt(&ptr, &length) && | 
|  | 1514 | *ptr++ == ':' | 
|  | 1515 | ) { | 
|  | 1516 | if (hex2mem(ptr, (char *) addr, length, 1)) | 
|  | 1517 | gdbstub_strcpy(output_buffer, "OK"); | 
|  | 1518 | else | 
|  | 1519 | gdbstub_strcpy(output_buffer, "E03"); | 
|  | 1520 |  | 
|  | 1521 | gdbstub_flush_caches = 1; | 
|  | 1522 | } else { | 
|  | 1523 | gdbstub_strcpy(output_buffer, "E02"); | 
|  | 1524 | } | 
|  | 1525 | break; | 
|  | 1526 |  | 
|  | 1527 | /* | 
|  | 1528 | * cAA..AA    Continue at address AA..AA(optional) | 
|  | 1529 | */ | 
|  | 1530 | case 'c': | 
|  | 1531 | /* try to read optional parameter, pc unchanged if no | 
|  | 1532 | * parm */ | 
|  | 1533 |  | 
|  | 1534 | ptr = &input_buffer[1]; | 
|  | 1535 | if (hexToInt(&ptr, &addr)) | 
|  | 1536 | regs->pc = addr; | 
|  | 1537 | goto done; | 
|  | 1538 |  | 
|  | 1539 | /* | 
|  | 1540 | * kill the program | 
|  | 1541 | */ | 
|  | 1542 | case 'k' : | 
|  | 1543 | goto done;	/* just continue */ | 
|  | 1544 |  | 
|  | 1545 | /* | 
|  | 1546 | * Reset the whole machine (FIXME: system dependent) | 
|  | 1547 | */ | 
|  | 1548 | case 'r': | 
|  | 1549 | break; | 
|  | 1550 |  | 
|  | 1551 | /* | 
|  | 1552 | * Step to next instruction | 
|  | 1553 | */ | 
|  | 1554 | case 's': | 
|  | 1555 | /* | 
|  | 1556 | * using the T flag doesn't seem to perform single | 
|  | 1557 | * stepping (it seems to wind up being caught by the | 
|  | 1558 | * JTAG unit), so we have to use breakpoints and | 
|  | 1559 | * continue instead. | 
|  | 1560 | */ | 
|  | 1561 | if (gdbstub_single_step(regs) < 0) | 
|  | 1562 | /* ignore any fault error for now */ | 
|  | 1563 | gdbstub_printk("unable to set single-step" | 
|  | 1564 | " bp\n"); | 
|  | 1565 | goto done; | 
|  | 1566 |  | 
|  | 1567 | /* | 
|  | 1568 | * Set baud rate (bBB) | 
|  | 1569 | */ | 
|  | 1570 | case 'b': | 
|  | 1571 | do { | 
|  | 1572 | int baudrate; | 
|  | 1573 |  | 
|  | 1574 | ptr = &input_buffer[1]; | 
|  | 1575 | if (!hexToInt(&ptr, &baudrate)) { | 
|  | 1576 | gdbstub_strcpy(output_buffer, "B01"); | 
|  | 1577 | break; | 
|  | 1578 | } | 
|  | 1579 |  | 
|  | 1580 | if (baudrate) { | 
|  | 1581 | /* ACK before changing speed */ | 
|  | 1582 | putpacket("OK"); | 
|  | 1583 | gdbstub_io_set_baud(baudrate); | 
|  | 1584 | } | 
|  | 1585 | } while (0); | 
|  | 1586 | break; | 
|  | 1587 |  | 
|  | 1588 | /* | 
|  | 1589 | * Set breakpoint | 
|  | 1590 | */ | 
|  | 1591 | case 'Z': | 
|  | 1592 | ptr = &input_buffer[1]; | 
|  | 1593 |  | 
|  | 1594 | if (!hexToInt(&ptr, &loop) || *ptr++ != ',' || | 
|  | 1595 | !hexToInt(&ptr, &addr) || *ptr++ != ',' || | 
|  | 1596 | !hexToInt(&ptr, &length) | 
|  | 1597 | ) { | 
|  | 1598 | gdbstub_strcpy(output_buffer, "E01"); | 
|  | 1599 | break; | 
|  | 1600 | } | 
|  | 1601 |  | 
|  | 1602 | /* only support software breakpoints */ | 
|  | 1603 | gdbstub_strcpy(output_buffer, "E03"); | 
|  | 1604 | if (loop != 0 || | 
|  | 1605 | length < 1 || | 
|  | 1606 | length > 7 || | 
|  | 1607 | (unsigned long) addr < 4096) | 
|  | 1608 | break; | 
|  | 1609 |  | 
|  | 1610 | if (gdbstub_set_breakpoint((u8 *) addr, length) < 0) | 
|  | 1611 | break; | 
|  | 1612 |  | 
|  | 1613 | gdbstub_strcpy(output_buffer, "OK"); | 
|  | 1614 | break; | 
|  | 1615 |  | 
|  | 1616 | /* | 
|  | 1617 | * Clear breakpoint | 
|  | 1618 | */ | 
|  | 1619 | case 'z': | 
|  | 1620 | ptr = &input_buffer[1]; | 
|  | 1621 |  | 
|  | 1622 | if (!hexToInt(&ptr, &loop) || *ptr++ != ',' || | 
|  | 1623 | !hexToInt(&ptr, &addr) || *ptr++ != ',' || | 
|  | 1624 | !hexToInt(&ptr, &length) | 
|  | 1625 | ) { | 
|  | 1626 | gdbstub_strcpy(output_buffer, "E01"); | 
|  | 1627 | break; | 
|  | 1628 | } | 
|  | 1629 |  | 
|  | 1630 | /* only support software breakpoints */ | 
|  | 1631 | gdbstub_strcpy(output_buffer, "E03"); | 
|  | 1632 | if (loop != 0 || | 
|  | 1633 | length < 1 || | 
|  | 1634 | length > 7 || | 
|  | 1635 | (unsigned long) addr < 4096) | 
|  | 1636 | break; | 
|  | 1637 |  | 
|  | 1638 | if (gdbstub_clear_breakpoint((u8 *) addr, length) < 0) | 
|  | 1639 | break; | 
|  | 1640 |  | 
|  | 1641 | gdbstub_strcpy(output_buffer, "OK"); | 
|  | 1642 | break; | 
|  | 1643 |  | 
|  | 1644 | default: | 
|  | 1645 | gdbstub_proto("### GDB Unsupported Cmd '%s'\n", | 
|  | 1646 | input_buffer); | 
|  | 1647 | break; | 
|  | 1648 | } | 
|  | 1649 |  | 
|  | 1650 | /* reply to the request */ | 
|  | 1651 | putpacket(output_buffer); | 
|  | 1652 | } | 
|  | 1653 |  | 
|  | 1654 | done: | 
|  | 1655 | /* | 
|  | 1656 | * Need to flush the instruction cache here, as we may | 
|  | 1657 | * have deposited a breakpoint, and the icache probably | 
|  | 1658 | * has no way of knowing that a data ref to some location | 
|  | 1659 | * may have changed something that is in the instruction | 
|  | 1660 | * cache. | 
|  | 1661 | * NB: We flush both caches, just to be sure... | 
|  | 1662 | */ | 
|  | 1663 | if (gdbstub_flush_caches) | 
|  | 1664 | gdbstub_purge_cache(); | 
|  | 1665 |  | 
|  | 1666 | gdbstub_load_fpu(); | 
|  | 1667 | mn10300_set_gdbleds(0); | 
|  | 1668 | if (excep == EXCEP_NMI) | 
|  | 1669 | NMICR = NMICR_NMIF; | 
|  | 1670 |  | 
|  | 1671 | touch_softlockup_watchdog(); | 
|  | 1672 |  | 
|  | 1673 | local_irq_restore(epsw); | 
|  | 1674 | return 1; | 
|  | 1675 | } | 
|  | 1676 |  | 
|  | 1677 | /* | 
|  | 1678 | * handle event interception | 
|  | 1679 | */ | 
|  | 1680 | asmlinkage int gdbstub_intercept(struct pt_regs *regs, | 
|  | 1681 | enum exception_code excep) | 
|  | 1682 | { | 
|  | 1683 | static u8 notfirst = 1; | 
|  | 1684 | int ret; | 
|  | 1685 |  | 
|  | 1686 | if (gdbstub_busy) | 
|  | 1687 | gdbstub_printk("--> gdbstub reentered itself\n"); | 
|  | 1688 | gdbstub_busy = 1; | 
|  | 1689 |  | 
|  | 1690 | if (notfirst) { | 
|  | 1691 | unsigned long mdr; | 
|  | 1692 | asm("mov mdr,%0" : "=d"(mdr)); | 
|  | 1693 |  | 
|  | 1694 | gdbstub_entry( | 
|  | 1695 | "--> gdbstub_intercept(%p,%04x) [MDR=%lx PC=%lx]\n", | 
|  | 1696 | regs, excep, mdr, regs->pc); | 
|  | 1697 |  | 
|  | 1698 | gdbstub_entry( | 
|  | 1699 | "PC:  %08lx EPSW:  %08lx  SSP: %08lx mode: %s\n", | 
|  | 1700 | regs->pc, regs->epsw, (unsigned long) &ret, | 
|  | 1701 | user_mode(regs) ? "User" : "Super"); | 
|  | 1702 | gdbstub_entry( | 
|  | 1703 | "d0:  %08lx   d1:  %08lx   d2: %08lx   d3: %08lx\n", | 
|  | 1704 | regs->d0, regs->d1, regs->d2, regs->d3); | 
|  | 1705 | gdbstub_entry( | 
|  | 1706 | "a0:  %08lx   a1:  %08lx   a2: %08lx   a3: %08lx\n", | 
|  | 1707 | regs->a0, regs->a1, regs->a2, regs->a3); | 
|  | 1708 | gdbstub_entry( | 
|  | 1709 | "e0:  %08lx   e1:  %08lx   e2: %08lx   e3: %08lx\n", | 
|  | 1710 | regs->e0, regs->e1, regs->e2, regs->e3); | 
|  | 1711 | gdbstub_entry( | 
|  | 1712 | "e4:  %08lx   e5:  %08lx   e6: %08lx   e7: %08lx\n", | 
|  | 1713 | regs->e4, regs->e5, regs->e6, regs->e7); | 
|  | 1714 | gdbstub_entry( | 
|  | 1715 | "lar: %08lx   lir: %08lx  mdr: %08lx  usp: %08lx\n", | 
|  | 1716 | regs->lar, regs->lir, regs->mdr, regs->sp); | 
|  | 1717 | gdbstub_entry( | 
|  | 1718 | "cvf: %08lx   crl: %08lx  crh: %08lx  drq: %08lx\n", | 
|  | 1719 | regs->mcvf, regs->mcrl, regs->mcrh, regs->mdrq); | 
|  | 1720 | gdbstub_entry( | 
|  | 1721 | "threadinfo=%p task=%p)\n", | 
|  | 1722 | current_thread_info(), current); | 
|  | 1723 | } else { | 
|  | 1724 | notfirst = 1; | 
|  | 1725 | } | 
|  | 1726 |  | 
|  | 1727 | ret = gdbstub(regs, excep); | 
|  | 1728 |  | 
|  | 1729 | gdbstub_entry("<-- gdbstub_intercept()\n"); | 
|  | 1730 | gdbstub_busy = 0; | 
|  | 1731 | return ret; | 
|  | 1732 | } | 
|  | 1733 |  | 
|  | 1734 | /* | 
|  | 1735 | * handle the GDB stub itself causing an exception | 
|  | 1736 | */ | 
|  | 1737 | asmlinkage void gdbstub_exception(struct pt_regs *regs, | 
|  | 1738 | enum exception_code excep) | 
|  | 1739 | { | 
|  | 1740 | unsigned long mdr; | 
|  | 1741 |  | 
|  | 1742 | asm("mov mdr,%0" : "=d"(mdr)); | 
|  | 1743 | gdbstub_entry("--> gdbstub exception({%p},%04x) [MDR=%lx]\n", | 
|  | 1744 | regs, excep, mdr); | 
|  | 1745 |  | 
|  | 1746 | while ((unsigned long) regs == 0xffffffff) {} | 
|  | 1747 |  | 
|  | 1748 | /* handle guarded memory accesses where we know it might fault */ | 
|  | 1749 | if (regs->pc == (unsigned) gdbstub_read_byte_guard) { | 
|  | 1750 | regs->pc = (unsigned) gdbstub_read_byte_cont; | 
|  | 1751 | goto fault; | 
|  | 1752 | } | 
|  | 1753 |  | 
|  | 1754 | if (regs->pc == (unsigned) gdbstub_read_word_guard) { | 
|  | 1755 | regs->pc = (unsigned) gdbstub_read_word_cont; | 
|  | 1756 | goto fault; | 
|  | 1757 | } | 
|  | 1758 |  | 
|  | 1759 | if (regs->pc == (unsigned) gdbstub_read_dword_guard) { | 
|  | 1760 | regs->pc = (unsigned) gdbstub_read_dword_cont; | 
|  | 1761 | goto fault; | 
|  | 1762 | } | 
|  | 1763 |  | 
|  | 1764 | if (regs->pc == (unsigned) gdbstub_write_byte_guard) { | 
|  | 1765 | regs->pc = (unsigned) gdbstub_write_byte_cont; | 
|  | 1766 | goto fault; | 
|  | 1767 | } | 
|  | 1768 |  | 
|  | 1769 | if (regs->pc == (unsigned) gdbstub_write_word_guard) { | 
|  | 1770 | regs->pc = (unsigned) gdbstub_write_word_cont; | 
|  | 1771 | goto fault; | 
|  | 1772 | } | 
|  | 1773 |  | 
|  | 1774 | if (regs->pc == (unsigned) gdbstub_write_dword_guard) { | 
|  | 1775 | regs->pc = (unsigned) gdbstub_write_dword_cont; | 
|  | 1776 | goto fault; | 
|  | 1777 | } | 
|  | 1778 |  | 
|  | 1779 | gdbstub_printk("\n### GDB stub caused an exception ###\n"); | 
|  | 1780 |  | 
|  | 1781 | /* something went horribly wrong */ | 
|  | 1782 | console_verbose(); | 
|  | 1783 | show_registers(regs); | 
|  | 1784 |  | 
|  | 1785 | panic("GDB Stub caused an unexpected exception - can't continue\n"); | 
|  | 1786 |  | 
|  | 1787 | /* we caught an attempt by the stub to access silly memory */ | 
|  | 1788 | fault: | 
|  | 1789 | gdbstub_entry("<-- gdbstub exception() = EFAULT\n"); | 
|  | 1790 | regs->d0 = -EFAULT; | 
|  | 1791 | return; | 
|  | 1792 | } | 
|  | 1793 |  | 
|  | 1794 | /* | 
|  | 1795 | * send an exit message to GDB | 
|  | 1796 | */ | 
|  | 1797 | void gdbstub_exit(int status) | 
|  | 1798 | { | 
|  | 1799 | unsigned char checksum; | 
|  | 1800 | unsigned char ch; | 
|  | 1801 | int count; | 
|  | 1802 |  | 
|  | 1803 | gdbstub_busy = 1; | 
|  | 1804 | output_buffer[0] = 'W'; | 
| Harvey Harrison | 2682497 | 2008-07-25 19:45:20 -0700 | [diff] [blame] | 1805 | output_buffer[1] = hex_asc_hi(status); | 
|  | 1806 | output_buffer[2] = hex_asc_lo(status); | 
| David Howells | b920de1 | 2008-02-08 04:19:31 -0800 | [diff] [blame] | 1807 | output_buffer[3] = 0; | 
|  | 1808 |  | 
|  | 1809 | gdbstub_io_tx_char('$'); | 
|  | 1810 | checksum = 0; | 
|  | 1811 | count = 0; | 
|  | 1812 |  | 
|  | 1813 | while ((ch = output_buffer[count]) != 0) { | 
|  | 1814 | gdbstub_io_tx_char(ch); | 
|  | 1815 | checksum += ch; | 
|  | 1816 | count += 1; | 
|  | 1817 | } | 
|  | 1818 |  | 
|  | 1819 | gdbstub_io_tx_char('#'); | 
| Harvey Harrison | 2682497 | 2008-07-25 19:45:20 -0700 | [diff] [blame] | 1820 | gdbstub_io_tx_char(hex_asc_hi(checksum)); | 
|  | 1821 | gdbstub_io_tx_char(hex_asc_lo(checksum)); | 
| David Howells | b920de1 | 2008-02-08 04:19:31 -0800 | [diff] [blame] | 1822 |  | 
|  | 1823 | /* make sure the output is flushed, or else RedBoot might clobber it */ | 
|  | 1824 | gdbstub_io_tx_flush(); | 
|  | 1825 |  | 
|  | 1826 | gdbstub_busy = 0; | 
|  | 1827 | } | 
|  | 1828 |  | 
|  | 1829 | /* | 
|  | 1830 | * initialise the GDB stub | 
|  | 1831 | */ | 
|  | 1832 | asmlinkage void __init gdbstub_init(void) | 
|  | 1833 | { | 
|  | 1834 | #ifdef CONFIG_GDBSTUB_IMMEDIATE | 
|  | 1835 | unsigned char ch; | 
|  | 1836 | int ret; | 
|  | 1837 | #endif | 
|  | 1838 |  | 
|  | 1839 | gdbstub_busy = 1; | 
|  | 1840 |  | 
|  | 1841 | printk(KERN_INFO "%s", gdbstub_banner); | 
|  | 1842 |  | 
|  | 1843 | gdbstub_io_init(); | 
|  | 1844 |  | 
|  | 1845 | gdbstub_entry("--> gdbstub_init\n"); | 
|  | 1846 |  | 
|  | 1847 | /* try to talk to GDB (or anyone insane enough to want to type GDB | 
|  | 1848 | * protocol by hand) */ | 
|  | 1849 | gdbstub_io("### GDB Tx ACK\n"); | 
|  | 1850 | gdbstub_io_tx_char('+'); /* 'hello world' */ | 
|  | 1851 |  | 
|  | 1852 | #ifdef CONFIG_GDBSTUB_IMMEDIATE | 
|  | 1853 | gdbstub_printk("GDB Stub waiting for packet\n"); | 
|  | 1854 |  | 
|  | 1855 | /* in case GDB is started before us, ACK any packets that are already | 
|  | 1856 | * sitting there (presumably "$?#xx") | 
|  | 1857 | */ | 
|  | 1858 | do { gdbstub_io_rx_char(&ch, 0); } while (ch != '$'); | 
|  | 1859 | do { gdbstub_io_rx_char(&ch, 0); } while (ch != '#'); | 
|  | 1860 | /* eat first csum byte */ | 
|  | 1861 | do { ret = gdbstub_io_rx_char(&ch, 0); } while (ret != 0); | 
|  | 1862 | /* eat second csum byte */ | 
|  | 1863 | do { ret = gdbstub_io_rx_char(&ch, 0); } while (ret != 0); | 
|  | 1864 |  | 
|  | 1865 | gdbstub_io("### GDB Tx NAK\n"); | 
|  | 1866 | gdbstub_io_tx_char('-'); /* NAK it */ | 
|  | 1867 |  | 
|  | 1868 | #else | 
|  | 1869 | printk("GDB Stub ready\n"); | 
|  | 1870 | #endif | 
|  | 1871 |  | 
|  | 1872 | gdbstub_busy = 0; | 
|  | 1873 | gdbstub_entry("<-- gdbstub_init\n"); | 
|  | 1874 | } | 
|  | 1875 |  | 
|  | 1876 | /* | 
|  | 1877 | * register the console at a more appropriate time | 
|  | 1878 | */ | 
|  | 1879 | #ifdef CONFIG_GDBSTUB_CONSOLE | 
|  | 1880 | static int __init gdbstub_postinit(void) | 
|  | 1881 | { | 
|  | 1882 | printk(KERN_NOTICE "registering console\n"); | 
|  | 1883 | register_console(&gdbstub_console); | 
|  | 1884 | return 0; | 
|  | 1885 | } | 
|  | 1886 |  | 
|  | 1887 | __initcall(gdbstub_postinit); | 
|  | 1888 | #endif | 
|  | 1889 |  | 
|  | 1890 | /* | 
|  | 1891 | * handle character reception on GDB serial port | 
|  | 1892 | * - jump into the GDB stub if BREAK is detected on the serial line | 
|  | 1893 | */ | 
|  | 1894 | asmlinkage void gdbstub_rx_irq(struct pt_regs *regs, enum exception_code excep) | 
|  | 1895 | { | 
|  | 1896 | char ch; | 
|  | 1897 | int ret; | 
|  | 1898 |  | 
|  | 1899 | gdbstub_entry("--> gdbstub_rx_irq\n"); | 
|  | 1900 |  | 
|  | 1901 | do { | 
|  | 1902 | ret = gdbstub_io_rx_char(&ch, 1); | 
|  | 1903 | if (ret != -EIO && ret != -EAGAIN) { | 
|  | 1904 | if (ret != -EINTR) | 
|  | 1905 | gdbstub_rx_unget = ch; | 
|  | 1906 | gdbstub(regs, excep); | 
|  | 1907 | } | 
|  | 1908 | } while (ret != -EAGAIN); | 
|  | 1909 |  | 
|  | 1910 | gdbstub_entry("<-- gdbstub_rx_irq\n"); | 
|  | 1911 | } |