blob: 4493a1591986c3380df2c86d40a8996b1688b96a [file] [log] [blame]
Stefan Roesea47a12b2010-04-15 16:07:28 +02001/* taken from arch/powerpc/kernel/ppc-stub.c */
wdenk4a9cbbe2002-08-27 09:48:53 +00002
3/****************************************************************************
4
5 THIS SOFTWARE IS NOT COPYRIGHTED
6
7 HP offers the following for use in the public domain. HP makes no
8 warranty with regard to the software or its performance and the
9 user accepts the software "AS IS" with all faults.
10
11 HP DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED, WITH REGARD
12 TO THIS SOFTWARE INCLUDING BUT NOT LIMITED TO THE WARRANTIES
13 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
14
15****************************************************************************/
16
17/****************************************************************************
18 * Header: remcom.c,v 1.34 91/03/09 12:29:49 glenne Exp $
19 *
20 * Module name: remcom.c $
21 * Revision: 1.34 $
22 * Date: 91/03/09 12:29:49 $
23 * Contributor: Lake Stevens Instrument Division$
24 *
25 * Description: low level support for gdb debugger. $
26 *
27 * Considerations: only works on target hardware $
28 *
29 * Written by: Glenn Engel $
30 * ModuleState: Experimental $
31 *
32 * NOTES: See Below $
33 *
34 * Modified for SPARC by Stu Grossman, Cygnus Support.
35 *
36 * This code has been extensively tested on the Fujitsu SPARClite demo board.
37 *
38 * To enable debugger support, two things need to happen. One, a
39 * call to set_debug_traps() is necessary in order to allow any breakpoints
40 * or error conditions to be properly intercepted and reported to gdb.
41 * Two, a breakpoint needs to be generated to begin communication. This
42 * is most easily accomplished by a call to breakpoint(). Breakpoint()
43 * simulates a breakpoint by executing a trap #1.
44 *
45 *************
46 *
47 * The following gdb commands are supported:
48 *
49 * command function Return value
50 *
51 * g return the value of the CPU registers hex data or ENN
52 * G set the value of the CPU registers OK or ENN
53 * qOffsets Get section offsets. Reply is Text=xxx;Data=yyy;Bss=zzz
54 *
55 * mAA..AA,LLLL Read LLLL bytes at address AA..AA hex data or ENN
56 * MAA..AA,LLLL: Write LLLL bytes at address AA.AA OK or ENN
57 *
58 * c Resume at current address SNN ( signal NN)
59 * cAA..AA Continue at address AA..AA SNN
60 *
61 * s Step one instruction SNN
62 * sAA..AA Step one instruction from AA..AA SNN
63 *
64 * k kill
65 *
66 * ? What was the last sigval ? SNN (signal NN)
67 *
68 * bBB..BB Set baud rate to BB..BB OK or BNN, then sets
69 * baud rate
70 *
71 * All commands and responses are sent with a packet which includes a
72 * checksum. A packet consists of
73 *
74 * $<packet info>#<checksum>.
75 *
76 * where
77 * <packet info> :: <characters representing the command or response>
78 * <checksum> :: <two hex digits computed as modulo 256 sum of <packetinfo>>
79 *
80 * When a packet is received, it is first acknowledged with either '+' or '-'.
81 * '+' indicates a successful transfer. '-' indicates a failed transfer.
82 *
83 * Example:
84 *
85 * Host: Reply:
86 * $m0,10#2a +$00010203040506070809101112131415#42
87 *
88 ****************************************************************************/
89
90#include <common.h>
Simon Glass25a58182020-05-10 11:40:06 -060091#include <asm/ptrace.h>
wdenk4a9cbbe2002-08-27 09:48:53 +000092
93#include <kgdb.h>
94#include <command.h>
95
wdenk4a9cbbe2002-08-27 09:48:53 +000096#undef KGDB_DEBUG
97
98/*
99 * BUFMAX defines the maximum number of characters in inbound/outbound buffers
100 */
101#define BUFMAX 1024
102static char remcomInBuffer[BUFMAX];
103static char remcomOutBuffer[BUFMAX];
104static char remcomRegBuffer[BUFMAX];
105
106static int initialized = 0;
Peng Fanf9f040b2014-09-01 21:48:07 +0800107static int kgdb_active;
wdenk4a9cbbe2002-08-27 09:48:53 +0000108static struct pt_regs entry_regs;
Wolfgang Denkcc3843e2008-03-09 10:33:31 +0100109static long error_jmp_buf[BUFMAX/2];
wdenk4a9cbbe2002-08-27 09:48:53 +0000110static int longjmp_on_fault = 0;
111#ifdef KGDB_DEBUG
112static int kdebug = 1;
113#endif
114
115static const char hexchars[]="0123456789abcdef";
116
117/* Convert ch from a hex digit to an int */
118static int
119hex(unsigned char ch)
120{
121 if (ch >= 'a' && ch <= 'f')
122 return ch-'a'+10;
123 if (ch >= '0' && ch <= '9')
124 return ch-'0';
125 if (ch >= 'A' && ch <= 'F')
126 return ch-'A'+10;
127 return -1;
128}
129
130/* Convert the memory pointed to by mem into hex, placing result in buf.
131 * Return a pointer to the last char put in buf (null).
132 */
133static unsigned char *
134mem2hex(char *mem, char *buf, int count)
135{
Robin Getz16035bc2009-12-21 18:40:44 -0500136 char *tmp;
wdenk4a9cbbe2002-08-27 09:48:53 +0000137 unsigned char ch;
138
Robin Getz16035bc2009-12-21 18:40:44 -0500139 /*
140 * We use the upper half of buf as an intermediate buffer for the
141 * raw memory copy. Hex conversion will work against this one.
142 */
143 tmp = buf + count;
wdenk4a9cbbe2002-08-27 09:48:53 +0000144 longjmp_on_fault = 1;
Robin Getz16035bc2009-12-21 18:40:44 -0500145
146 memcpy(tmp, mem, count);
147
wdenk4a9cbbe2002-08-27 09:48:53 +0000148 while (count-- > 0) {
Robin Getz16035bc2009-12-21 18:40:44 -0500149 ch = *tmp++;
wdenk4a9cbbe2002-08-27 09:48:53 +0000150 *buf++ = hexchars[ch >> 4];
151 *buf++ = hexchars[ch & 0xf];
152 }
153 *buf = 0;
154 longjmp_on_fault = 0;
Wolfgang Denk77ddac92005-10-13 16:45:02 +0200155 return (unsigned char *)buf;
wdenk4a9cbbe2002-08-27 09:48:53 +0000156}
157
158/* convert the hex array pointed to by buf into binary to be placed in mem
159 * return a pointer to the character AFTER the last byte fetched from buf.
160*/
161static char *
162hex2mem(char *buf, char *mem, int count)
163{
Robin Getz16035bc2009-12-21 18:40:44 -0500164 int hexValue;
165 char *tmp_raw, *tmp_hex;
166
167 /*
168 * We use the upper half of buf as an intermediate buffer for the
169 * raw memory that is converted from hex.
170 */
171 tmp_raw = buf + count * 2;
172 tmp_hex = tmp_raw - 1;
wdenk4a9cbbe2002-08-27 09:48:53 +0000173
174 longjmp_on_fault = 1;
Robin Getz16035bc2009-12-21 18:40:44 -0500175 while (tmp_hex >= buf) {
176 tmp_raw--;
177 hexValue = hex(*tmp_hex--);
178 if (hexValue < 0)
wdenk4a9cbbe2002-08-27 09:48:53 +0000179 kgdb_error(KGDBERR_NOTHEXDIG);
Robin Getz16035bc2009-12-21 18:40:44 -0500180 *tmp_raw = hexValue;
181 hexValue = hex(*tmp_hex--);
182 if (hexValue < 0)
wdenk4a9cbbe2002-08-27 09:48:53 +0000183 kgdb_error(KGDBERR_NOTHEXDIG);
Robin Getz16035bc2009-12-21 18:40:44 -0500184 *tmp_raw |= hexValue << 4;
185
wdenk4a9cbbe2002-08-27 09:48:53 +0000186 }
Robin Getz16035bc2009-12-21 18:40:44 -0500187
188 memcpy(mem, tmp_raw, count);
189
190 kgdb_flush_cache_range((void *)mem, (void *)(mem+count));
wdenk4a9cbbe2002-08-27 09:48:53 +0000191 longjmp_on_fault = 0;
192
193 return buf;
194}
195
196/*
197 * While we find nice hex chars, build an int.
198 * Return number of chars processed.
199 */
200static int
201hexToInt(char **ptr, int *intValue)
202{
203 int numChars = 0;
204 int hexValue;
205
206 *intValue = 0;
207
208 longjmp_on_fault = 1;
209 while (**ptr) {
210 hexValue = hex(**ptr);
211 if (hexValue < 0)
212 break;
213
214 *intValue = (*intValue << 4) | hexValue;
215 numChars ++;
216
217 (*ptr)++;
218 }
219 longjmp_on_fault = 0;
220
221 return (numChars);
222}
223
224/* scan for the sequence $<data>#<checksum> */
225static void
226getpacket(char *buffer)
227{
228 unsigned char checksum;
229 unsigned char xmitcsum;
230 int i;
231 int count;
232 unsigned char ch;
233
234 do {
235 /* wait around for the start character, ignore all other
236 * characters */
237 while ((ch = (getDebugChar() & 0x7f)) != '$') {
238#ifdef KGDB_DEBUG
239 if (kdebug)
240 putc(ch);
241#endif
242 ;
243 }
244
245 checksum = 0;
246 xmitcsum = -1;
247
248 count = 0;
249
250 /* now, read until a # or end of buffer is found */
251 while (count < BUFMAX) {
252 ch = getDebugChar() & 0x7f;
253 if (ch == '#')
254 break;
255 checksum = checksum + ch;
256 buffer[count] = ch;
257 count = count + 1;
258 }
259
260 if (count >= BUFMAX)
261 continue;
262
263 buffer[count] = 0;
264
265 if (ch == '#') {
266 xmitcsum = hex(getDebugChar() & 0x7f) << 4;
267 xmitcsum |= hex(getDebugChar() & 0x7f);
268 if (checksum != xmitcsum)
269 putDebugChar('-'); /* failed checksum */
270 else {
271 putDebugChar('+'); /* successful transfer */
272 /* if a sequence char is present, reply the ID */
273 if (buffer[2] == ':') {
274 putDebugChar(buffer[0]);
275 putDebugChar(buffer[1]);
276 /* remove sequence chars from buffer */
277 count = strlen(buffer);
278 for (i=3; i <= count; i++)
279 buffer[i-3] = buffer[i];
280 }
281 }
282 }
283 } while (checksum != xmitcsum);
284}
285
286/* send the packet in buffer. */
287static void
288putpacket(unsigned char *buffer)
289{
290 unsigned char checksum;
291 int count;
292 unsigned char ch, recv;
293
294 /* $<packet info>#<checksum>. */
295 do {
296 putDebugChar('$');
297 checksum = 0;
298 count = 0;
299
300 while ((ch = buffer[count])) {
301 putDebugChar(ch);
302 checksum += ch;
303 count += 1;
304 }
305
306 putDebugChar('#');
307 putDebugChar(hexchars[checksum >> 4]);
308 putDebugChar(hexchars[checksum & 0xf]);
309 recv = getDebugChar();
310 } while ((recv & 0x7f) != '+');
311}
312
313/*
314 * This function does all command processing for interfacing to gdb.
315 */
316static int
317handle_exception (struct pt_regs *regs)
318{
319 int addr;
320 int length;
321 char *ptr;
322 kgdb_data kd;
323 int i;
324
325 if (!initialized) {
326 printf("kgdb: exception before kgdb is initialized! huh?\n");
327 return (0);
328 }
329
Vagrant Cascadianeae4b2b2016-04-30 19:18:00 -0700330 /* probably should check which exception occurred as well */
wdenk4a9cbbe2002-08-27 09:48:53 +0000331 if (longjmp_on_fault) {
332 longjmp_on_fault = 0;
Wolfgang Denkcc3843e2008-03-09 10:33:31 +0100333 kgdb_longjmp(error_jmp_buf, KGDBERR_MEMFAULT);
wdenk4a9cbbe2002-08-27 09:48:53 +0000334 panic("kgdb longjump failed!\n");
335 }
336
337 if (kgdb_active) {
338 printf("kgdb: unexpected exception from within kgdb\n");
339 return (0);
340 }
341 kgdb_active = 1;
342
343 kgdb_interruptible(0);
344
345 printf("kgdb: handle_exception; trap [0x%x]\n", kgdb_trap(regs));
346
Wolfgang Denkcc3843e2008-03-09 10:33:31 +0100347 if (kgdb_setjmp(error_jmp_buf) != 0)
wdenk4a9cbbe2002-08-27 09:48:53 +0000348 panic("kgdb: error or fault in entry init!\n");
349
350 kgdb_enter(regs, &kd);
351
Peng Fanf9f040b2014-09-01 21:48:07 +0800352 entry_regs = *regs;
wdenk4a9cbbe2002-08-27 09:48:53 +0000353
354 ptr = remcomOutBuffer;
355
356 *ptr++ = 'T';
357
358 *ptr++ = hexchars[kd.sigval >> 4];
359 *ptr++ = hexchars[kd.sigval & 0xf];
360
361 for (i = 0; i < kd.nregs; i++) {
362 kgdb_reg *rp = &kd.regs[i];
363
364 *ptr++ = hexchars[rp->num >> 4];
365 *ptr++ = hexchars[rp->num & 0xf];
366 *ptr++ = ':';
Wolfgang Denk77ddac92005-10-13 16:45:02 +0200367 ptr = (char *)mem2hex((char *)&rp->val, ptr, 4);
wdenk4a9cbbe2002-08-27 09:48:53 +0000368 *ptr++ = ';';
369 }
370
371 *ptr = 0;
372
373#ifdef KGDB_DEBUG
374 if (kdebug)
375 printf("kgdb: remcomOutBuffer: %s\n", remcomOutBuffer);
376#endif
377
Wolfgang Denk77ddac92005-10-13 16:45:02 +0200378 putpacket((unsigned char *)&remcomOutBuffer);
wdenk4a9cbbe2002-08-27 09:48:53 +0000379
380 while (1) {
381 volatile int errnum;
382
383 remcomOutBuffer[0] = 0;
384
385 getpacket(remcomInBuffer);
386 ptr = &remcomInBuffer[1];
387
388#ifdef KGDB_DEBUG
389 if (kdebug)
390 printf("kgdb: remcomInBuffer: %s\n", remcomInBuffer);
391#endif
392
Wolfgang Denkcc3843e2008-03-09 10:33:31 +0100393 errnum = kgdb_setjmp(error_jmp_buf);
wdenk4a9cbbe2002-08-27 09:48:53 +0000394
395 if (errnum == 0) switch (remcomInBuffer[0]) {
396
397 case '?': /* report most recent signal */
398 remcomOutBuffer[0] = 'S';
399 remcomOutBuffer[1] = hexchars[kd.sigval >> 4];
400 remcomOutBuffer[2] = hexchars[kd.sigval & 0xf];
401 remcomOutBuffer[3] = 0;
402 break;
403
404#ifdef KGDB_DEBUG
405 case 'd':
406 /* toggle debug flag */
407 kdebug ^= 1;
408 break;
409#endif
410
411 case 'g': /* return the value of the CPU registers. */
412 length = kgdb_getregs(regs, remcomRegBuffer, BUFMAX);
413 mem2hex(remcomRegBuffer, remcomOutBuffer, length);
414 break;
415
416 case 'G': /* set the value of the CPU registers */
417 length = strlen(ptr);
418 if ((length & 1) != 0) kgdb_error(KGDBERR_BADPARAMS);
419 hex2mem(ptr, remcomRegBuffer, length/2);
420 kgdb_putregs(regs, remcomRegBuffer, length/2);
421 strcpy(remcomOutBuffer,"OK");
422 break;
423
424 case 'm': /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */
425 /* Try to read %x,%x. */
426
427 if (hexToInt(&ptr, &addr)
428 && *ptr++ == ','
429 && hexToInt(&ptr, &length)) {
430 mem2hex((char *)addr, remcomOutBuffer, length);
431 } else {
432 kgdb_error(KGDBERR_BADPARAMS);
433 }
434 break;
435
436 case 'M': /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
437 /* Try to read '%x,%x:'. */
438
439 if (hexToInt(&ptr, &addr)
440 && *ptr++ == ','
441 && hexToInt(&ptr, &length)
442 && *ptr++ == ':') {
443 hex2mem(ptr, (char *)addr, length);
444 strcpy(remcomOutBuffer, "OK");
445 } else {
446 kgdb_error(KGDBERR_BADPARAMS);
447 }
448 break;
449
450
451 case 'k': /* kill the program, actually return to monitor */
452 kd.extype = KGDBEXIT_KILL;
453 *regs = entry_regs;
wdenk4a9cbbe2002-08-27 09:48:53 +0000454 goto doexit;
455
456 case 'C': /* CSS continue with signal SS */
457 *ptr = '\0'; /* ignore the signal number for now */
458 /* fall through */
459
460 case 'c': /* cAA..AA Continue; address AA..AA optional */
461 /* try to read optional parameter, pc unchanged if no parm */
462 kd.extype = KGDBEXIT_CONTINUE;
463
464 if (hexToInt(&ptr, &addr)) {
465 kd.exaddr = addr;
466 kd.extype |= KGDBEXIT_WITHADDR;
467 }
468
469 goto doexit;
470
471 case 'S': /* SSS single step with signal SS */
472 *ptr = '\0'; /* ignore the signal number for now */
473 /* fall through */
474
475 case 's':
476 kd.extype = KGDBEXIT_SINGLE;
477
478 if (hexToInt(&ptr, &addr)) {
479 kd.exaddr = addr;
480 kd.extype |= KGDBEXIT_WITHADDR;
481 }
482
483 doexit:
484/* Need to flush the instruction cache here, as we may have deposited a
485 * breakpoint, and the icache probably has no way of knowing that a data ref to
486 * some location may have changed something that is in the instruction cache.
487 */
488 kgdb_flush_cache_all();
489 kgdb_exit(regs, &kd);
490 kgdb_active = 0;
491 kgdb_interruptible(1);
492 return (1);
493
494 case 'r': /* Reset (if user process..exit ???)*/
495 panic("kgdb reset.");
496 break;
497
498 case 'P': /* Pr=v set reg r to value v (r and v are hex) */
499 if (hexToInt(&ptr, &addr)
500 && *ptr++ == '='
501 && ((length = strlen(ptr)) & 1) == 0) {
502 hex2mem(ptr, remcomRegBuffer, length/2);
503 kgdb_putreg(regs, addr,
504 remcomRegBuffer, length/2);
505 strcpy(remcomOutBuffer,"OK");
506 } else {
507 kgdb_error(KGDBERR_BADPARAMS);
508 }
509 break;
510 } /* switch */
511
512 if (errnum != 0)
513 sprintf(remcomOutBuffer, "E%02d", errnum);
514
515#ifdef KGDB_DEBUG
516 if (kdebug)
517 printf("kgdb: remcomOutBuffer: %s\n", remcomOutBuffer);
518#endif
519
520 /* reply to the request */
Wolfgang Denk77ddac92005-10-13 16:45:02 +0200521 putpacket((unsigned char *)&remcomOutBuffer);
wdenk4a9cbbe2002-08-27 09:48:53 +0000522
523 } /* while(1) */
524}
525
526/*
527 * kgdb_init must be called *after* the
528 * monitor is relocated into ram
529 */
530void
531kgdb_init(void)
532{
533 kgdb_serial_init();
534 debugger_exception_handler = handle_exception;
535 initialized = 1;
536
537 putDebugStr("kgdb ready\n");
538 puts("ready\n");
539}
540
541void
542kgdb_error(int errnum)
543{
544 longjmp_on_fault = 0;
Wolfgang Denkcc3843e2008-03-09 10:33:31 +0100545 kgdb_longjmp(error_jmp_buf, errnum);
wdenk4a9cbbe2002-08-27 09:48:53 +0000546 panic("kgdb_error: longjmp failed!\n");
547}
548
549/* Output string in GDB O-packet format if GDB has connected. If nothing
550 output, returns 0 (caller must then handle output). */
551int
552kgdb_output_string (const char* s, unsigned int count)
553{
554 char buffer[512];
555
556 count = (count <= (sizeof(buffer) / 2 - 2))
557 ? count : (sizeof(buffer) / 2 - 2);
558
559 buffer[0] = 'O';
560 mem2hex ((char *)s, &buffer[1], count);
Wolfgang Denk77ddac92005-10-13 16:45:02 +0200561 putpacket((unsigned char *)&buffer);
wdenk4a9cbbe2002-08-27 09:48:53 +0000562
563 return 1;
564}
565
566void
567breakpoint(void)
568{
569 if (!initialized) {
570 printf("breakpoint() called b4 kgdb init\n");
571 return;
572 }
573
574 kgdb_breakpoint(0, 0);
575}
576
577int
Simon Glass09140112020-05-10 11:40:03 -0600578do_kgdb(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
wdenk4a9cbbe2002-08-27 09:48:53 +0000579{
580 printf("Entering KGDB mode via exception handler...\n\n");
581 kgdb_breakpoint(argc - 1, argv + 1);
582 printf("\nReturned from KGDB mode\n");
583 return 0;
584}
585
wdenk0d498392003-07-01 21:06:45 +0000586U_BOOT_CMD(
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200587 kgdb, CONFIG_SYS_MAXARGS, 1, do_kgdb,
Peter Tyser2fb26042009-01-27 18:03:12 -0600588 "enter gdb remote debug mode",
wdenk8bde7f72003-06-27 21:31:46 +0000589 "[arg0 arg1 .. argN]\n"
590 " - executes a breakpoint so that kgdb mode is\n"
591 " entered via the exception handler. To return\n"
592 " to the monitor, the remote gdb debugger must\n"
593 " execute a \"continue\" or \"quit\" command.\n"
594 "\n"
595 " if a program is loaded by the remote gdb, any args\n"
596 " passed to the kgdb command are given to the loaded\n"
597 " program if it is executed (see the \"hello_world\"\n"
598 " example program in the U-Boot examples directory)."
599);