Mercurial > ecos
annotate packages/hal/common/current/src/generic-stub.c @ 28:18ee5a9c102e ecos-sw-1999-08-09
Merge from eCos master repository on 1999-08-09-17:04:48-BST
| author | jlarmour |
|---|---|
| date | Mon, 09 Aug 1999 16:37:19 +0000 |
| parents | 443894e2e912 |
| children | 29bc183297e1 |
| rev | line source |
|---|---|
| 2 | 1 #include "board.h" |
| 2 | |
| 3 #ifdef CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS | |
| 4 | |
| 5 /* Eventually, this should default to ON */ | |
| 6 #if USE_GDBSTUB_PROTOTYPES | |
| 7 #include "stub-tservice.h" | |
| 8 #include "generic-stub.h" | |
| 9 #else | |
| 10 // Function declarations (prevents compiler warnings) | |
| 11 int stubhex (unsigned char ch); | |
| 12 static void getpacket (char *buffer); | |
| 13 static void unlock_thread_scheduler (void); | |
| 14 static uint32 crc32 (unsigned char *ptr, int len, uint32 crc); | |
| 15 #endif | |
| 16 | |
| 17 #include "thread-pkts.h" | |
| 18 /* Defines function macros if thread support is not selected in board.h */ | |
| 19 | |
| 20 | |
| 0 | 21 /**************************************************************************** |
| 22 | |
| 2 | 23 THIS SOFTWARE IS NOT COPYRIGHTED |
| 0 | 24 |
| 25 HP offers the following for use in the public domain. HP makes no | |
| 26 warranty with regard to the software or it's performance and the | |
| 27 user accepts the software "AS IS" with all faults. | |
| 28 | |
| 29 HP DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED, WITH REGARD | |
| 30 TO THIS SOFTWARE INCLUDING BUT NOT LIMITED TO THE WARRANTIES | |
| 31 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. | |
| 32 | |
| 33 ****************************************************************************/ | |
| 34 | |
| 35 /**************************************************************************** | |
| 36 * Header: remcom.c,v 1.34 91/03/09 12:29:49 glenne Exp $ | |
| 37 * | |
| 38 * Module name: remcom.c $ | |
| 39 * Revision: 1.34 $ | |
| 40 * Date: 91/03/09 12:29:49 $ | |
| 41 * Contributor: Lake Stevens Instrument Division$ | |
| 42 * | |
| 43 * Description: low level support for gdb debugger. $ | |
| 44 * | |
| 45 * Considerations: only works on target hardware $ | |
| 46 * | |
| 47 * Written by: Glenn Engel $ | |
| 48 * ModuleState: Experimental $ | |
| 49 * | |
| 50 * NOTES: See Below $ | |
| 51 * | |
| 2 | 52 * Modified for SPARC by Stu Grossman, Cygnus Solutions. |
| 0 | 53 * Modified for generic CygMON stub support by Bob Manson, Cygnus Solutions. |
| 54 * | |
| 55 * To enable debugger support, two things need to happen. One, a | |
| 2 | 56 * call to set_debug_traps () is necessary in order to allow any breakpoints |
| 0 | 57 * or error conditions to be properly intercepted and reported to gdb. |
| 58 * Two, a breakpoint needs to be generated to begin communication. This | |
| 2 | 59 * is most easily accomplished by a call to breakpoint (). Breakpoint () |
| 0 | 60 * simulates a breakpoint by executing a trap #1. |
| 61 * | |
| 62 ************* | |
| 63 * | |
| 64 * The following gdb commands are supported: | |
| 65 * | |
| 66 * command function Return value | |
| 67 * | |
| 68 * g return the value of the CPU registers hex data or ENN | |
| 69 * G set the value of the CPU registers OK or ENN | |
| 70 * | |
| 71 * mAA..AA,LLLL Read LLLL bytes at address AA..AA hex data or ENN | |
| 72 * MAA..AA,LLLL: Write LLLL bytes at address AA.AA OK or ENN | |
| 73 * | |
| 74 * c Resume at current address SNN ( signal NN) | |
| 75 * cAA..AA Continue at address AA..AA SNN | |
| 76 * | |
| 77 * s Step one instruction SNN | |
| 78 * sAA..AA Step one instruction from AA..AA SNN | |
| 79 * | |
| 80 * k kill | |
| 81 * | |
| 82 * ? What was the last sigval ? SNN (signal NN) | |
| 83 * | |
| 2 | 84 * bBB..BB Set baud rate to BB..BB OK or BNN, then sets |
| 85 * baud rate | |
| 0 | 86 * |
| 87 * All commands and responses are sent with a packet which includes a | |
| 88 * checksum. A packet consists of | |
| 89 * | |
| 90 * $<packet info>#<checksum>. | |
| 91 * | |
| 92 * where | |
| 93 * <packet info> :: <characters representing the command or response> | |
| 94 * <checksum> :: < two hex digits computed as modulo 256 sum of <packetinfo>> | |
| 95 * | |
| 96 * When a packet is received, it is first acknowledged with either '+' or '-'. | |
| 97 * '+' indicates a successful transfer. '-' indicates a failed transfer. | |
| 98 * | |
| 99 * Example: | |
| 100 * | |
| 101 * Host: Reply: | |
| 102 * $m0,10#2a +$00010203040506070809101112131415#42 | |
| 103 * | |
| 104 ****************************************************************************/ | |
| 105 | |
| 2 | 106 #ifndef __ECOS__ |
| 107 #include <string.h> | |
| 108 #include <signal.h> | |
| 109 #endif // __ECOS__ | |
| 0 | 110 |
| 111 /************************************************************************/ | |
| 112 /* BUFMAX defines the maximum number of characters in inbound/outbound buffers*/ | |
| 113 /* at least NUMREGBYTES*2 are needed for register packets */ | |
| 114 #define BUFMAX 2048 | |
| 115 | |
| 2 | 116 static int initialized = 0; /* !0 means we've been initialized */ |
| 117 | |
| 0 | 118 static int process_exception (int sigval); |
| 119 static void do_nothing (void); /* and do it gracefully */ | |
| 120 static int syscall_do_nothing (int); | |
| 2 | 121 |
| 122 void __free_program_args (void); | |
| 0 | 123 |
| 124 volatile __PFI __process_exception_vec = process_exception; | |
| 125 volatile __PFV __process_exit_vec = do_nothing; | |
| 126 volatile __PFI __process_syscall_vec = syscall_do_nothing; | |
| 127 volatile __PFI __process_signal_vec = NULL; | |
| 2 | 128 volatile __PFV __init_vec = NULL; |
| 129 volatile __PFV __cleanup_vec = NULL; | |
| 130 | |
| 131 static char *__add_program_arg (int argnum, uint32 arglen); | |
| 0 | 132 |
| 133 static const char hexchars[] = "0123456789abcdef"; | |
| 134 | |
| 2 | 135 static void process_query (char *pkt); |
| 136 static void process_set (char *pkt); | |
| 0 | 137 |
| 138 char | |
| 139 __tohex (int c) | |
| 140 { | |
| 141 return hexchars [c & 15]; | |
| 142 } | |
| 143 | |
| 2 | 144 #define __tohex(c) hexchars[(c) & 15] |
| 0 | 145 |
| 146 #ifndef NUMREGS_GDB | |
| 147 #define NUMREGS_GDB NUMREGS | |
| 148 #endif | |
| 149 | |
| 150 /* One pushback character. */ | |
| 151 int ungot_char = -1; | |
| 152 | |
| 153 static int | |
| 154 readDebugChar (void) | |
| 155 { | |
| 156 if (ungot_char > 0) | |
| 157 { | |
| 158 int result = ungot_char; | |
| 159 ungot_char = -1; | |
| 160 return result; | |
| 161 } | |
| 162 else | |
| 163 return getDebugChar (); | |
| 164 } | |
| 165 | |
| 166 /* Convert ch from a hex digit to an int. */ | |
| 167 | |
| 168 int | |
| 2 | 169 stubhex (ch) |
| 170 unsigned char ch; | |
| 0 | 171 { |
| 172 if (ch >= 'a' && ch <= 'f') | |
| 173 return ch-'a'+10; | |
| 174 if (ch >= '0' && ch <= '9') | |
| 175 return ch-'0'; | |
| 176 if (ch >= 'A' && ch <= 'F') | |
| 177 return ch-'A'+10; | |
| 178 return -1; | |
| 179 } | |
| 180 | |
| 181 static void | |
| 2 | 182 getpacket (buffer) |
| 183 char *buffer; | |
| 0 | 184 { |
| 185 struct gdb_packet packet; | |
| 186 | |
| 187 packet.state = 0; | |
| 188 packet.contents = buffer; | |
| 2 | 189 while (__add_char_to_packet (readDebugChar () & 0xff, &packet) != 1) |
| 0 | 190 { |
| 191 /* Empty */ | |
| 192 } | |
| 193 } | |
| 194 | |
| 195 int | |
| 2 | 196 __add_char_to_packet (ch, packet) |
| 197 unsigned int ch; | |
| 198 struct gdb_packet *packet; | |
| 0 | 199 { |
| 200 if (packet->state == 0) | |
| 201 { | |
| 202 if (ch == '$') | |
| 2 | 203 { |
| 204 packet->state = 1; | |
| 205 packet->length = 0; | |
| 206 packet->checksum = 0; | |
| 207 packet->xmitcsum = -1; | |
| 208 } | |
| 0 | 209 return 0; |
| 210 } | |
| 211 | |
| 212 if (packet->state == 1) | |
| 213 { | |
| 214 if (ch == '#') | |
| 2 | 215 { |
| 216 packet->contents[packet->length] = 0; | |
| 217 packet->state = 2; | |
| 218 } | |
| 0 | 219 else |
| 2 | 220 { |
| 221 if (packet->length == BUFMAX) { | |
| 222 packet->state = 0; | |
| 223 return -1; | |
| 224 } | |
| 225 packet->checksum += ch; | |
| 226 packet->contents[packet->length++] = ch; | |
| 227 } | |
| 0 | 228 return 0; |
| 229 } | |
| 230 | |
| 231 if (packet->state == 2) | |
| 232 { | |
| 233 packet->xmitcsum = stubhex (ch) << 4; | |
| 234 packet->state = 3; | |
| 235 return 0; | |
| 236 } | |
| 237 | |
| 238 if (packet->state == 3) | |
| 239 { | |
| 2 | 240 packet->xmitcsum |= stubhex (ch); |
| 0 | 241 if ((packet->checksum & 255) != packet->xmitcsum) |
| 2 | 242 { |
| 243 putDebugChar ('-'); /* failed checksum */ | |
| 244 packet->state = 0; | |
| 245 return -1; | |
| 246 } | |
| 0 | 247 else |
| 2 | 248 { |
| 249 putDebugChar ('+'); /* successful transfer */ | |
| 250 /* if a sequence char is present, reply the sequence ID */ | |
| 251 if (packet->contents[2] == ':') | |
| 252 { | |
| 253 uint32 count = packet->length; | |
| 254 uint32 i; | |
| 255 putDebugChar (packet->contents[0]); | |
| 256 putDebugChar (packet->contents[1]); | |
| 257 /* remove sequence chars from buffer */ | |
| 258 for (i=3; i <= count; i++) | |
| 259 packet->contents[i-3] = packet->contents[i]; | |
| 260 } | |
| 261 return 1; | |
| 262 } | |
| 0 | 263 } |
| 264 /* We should never get here. */ | |
| 265 packet->state = 0; | |
| 266 return -1; | |
| 267 } | |
| 268 | |
| 269 /* send the packet in buffer. */ | |
| 270 | |
| 2 | 271 void |
| 272 __putpacket (buffer) | |
| 273 char *buffer; | |
| 0 | 274 { |
| 275 unsigned char checksum; | |
| 2 | 276 uint32 count; |
| 0 | 277 unsigned char ch; |
| 278 | |
| 279 /* $<packet info>#<checksum>. */ | |
| 280 do | |
| 281 { | |
| 282 putDebugChar ('$'); | |
| 283 checksum = 0; | |
| 284 count = 0; | |
| 285 | |
| 286 while ((ch = buffer[count])) | |
| 2 | 287 { |
| 288 putDebugChar (ch); | |
| 289 checksum += ch; | |
| 290 count += 1; | |
| 291 } | |
| 0 | 292 |
| 293 putDebugChar ('#'); | |
| 294 putDebugChar (hexchars[(checksum >> 4) & 0xf]); | |
| 295 putDebugChar (hexchars[checksum & 0xf]); | |
| 296 | |
| 297 } | |
| 298 while ((readDebugChar () & 0x7f) != '+'); | |
| 299 } | |
| 300 | |
| 301 static char remcomInBuffer[BUFMAX]; | |
| 302 static char remcomOutBuffer[BUFMAX]; | |
| 303 | |
| 304 /* Indicate to caller of mem2hex or hex2mem that there has been an | |
| 305 error. */ | |
| 306 volatile int __mem_fault = 0; | |
| 307 | |
| 2 | 308 |
| 309 #ifndef TARGET_HAS_OWN_MEM_FUNCS | |
| 310 /* | |
| 311 * _target_readmem_hook / _target_writemem_hook: | |
| 312 * Allow target to get involved in reading/writing memory. | |
| 313 * | |
| 314 * If these hooks are defined by the target, they will be | |
| 315 * called for each user program memory access. Otherwise, the stub | |
| 316 * will simply dereference a pointer to access user program memory. | |
| 317 */ | |
| 318 | |
| 319 unsigned char (*_target_readmem_hook) (unsigned char* addr); | |
| 320 void (*_target_writemem_hook) (unsigned char* addr, | |
| 321 unsigned char value); | |
| 322 | |
| 323 static unsigned char | |
| 324 get_target_byte (volatile unsigned char *address) | |
| 0 | 325 { |
| 2 | 326 if (_target_readmem_hook) /* target needs to control memory access */ |
| 327 return _target_readmem_hook ((unsigned char *) address); | |
| 328 else | |
| 329 return *address; | |
| 330 } | |
| 331 | |
| 332 static void | |
| 333 put_target_byte (volatile unsigned char *address, unsigned char value) | |
| 334 { | |
| 335 if (_target_writemem_hook) /* target needs to control memory access */ | |
| 336 _target_writemem_hook ((unsigned char *) address, value); | |
| 337 else | |
| 338 *address = value; | |
| 339 } | |
| 340 | |
| 341 /* These are the "arguments" to __do_read_mem and __do_write_mem, | |
| 342 which are passed as globals to avoid squeezing them thru | |
| 343 __set_mem_fault_trap. */ | |
| 344 | |
| 345 static volatile target_register_t memCount; | |
| 346 static volatile unsigned char *memSrc, *memDst; | |
| 0 | 347 |
| 2 | 348 /* |
| 349 * __do_read_mem: | |
| 350 * Copy from target memory to trusted memory. | |
| 351 */ | |
| 352 | |
| 353 static void | |
| 354 __do_read_mem (void) | |
| 355 { | |
| 356 __mem_fault = 0; | |
| 357 while (memCount) | |
| 358 { | |
| 359 unsigned char ch = get_target_byte (memSrc++); | |
| 360 | |
| 361 if (__mem_fault) | |
| 362 return; | |
| 363 *memDst++ = ch; | |
| 364 memCount--; | |
| 365 } | |
| 0 | 366 } |
| 367 | |
| 2 | 368 /* |
| 369 * __do_write_mem: | |
| 370 * Copy from trusted memory to target memory. | |
| 371 */ | |
| 372 | |
| 373 static void | |
| 374 __do_write_mem (void) | |
| 375 { | |
| 376 __mem_fault = 0; | |
| 377 while (memCount) | |
| 378 { | |
| 379 unsigned char ch = *memSrc++; | |
| 380 | |
| 381 put_target_byte (memDst++, ch); | |
| 382 if (__mem_fault) | |
| 383 return; | |
| 384 memCount--; | |
| 385 } | |
| 386 } | |
| 387 | |
| 388 /* | |
| 389 * __read_mem_safe: | |
| 390 * Get contents of target memory, abort on error. | |
| 391 */ | |
| 392 | |
| 0 | 393 int |
| 394 __read_mem_safe (unsigned char *dst, target_register_t src, int count) | |
| 395 { | |
| 2 | 396 memCount = count; |
| 397 memSrc = (unsigned char *) src; | |
| 398 memDst = (unsigned char *) dst; | |
| 399 __set_mem_fault_trap (__do_read_mem); | |
| 400 return count - memCount; /* return number of bytes successfully read */ | |
| 0 | 401 } |
| 402 | |
| 2 | 403 /* |
| 404 * __write_mem_safe: | |
| 405 * Set contents of target memory, abort on error. | |
| 406 */ | |
| 407 | |
| 0 | 408 int |
| 409 __write_mem_safe (unsigned char *src, target_register_t dst, int count) | |
| 410 { | |
| 2 | 411 memCount = count; |
| 412 memSrc = (unsigned char *) src; | |
| 413 memDst = (unsigned char *) dst; | |
| 414 __set_mem_fault_trap (__do_write_mem); | |
| 415 return count - memCount; /* return number of bytes successfully read */ | |
| 0 | 416 } |
| 417 | |
| 2 | 418 #endif /* TARGET_HAS_OWN_MEM_FUNCS */ |
| 419 | |
| 420 /* These are the "arguments" to __mem2hex_helper and __hex2mem_helper, | |
| 421 which are passed as globals to avoid squeezing them thru | |
| 422 __set_mem_fault_trap. */ | |
| 423 | |
| 424 static int hexMemCount; | |
| 425 static char *hexMemSrc, *hexMemDst; | |
| 426 static int may_fault_mode; | |
| 427 | |
| 428 /* Hamburger helper? */ | |
| 429 static void | |
| 430 __mem2hex_helper (void) | |
| 431 { | |
| 432 __mem_fault = 0; | |
| 433 while (hexMemCount-- > 0) | |
| 434 { | |
| 435 unsigned char ch; | |
| 436 | |
| 437 if (may_fault_mode) | |
| 438 __read_mem_safe (&ch, (target_register_t) (hexMemSrc++), 1); | |
| 439 else | |
| 440 ch = *(hexMemSrc++); | |
| 441 if (__mem_fault) | |
| 442 return; | |
| 443 *(hexMemDst++) = hexchars[(ch >> 4) & 0xf]; | |
| 444 if (__mem_fault) | |
| 445 return; | |
| 446 *(hexMemDst++) = hexchars[ch & 0xf]; | |
| 447 if (__mem_fault) | |
| 448 return; | |
| 449 } | |
| 450 } | |
| 451 | |
| 452 /* Convert the memory pointed to by MEM into HEX, placing result in BUF. | |
| 453 * Return a pointer to the last char put in buf (NUL). In case of a memory | |
| 454 * fault, return 0. | |
| 0 | 455 * If MAY_FAULT is non-zero, then we will handle memory faults by returning |
| 2 | 456 * a 0 (and assume that MEM is a pointer into the user program), else we |
| 457 * treat a fault like any other fault in the stub (and assume that MEM is | |
| 458 * a pointer into the stub's memory). | |
| 0 | 459 */ |
| 460 | |
| 2 | 461 char * |
| 462 __mem2hex (mem, buf, count, may_fault) | |
| 463 char *mem; | |
| 464 char *buf; | |
| 0 | 465 int count; |
| 466 int may_fault; | |
| 467 { | |
| 2 | 468 hexMemDst = (unsigned char *) buf; |
| 469 hexMemSrc = (unsigned char *) mem; | |
| 470 hexMemCount = count; | |
| 471 may_fault_mode = may_fault; | |
| 472 | |
| 473 if (may_fault) | |
| 0 | 474 { |
| 2 | 475 if (__set_mem_fault_trap (__mem2hex_helper)) |
| 476 return 0; | |
| 0 | 477 } |
| 2 | 478 else |
| 479 __mem2hex_helper (); | |
| 0 | 480 |
| 2 | 481 *hexMemDst = 0; |
| 0 | 482 |
| 2 | 483 return (char *) hexMemDst; |
| 0 | 484 } |
| 485 | |
| 2 | 486 static void |
| 487 __hex2mem_helper (void) | |
| 0 | 488 { |
| 2 | 489 target_register_t i; |
| 0 | 490 unsigned char ch; |
| 491 | |
| 2 | 492 __mem_fault = 0; |
| 493 for (i=0; i < hexMemCount && *hexMemSrc; i++) | |
| 0 | 494 { |
| 2 | 495 ch = stubhex (*(hexMemSrc++)) << 4; |
| 496 if (__mem_fault) | |
| 497 return; | |
| 498 ch |= stubhex (*(hexMemSrc++)); | |
| 499 if (__mem_fault) | |
| 500 return; | |
| 501 if (may_fault_mode) | |
| 502 __write_mem_safe (&ch, (target_register_t) (hexMemDst++), 1); | |
| 503 else | |
| 504 *(hexMemDst++) = ch; | |
| 0 | 505 if (__mem_fault) |
| 2 | 506 return; |
| 0 | 507 } |
| 2 | 508 } |
| 509 | |
| 510 /* Convert COUNT bytes of the hex array pointed to by BUF into binary | |
| 511 to be placed in MEM. Return a pointer to the character AFTER the | |
| 512 last byte written. | |
| 513 | |
| 514 If MAY_FAULT is set, we will return a non-zero value if a memory | |
| 515 fault occurs (and we assume that MEM is a pointer into the user | |
| 516 program). Otherwise, we will take a trap just like any other memory | |
| 517 fault (and assume that MEM points into the stub's memory). */ | |
| 0 | 518 |
| 2 | 519 char * |
| 520 __hex2mem (buf, mem, count, may_fault) | |
| 521 char *buf; | |
| 522 char *mem; | |
| 523 int count; | |
| 524 int may_fault; | |
| 525 { | |
| 526 hexMemSrc = (unsigned char *) buf; | |
| 527 hexMemDst = (unsigned char *) mem; | |
| 528 hexMemCount = count; | |
| 529 may_fault_mode = may_fault; | |
| 0 | 530 |
| 2 | 531 if (may_fault) |
| 532 { | |
| 533 if (__set_mem_fault_trap (__hex2mem_helper)) | |
| 534 return 0; | |
| 535 } | |
| 536 else | |
| 537 __hex2mem_helper (); | |
| 538 | |
| 539 return (char *) hexMemDst; | |
| 540 } | |
| 541 | |
| 542 void | |
| 543 set_debug_traps (void) | |
| 544 { | |
| 545 __install_traps (); | |
| 546 initialized = 1; /* FIXME: Change this to dbg_stub_initialized */ | |
| 0 | 547 } |
| 548 | |
| 549 /* | |
| 550 * While we find nice hex chars, build an int. | |
| 551 * Return number of chars processed. | |
| 552 */ | |
| 553 | |
| 2 | 554 unsigned int |
| 555 __hexToInt (char **ptr, target_register_t *intValue) | |
| 0 | 556 { |
| 557 int numChars = 0; | |
| 558 int hexValue; | |
| 559 | |
| 560 *intValue = 0; | |
| 561 | |
| 562 while (**ptr) | |
| 563 { | |
| 2 | 564 hexValue = stubhex (**ptr); |
| 0 | 565 if (hexValue < 0) |
| 2 | 566 break; |
| 0 | 567 |
| 568 *intValue = (*intValue << 4) | hexValue; | |
| 569 numChars ++; | |
| 570 | |
| 571 (*ptr)++; | |
| 572 } | |
| 573 | |
| 574 return (numChars); | |
| 575 } | |
| 576 | |
| 577 /* | |
| 578 * Complement of __hexToInt: take an int of size "numBits", | |
| 579 * convert it to a hex string. Return length of (unterminated) output. | |
| 580 */ | |
| 581 | |
| 582 unsigned int | |
| 583 __intToHex (char *ptr, target_register_t intValue, int numBits) | |
| 584 { | |
| 585 int numChars = 0; | |
| 586 | |
| 587 if (intValue == 0) | |
| 588 { | |
| 589 *(ptr++) = '0'; | |
| 590 *(ptr++) = '0'; | |
| 591 return 2; | |
| 592 } | |
| 593 | |
| 594 numBits = (numBits + 7) / 8; | |
| 595 while (numBits) | |
| 596 { | |
| 597 int v = (intValue >> ((numBits - 1) * 8)); | |
| 598 if (v || (numBits == 1)) | |
| 2 | 599 { |
| 600 v = v & 255; | |
| 601 *(ptr++) = __tohex ((v / 16) & 15); | |
| 602 *(ptr++) = __tohex (v & 15); | |
| 603 numChars += 2; | |
| 604 } | |
| 0 | 605 numBits--; |
| 606 } | |
| 607 | |
| 608 return (numChars); | |
| 609 } | |
| 610 | |
| 2 | 611 #if DEBUG_THREADS |
| 612 /* | |
| 613 * Kernel Thread Control | |
| 614 * | |
| 615 * If the current thread is set to other than zero (or minus one), | |
| 616 * then ask the kernel to lock it's scheduler so that only that thread | |
| 617 * can run. | |
| 618 */ | |
| 619 | |
| 620 static unsigned char did_lock_scheduler = 0; | |
| 621 static unsigned char did_disable_interrupts = 0; | |
| 622 | |
| 623 /* Pointer to "kernel call" for scheduler control */ | |
| 624 static int (*schedlock_fn) (int, int, long) = stub_lock_scheduler; | |
| 625 | |
| 626 /* Pointer to target stub call for disabling interrupts. | |
| 627 Target stub will initialize this if it can. */ | |
| 628 int (*__disable_interrupts_hook) (int); /* don't initialize here! */ | |
| 629 #endif | |
| 630 | |
| 631 static void | |
| 632 lock_thread_scheduler (int kind) /* "step" or "continue" */ | |
| 633 { | |
| 634 #if DEBUG_THREADS | |
| 635 int ret = 0; | |
| 636 | |
| 637 /* GDB will signal its desire to run a single thread | |
| 638 by setting _gdb_cont_thread to non-zero / non-negative. */ | |
| 639 if (_gdb_cont_thread <= 0) | |
| 640 return; | |
| 641 | |
| 642 if (schedlock_fn) /* kernel call */ | |
| 643 ret = (*schedlock_fn) (1, kind, _gdb_cont_thread); | |
| 644 | |
| 645 if (ret == 1) | |
| 646 { | |
| 647 did_lock_scheduler = 1; | |
| 648 return; | |
| 649 } | |
| 650 | |
| 651 if (schedlock_fn == 0 || /* no kernel scheduler call */ | |
| 652 ret == -1) /* kernel asks stub to handle it */ | |
| 653 if (__disable_interrupts_hook) /* target stub has capability */ | |
| 654 if ((*__disable_interrupts_hook) (1)) | |
| 655 { | |
| 656 did_disable_interrupts = 1; | |
| 657 return; | |
| 658 } | |
| 659 #endif /* DEBUG_THREADS */ | |
| 660 } | |
| 661 | |
| 662 static void | |
| 663 unlock_thread_scheduler () | |
| 664 { | |
| 665 #if DEBUG_THREADS | |
| 666 if (did_lock_scheduler) | |
| 667 if (schedlock_fn) /* kernel call */ | |
| 668 { | |
| 669 (*schedlock_fn) (0, 0, _gdb_cont_thread); | |
| 670 /* I could check the return value, but | |
| 671 what would I do if it failed??? */ | |
| 672 did_lock_scheduler = 0; | |
| 673 } | |
| 674 if (did_disable_interrupts) | |
| 675 if (__disable_interrupts_hook) /* target stub call */ | |
| 676 { | |
| 677 (*__disable_interrupts_hook) (0); | |
| 678 /* Again, I could check the return value, but | |
| 679 what would I do if it failed??? */ | |
| 680 did_disable_interrupts = 0; | |
| 681 } | |
| 682 #endif /* DEBUG_THREADS */ | |
| 683 } | |
| 684 | |
| 0 | 685 void |
| 686 __handle_exception (void) | |
| 687 { | |
| 688 int sigval; | |
| 689 | |
| 2 | 690 #ifdef TARGET_HAS_NEXT_STEP |
| 691 if (! __next_step_done ()) | |
| 692 { | |
| 693 __clear_breakpoints (); | |
| 694 __install_breakpoints (); | |
| 695 __single_step (); | |
| 696 return; | |
| 697 } | |
| 698 #endif | |
| 0 | 699 |
| 2 | 700 #ifdef __ECOS__ |
| 701 // We need to unpack the registers before they are accessed. | |
| 702 if (__cleanup_vec != NULL) | |
| 703 __cleanup_vec (); | |
| 0 | 704 |
| 2 | 705 #ifdef CYGDBG_HAL_DEBUG_GDB_BREAK_SUPPORT |
| 706 // Special case for GDB BREAKs. This flag is set by cyg_stub_cleanup. | |
| 707 if (cyg_hal_gdb_break) { | |
| 708 cyg_hal_gdb_break = 0; | |
| 709 sigval = SIGINT; | |
| 710 } else | |
| 711 #endif | |
| 712 sigval = __computeSignal (__get_trap_number ()); | |
| 713 #else // __ECOS__ | |
| 0 | 714 /* reply to host that an exception has occurred */ |
| 715 sigval = __computeSignal (__get_trap_number ()); | |
| 2 | 716 #endif // __ECOS__ |
| 0 | 717 |
| 718 if (__is_breakpoint_function ()) | |
| 719 __skipinst (); | |
| 720 | |
| 2 | 721 #ifndef __ECOS__ |
| 722 if (__cleanup_vec != NULL) | |
| 723 __cleanup_vec (); | |
| 724 #endif // !__ECOS__ | |
| 725 | |
| 726 __clear_breakpoints (); | |
| 727 | |
| 728 /* Undo effect of previous single step. */ | |
| 729 unlock_thread_scheduler (); | |
| 730 __clear_single_step (); | |
| 731 | |
| 732 #ifdef SIGSYSCALL | |
| 733 if (sigval == SIGSYSCALL) | |
| 0 | 734 { |
| 735 int val; | |
| 736 /* Do the skipinst FIRST. */ | |
| 2 | 737 #ifndef SYSCALL_PC_AFTER_INST |
| 0 | 738 __skipinst (); |
| 2 | 739 #endif |
| 0 | 740 val = __process_syscall_vec (__get_syscall_num ()); |
| 2 | 741 if (val < 0) |
| 742 sigval = -val; | |
| 743 else | |
| 744 sigval = 0; | |
| 0 | 745 } |
| 746 | |
| 747 #endif | |
| 748 | |
| 2 | 749 /* Indirect function call to stub, cygmon monitor or other */ |
| 750 if (sigval != 0) | |
| 751 { | |
| 752 while (__process_exception_vec (sigval)) | |
| 753 { | |
| 754 /* Empty! */ | |
| 755 } | |
| 756 } | |
| 0 | 757 |
| 2 | 758 __install_breakpoints (); |
| 0 | 759 |
| 2 | 760 if (__init_vec != NULL) |
| 761 __init_vec (); | |
| 0 | 762 } |
| 763 | |
| 2 | 764 /* |
| 765 * _get_trace_register_hook: | |
| 766 * This function pointer will be non-zero if the trace component | |
| 767 * wants to intercept requests for register values. | |
| 768 * | |
| 769 * FIXME: evidently I need a new hook for large registers... | |
| 770 */ | |
| 771 | |
| 772 int (*_get_trace_register_hook) (regnames_t, target_register_t *); | |
| 773 | |
| 774 int | |
| 775 __process_packet (char *packet) | |
| 0 | 776 { |
| 2 | 777 int is_binary = 0; |
| 0 | 778 remcomOutBuffer[0] = 0; |
| 779 | |
| 780 switch (packet[0]) | |
| 781 { | |
| 782 case '?': | |
| 783 { | |
| 2 | 784 int sigval = __computeSignal (__get_trap_number ()); |
| 785 remcomOutBuffer[0] = 'S'; | |
| 786 remcomOutBuffer[1] = hexchars[(sigval >> 4) & 0xf]; | |
| 787 remcomOutBuffer[2] = hexchars[sigval & 0xf]; | |
| 788 remcomOutBuffer[3] = 0; | |
| 789 break; | |
| 0 | 790 } |
| 791 | |
| 792 case 'd': | |
| 793 /* toggle debug flag */ | |
| 794 break; | |
| 795 | |
| 796 case 'q': | |
| 797 /* general query packet */ | |
| 798 process_query (&packet[1]); | |
| 799 break; | |
| 800 | |
| 801 case 'Q': | |
| 802 /* general set packet */ | |
| 803 process_set (&packet[1]); | |
| 804 break; | |
| 805 | |
| 2 | 806 case 'g': /* return the value of the CPU registers */ |
| 0 | 807 { |
| 2 | 808 char *ptr = remcomOutBuffer; |
| 809 int regnum; | |
| 810 | |
| 811 for (regnum = 0; regnum < NUMREGS_GDB; regnum++) | |
| 812 { | |
| 813 /* We need to compensate for the value offset within the | |
| 814 register. */ | |
| 815 char dummyDat[32]; | |
| 816 target_register_t addr; | |
| 817 char *vptr; | |
| 818 int reg_valid = 1; | |
| 819 | |
| 820 #ifdef TARGET_HAS_LARGE_REGISTERS | |
| 821 if (sizeof (target_register_t) < REGSIZE (regnum)) | |
| 822 { | |
| 823 get_register_as_bytes (regnum, dummyDat); | |
| 824 vptr = dummyDat; | |
| 825 } | |
| 826 else | |
| 827 #endif | |
| 828 { | |
| 829 if (_get_trace_register_hook) | |
| 830 reg_valid = _get_trace_register_hook (regnum, &addr); | |
| 831 else | |
| 832 addr = get_register (regnum); | |
| 833 | |
| 834 vptr = ((char *) &addr) + sizeof (addr) - REGSIZE (regnum); | |
| 835 if (sizeof (addr) < REGSIZE (regnum)) | |
| 836 { | |
| 837 int off = REGSIZE (regnum) - sizeof (addr); | |
| 838 int x; | |
| 0 | 839 |
| 2 | 840 for (x = 0; x < off; x++) |
| 841 dummyDat[x] = 0; | |
| 842 memcpy (dummyDat + off, &addr, sizeof (addr)); | |
| 843 vptr = dummyDat; | |
| 844 } | |
| 845 } | |
| 846 if (reg_valid) /* we have a valid reg value */ | |
| 847 { | |
| 848 ptr = __mem2hex (vptr, ptr, REGSIZE (regnum), 0); | |
| 849 } | |
| 850 else | |
| 851 { | |
| 852 /* Trace component returned a failure code. | |
| 853 This means that the register value is not available. | |
| 854 We'll fill it with 'x's, and GDB will understand. */ | |
| 855 memset (ptr, 'x', 2 * REGSIZE (regnum)); | |
| 856 ptr += 2 * REGSIZE (regnum); | |
| 857 } | |
| 858 } | |
| 859 break; | |
| 860 } | |
| 0 | 861 |
| 2 | 862 case 'A': /* set program arguments */ |
| 863 { | |
| 864 if (packet[1] == '\0') | |
| 865 { | |
| 866 __free_program_args (); | |
| 867 strcpy (remcomOutBuffer, "OK"); | |
| 868 } | |
| 869 else | |
| 870 { | |
| 871 target_register_t arglen, argnum; | |
| 872 char *ptr = &packet[1]; | |
| 873 | |
| 874 while (1) | |
| 875 { | |
| 876 if (__hexToInt (&ptr, &arglen) | |
| 877 && (*ptr++ == ',') | |
| 878 && __hexToInt (&ptr, &argnum) | |
| 879 && (*ptr++ == ',')) | |
| 880 { | |
| 881 if (arglen > 0) | |
| 882 { | |
| 883 char *s = __add_program_arg (argnum, arglen); | |
| 884 if (s != NULL) | |
| 885 { | |
| 886 __hex2mem (ptr, s, arglen, 0); | |
| 887 } | |
| 888 ptr += arglen * 2; | |
| 889 } | |
| 890 | |
| 891 if (*ptr == ',') | |
| 892 ptr++; | |
| 893 else | |
| 894 break; | |
| 895 } | |
| 896 else | |
| 897 break; | |
| 898 } | |
| 899 if (*ptr == '\0') | |
| 900 strcpy (remcomOutBuffer, "OK"); | |
| 901 else | |
| 902 strcpy (remcomOutBuffer, "E01"); | |
| 903 } | |
| 0 | 904 } |
| 2 | 905 break; |
| 0 | 906 |
| 907 case 'P': | |
| 2 | 908 case 'G': /* set the value of the CPU registers - return OK */ |
| 0 | 909 { |
| 2 | 910 int x; |
| 911 int sr = 0, er = NUMREGS_GDB; | |
| 912 char *ptr = &packet[1]; | |
| 913 | |
| 914 if (packet[0] == 'P') | |
| 915 { | |
| 916 target_register_t regno; | |
| 0 | 917 |
| 2 | 918 if (__hexToInt (&ptr, ®no) |
| 919 && (*ptr++ == '=')) | |
| 920 { | |
| 921 sr = regno; | |
| 922 er = regno + 1; | |
| 923 } | |
| 924 else | |
| 925 { | |
| 926 strcpy (remcomOutBuffer, "P01"); | |
| 927 break; | |
| 928 } | |
| 929 } | |
| 0 | 930 |
| 2 | 931 for (x = sr; x < er; x++) |
| 932 { | |
| 933 target_register_t value = 0; | |
| 934 char *vptr; | |
| 935 | |
| 936 #ifdef TARGET_HAS_LARGE_REGISTERS | |
| 937 if (sizeof (target_register_t) < REGSIZE (x)) | |
| 938 { | |
| 939 char dummyDat [32]; | |
| 0 | 940 |
| 2 | 941 __hex2mem (ptr, dummyDat, REGSIZE (x), 0); |
| 942 put_register_as_bytes (x, dummyDat); | |
| 943 } | |
| 944 else | |
| 945 #endif | |
| 946 { | |
| 947 vptr = ((char *) &value) + sizeof (value) - REGSIZE (x); | |
| 948 __hex2mem (ptr, vptr, REGSIZE (x), 0); | |
| 949 put_register (x, value); | |
| 950 } | |
| 951 ptr += REGSIZE (x) * 2; | |
| 952 } | |
| 0 | 953 |
| 2 | 954 strcpy (remcomOutBuffer, "OK"); |
| 955 break; | |
| 0 | 956 } |
| 957 | |
| 2 | 958 case 'm': /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */ |
| 0 | 959 /* Try to read %x,%x. */ |
| 960 { | |
| 2 | 961 target_register_t addr, length; |
| 962 char *ptr = &packet[1]; | |
| 0 | 963 |
| 2 | 964 if (__hexToInt (&ptr, &addr) |
| 965 && *ptr++ == ',' | |
| 966 && __hexToInt (&ptr, &length)) | |
| 967 { | |
| 968 if (__mem2hex ((char *) addr, remcomOutBuffer, length, 1)) | |
| 969 break; | |
| 0 | 970 |
| 2 | 971 strcpy (remcomOutBuffer, "E03"); |
| 972 } | |
| 973 else | |
| 974 strcpy (remcomOutBuffer, "E01"); | |
| 975 break; | |
| 0 | 976 } |
| 977 | |
| 2 | 978 case 'X': |
| 979 /* XAA..AA,LLLL: Write LLLL escaped binary bytes at address AA.AA */ | |
| 980 is_binary = 1; | |
| 981 /* fall through */ | |
| 0 | 982 case 'M': /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */ |
| 983 /* Try to read '%x,%x:'. */ | |
| 984 { | |
| 2 | 985 target_register_t addr, length; |
| 986 char *ptr = &packet[1], buf[128]; | |
| 987 int i; | |
| 988 | |
| 989 if (__hexToInt (&ptr, &addr) | |
| 990 && *ptr++ == ',' | |
| 991 && __hexToInt (&ptr, &length) | |
| 992 && *ptr++ == ':') | |
| 993 { | |
| 994 if (is_binary) | |
| 995 { | |
| 996 while (length > 0) | |
| 997 { | |
| 998 for (i = 0; i < sizeof(buf) && i < length; i++) | |
| 999 if ((buf[i] = *ptr++) == 0x7d) | |
| 1000 buf[i] = 0x20 | (*ptr++ & 0xff); | |
| 1001 | |
| 1002 if (__write_mem_safe (buf, addr, i) != i) | |
| 1003 break; | |
| 0 | 1004 |
| 2 | 1005 length -= i; |
| 1006 addr += i; | |
| 1007 } | |
| 1008 if (length <= 0) | |
| 1009 strcpy (remcomOutBuffer, "OK"); | |
| 1010 else | |
| 1011 strcpy (remcomOutBuffer, "E03"); | |
| 1012 } | |
| 1013 else | |
| 1014 { | |
| 1015 if (__hex2mem (ptr, (char *) addr, length, 1) != NULL) | |
| 1016 strcpy (remcomOutBuffer, "OK"); | |
| 1017 else | |
| 1018 strcpy (remcomOutBuffer, "E03"); | |
| 1019 } | |
| 1020 } | |
| 1021 else | |
| 1022 strcpy (remcomOutBuffer, "E02"); | |
| 1023 break; | |
| 0 | 1024 } |
| 1025 | |
| 1026 case 'S': | |
| 2 | 1027 case 's': /* sAA..AA Step from address AA..AA (optional) */ |
| 0 | 1028 case 'C': |
| 2 | 1029 case 'c': /* cAA..AA Continue at address AA..AA (optional) */ |
| 0 | 1030 /* try to read optional parameter, pc unchanged if no parm */ |
| 1031 | |
| 1032 { | |
| 2 | 1033 char *ptr = &packet[1]; |
| 1034 target_register_t addr; | |
| 1035 target_register_t sigval = 0; | |
| 1036 | |
| 1037 if (packet[0] == 'C' || packet[0] == 'S') | |
| 1038 { | |
| 1039 __hexToInt (&ptr, &sigval); | |
| 1040 if (*ptr == ';') | |
| 1041 ptr++; | |
| 1042 } | |
| 0 | 1043 |
| 2 | 1044 if (__hexToInt (&ptr, &addr)) |
| 1045 set_pc (addr); | |
| 1046 | |
| 1047 /* Need to flush the instruction cache here, as we may have | |
| 1048 deposited a breakpoint, and the icache probably has no way of | |
| 1049 knowing that a data ref to some location may have changed | |
| 1050 something that is in the instruction cache. */ | |
| 1051 | |
| 1052 #ifdef __ECOS__ | |
| 1053 __data_cache (CACHE_FLUSH) ; | |
| 1054 #endif | |
| 1055 __instruction_cache (CACHE_FLUSH) ; | |
| 0 | 1056 |
| 2 | 1057 /* If we have a function to handle signals, call it. */ |
| 1058 if (sigval != 0 && __process_signal_vec != NULL) | |
| 1059 { | |
| 1060 /* If 0 is returned, we either ignored the signal or invoked a user | |
| 1061 handler. Otherwise, the user program should die. */ | |
| 1062 if (! __process_signal_vec (sigval)) | |
| 1063 sigval = 0; | |
| 1064 } | |
| 0 | 1065 |
| 2 | 1066 if (sigval != 0) |
| 1067 { | |
| 1068 sigval = SIGKILL; /* Always nuke the program */ | |
| 1069 __kill_program (sigval); | |
| 1070 return 0; | |
| 1071 } | |
| 0 | 1072 |
| 2 | 1073 /* Set machine state to force a single step. */ |
| 1074 if (packet[0] == 's' || packet[0] == 'S') | |
| 1075 { | |
| 1076 lock_thread_scheduler (0); /* 0 == single-step */ | |
| 1077 #ifdef __ECOS__ | |
| 1078 // PR 19845 workaround: | |
| 1079 // Make sure the single-step magic affects the correct registers. | |
| 1080 _registers = ®isters[0]; | |
| 1081 #endif | |
| 1082 __single_step (); | |
| 1083 } | |
| 1084 else | |
| 1085 { | |
| 1086 lock_thread_scheduler (1); /* 1 == continue */ | |
| 1087 } | |
| 0 | 1088 |
|
28
18ee5a9c102e
Merge from eCos master repository on 1999-08-09-17:04:48-BST
jlarmour
parents:
2
diff
changeset
|
1089 #ifdef __ECOS__ |
|
18ee5a9c102e
Merge from eCos master repository on 1999-08-09-17:04:48-BST
jlarmour
parents:
2
diff
changeset
|
1090 /* Need to flush the data and instruction cache here, as we may have |
|
18ee5a9c102e
Merge from eCos master repository on 1999-08-09-17:04:48-BST
jlarmour
parents:
2
diff
changeset
|
1091 deposited a breakpoint in __single_step. */ |
|
18ee5a9c102e
Merge from eCos master repository on 1999-08-09-17:04:48-BST
jlarmour
parents:
2
diff
changeset
|
1092 |
|
18ee5a9c102e
Merge from eCos master repository on 1999-08-09-17:04:48-BST
jlarmour
parents:
2
diff
changeset
|
1093 __data_cache (CACHE_FLUSH) ; |
|
18ee5a9c102e
Merge from eCos master repository on 1999-08-09-17:04:48-BST
jlarmour
parents:
2
diff
changeset
|
1094 __instruction_cache (CACHE_FLUSH) ; |
|
18ee5a9c102e
Merge from eCos master repository on 1999-08-09-17:04:48-BST
jlarmour
parents:
2
diff
changeset
|
1095 #endif |
|
18ee5a9c102e
Merge from eCos master repository on 1999-08-09-17:04:48-BST
jlarmour
parents:
2
diff
changeset
|
1096 |
| 2 | 1097 return -1; |
| 0 | 1098 } |
| 1099 | |
| 1100 /* kill the program */ | |
| 1101 case 'k' : | |
| 1102 __process_exit_vec (); | |
| 1103 return 1; | |
| 2 | 1104 |
| 1105 case 'r': /* Reset */ | |
| 0 | 1106 __reset (); |
| 1107 break; | |
| 2 | 1108 |
| 0 | 1109 case 'H': |
| 1110 STUB_PKT_CHANGETHREAD (packet+1, remcomOutBuffer, 300) ; | |
| 1111 break ; | |
| 1112 case 'T' : | |
| 1113 STUB_PKT_THREAD_ALIVE (packet+1, remcomOutBuffer, 300) ; | |
| 1114 break ; | |
| 2 | 1115 case 'B': |
| 1116 /* breakpoint */ | |
| 0 | 1117 { |
| 2 | 1118 target_register_t addr; |
| 1119 char mode; | |
| 1120 char *ptr = &packet[1]; | |
| 1121 if (__hexToInt (&ptr, &addr) && *(ptr++) == ',') | |
| 1122 { | |
| 1123 mode = *(ptr++); | |
| 1124 if (mode == 'C') | |
| 1125 __remove_breakpoint (addr); | |
| 1126 else | |
| 1127 __set_breakpoint (addr); | |
| 1128 strcpy (remcomOutBuffer, "OK"); | |
| 1129 } | |
| 1130 else | |
| 1131 { | |
| 1132 strcpy (remcomOutBuffer, "E01"); | |
| 1133 } | |
| 1134 break; | |
| 1135 } | |
| 0 | 1136 |
| 2 | 1137 case 'b': /* bBB... Set baud rate to BB... */ |
| 1138 { | |
| 1139 target_register_t baudrate; | |
| 0 | 1140 |
| 2 | 1141 char *ptr = &packet[1]; |
| 1142 if (!__hexToInt (&ptr, &baudrate)) | |
| 1143 { | |
| 1144 strcpy (remcomOutBuffer, "B01"); | |
| 1145 break; | |
| 1146 } | |
| 1147 | |
| 1148 __putpacket ("OK"); /* Ack before changing speed */ | |
| 1149 __set_baud_rate (baudrate); | |
| 1150 break; | |
| 0 | 1151 } |
| 2 | 1152 default: |
| 1153 __process_target_packet (packet, remcomOutBuffer, 300); | |
| 1154 break; | |
| 0 | 1155 } |
| 1156 | |
| 1157 /* reply to the request */ | |
| 2 | 1158 __putpacket (remcomOutBuffer); |
| 0 | 1159 return 0; |
| 1160 } | |
| 1161 | |
| 1162 static void | |
| 1163 send_t_packet (int sigval) | |
| 1164 { | |
| 1165 __build_t_packet (sigval, remcomOutBuffer); | |
| 2 | 1166 __putpacket (remcomOutBuffer); |
| 0 | 1167 } |
| 1168 | |
| 1169 /* | |
| 1170 * This function does all command procesing for interfacing to gdb. | |
| 1171 */ | |
| 1172 | |
| 1173 static int | |
| 1174 process_exception (int sigval) | |
| 1175 { | |
| 1176 int status; | |
| 1177 | |
| 1178 /* Nasty. */ | |
| 1179 if (ungot_char < 0) | |
| 1180 send_t_packet (sigval); | |
| 1181 | |
| 1182 do { | |
| 1183 getpacket (remcomInBuffer); | |
| 2 | 1184 status = __process_packet (remcomInBuffer); |
| 0 | 1185 } while (status == 0); |
| 1186 | |
| 1187 if (status < 0) | |
| 1188 return 0; | |
| 1189 else | |
| 1190 return 1; | |
| 1191 } | |
| 1192 | |
| 1193 void | |
| 1194 __send_exit_status (int status) | |
| 1195 { | |
| 1196 remcomOutBuffer[0] = 'W'; | |
| 1197 remcomOutBuffer[1] = hexchars[(status >> 4) & 0xf]; | |
| 1198 remcomOutBuffer[2] = hexchars[status & 0xf]; | |
| 1199 remcomOutBuffer[3] = 0; | |
| 2 | 1200 __putpacket (remcomOutBuffer); |
| 0 | 1201 } |
| 1202 | |
| 2 | 1203 /* Read up to MAXLEN bytes from the remote GDB client, and store in DEST |
| 1204 (which is a pointer in the user program). BLOCK indicates what mode | |
| 1205 is being used; if it is set, we will wait for MAXLEN bytes to be | |
| 1206 entered. Otherwise, the function will return immediately with whatever | |
| 1207 bytes are waiting to be read. | |
| 1208 | |
| 1209 The value returned is the number of bytes read. A -1 indicates that an | |
| 1210 error of some sort occurred. */ | |
| 1211 | |
| 0 | 1212 int |
| 2 | 1213 __get_gdb_input (target_register_t dest, int maxlen, int block) |
| 0 | 1214 { |
| 1215 char buf[4]; | |
| 1216 int len, i; | |
| 2 | 1217 char d; |
| 0 | 1218 |
| 1219 buf[0] = 'I'; | |
| 1220 buf[1] = '0'; | |
| 1221 buf[2] = block ? '0' : '1'; | |
| 1222 buf[3] = 0; | |
| 2 | 1223 __putpacket (buf); |
| 0 | 1224 getpacket (remcomInBuffer); |
| 1225 if (remcomInBuffer[0] != 'I') | |
| 1226 return -1; | |
| 1227 len = stubhex (remcomInBuffer[1]) * 16 + stubhex (remcomInBuffer[2]); | |
| 1228 for (i = 0; i < len; i++) | |
| 1229 { | |
| 2 | 1230 d = stubhex (remcomInBuffer[3 + i * 2]) * 16; |
| 1231 d |= stubhex (remcomInBuffer[3 + i * 2 + 1]); | |
| 1232 __write_mem_safe (&d, dest + i, 1); | |
| 0 | 1233 } |
| 2 | 1234 /* Write the trailing \0. */ |
| 1235 d = '\0'; | |
| 1236 __write_mem_safe (&d, dest + i, 1); | |
| 0 | 1237 return len; |
| 1238 } | |
| 1239 | |
| 1240 void | |
| 1241 __output_hex_value (target_register_t i) | |
| 1242 { | |
| 1243 char buf[32], *ptr=buf+31; | |
| 1244 unsigned int x; | |
| 1245 | |
| 1246 *ptr = 0; | |
| 2 | 1247 for (x = 0; x < (sizeof (i) * 2); x++) |
| 0 | 1248 { |
| 1249 *(--ptr) = hexchars[i & 15]; | |
| 1250 i = i >> 4; | |
| 1251 } | |
| 1252 while (*ptr) | |
| 1253 { | |
| 1254 putDebugChar (*(ptr++)); | |
| 1255 } | |
| 1256 } | |
| 1257 | |
| 2 | 1258 /* Write the C-style string pointed to by STR to the GDB comm port. */ |
| 1259 void | |
| 1260 __putDebugStr (char *str) | |
| 1261 { | |
| 1262 while (*str) | |
| 1263 { | |
| 1264 putDebugChar (*str); | |
| 1265 str++; | |
| 1266 } | |
| 1267 } | |
| 1268 | |
| 1269 /* Send STRING_LEN bytes of STR to GDB, using 'O' packets. | |
| 1270 STR is assumed to be in the program being debugged. */ | |
| 1271 | |
| 0 | 1272 int |
| 2 | 1273 __output_gdb_string (target_register_t str, int string_len) |
| 0 | 1274 { |
| 2 | 1275 /* We will arbitrarily limit output packets to less than 400 bytes. */ |
| 1276 static char buf[400]; | |
| 0 | 1277 int x; |
| 1278 int len; | |
| 1279 | |
| 1280 if (string_len == 0) | |
| 2 | 1281 { |
| 1282 /* We can't do strlen on a user pointer. */ | |
| 1283 return -1; | |
| 1284 } | |
| 0 | 1285 |
| 2 | 1286 len = string_len; |
| 1287 while (len > 0) | |
| 0 | 1288 { |
| 2 | 1289 int packetlen = ((len < 175) ? len : 175); |
| 1290 buf[0] = 'O'; | |
| 1291 for (x = 0; x < packetlen; x++) | |
| 1292 { | |
| 1293 char c; | |
| 1294 | |
| 1295 __read_mem_safe (&c, str + x, 1); | |
| 1296 buf[x*2+1] = hexchars[(c >> 4) & 0xf]; | |
| 1297 buf[x*2+2] = hexchars[c % 16]; | |
| 1298 } | |
| 1299 str += x; | |
| 1300 len -= x; | |
| 1301 buf[x*2+1] = 0; | |
| 1302 __putpacket (buf); | |
| 0 | 1303 } |
| 1304 return string_len; | |
| 1305 } | |
| 1306 | |
| 1307 static void | |
| 1308 do_nothing (void) | |
| 1309 { | |
| 1310 /* mmmm */ | |
| 1311 } | |
| 1312 | |
| 1313 static int | |
| 1314 syscall_do_nothing (int junk) | |
| 1315 { | |
| 1316 return 0; | |
| 1317 } | |
| 1318 | |
| 1319 /* Start the stub running. */ | |
| 1320 void | |
| 2 | 1321 __switch_to_stub (void) |
| 0 | 1322 { |
| 1323 __process_exception_vec = process_exception; | |
| 1324 } | |
| 1325 | |
| 2 | 1326 #if ! defined(BOARD_SPECIFIC_STUB_INIT) |
| 1327 void | |
| 1328 initialize_stub (void) | |
| 1329 { | |
| 1330 set_debug_traps (); | |
| 1331 /* FIXME: This function should be renamed to specifically init the | |
| 1332 hardware required by debug operations. If initHardware is implemented at | |
| 1333 all, it should be called before main (). | |
| 1334 */ | |
| 1335 initHardware () ; | |
| 1336 /* This acks any stale packets , NOT an effective solution */ | |
| 1337 putDebugChar ('+'); | |
| 1338 } | |
| 1339 #endif | |
| 1340 | |
| 0 | 1341 void |
| 1342 ungetDebugChar (int c) | |
| 1343 { | |
| 1344 ungot_char = c; | |
| 1345 } | |
| 1346 | |
| 2 | 1347 void |
| 1348 __kill_program (int sigval) | |
| 0 | 1349 { |
| 1350 remcomOutBuffer[0] = 'X'; | |
| 1351 remcomOutBuffer[1] = hexchars[(sigval >> 4) & 15]; | |
| 1352 remcomOutBuffer[2] = hexchars[sigval & 15]; | |
| 1353 remcomOutBuffer[3] = 0; | |
| 2 | 1354 __putpacket (remcomOutBuffer); |
| 1355 } | |
| 1356 | |
| 1357 #define MAX_ARG_COUNT 20 | |
| 1358 #define MAX_ARGDATA 128 | |
| 1359 | |
| 1360 static char *program_argv [MAX_ARG_COUNT]; | |
| 1361 static int program_argc; | |
| 1362 static int last_program_arg; | |
| 1363 static char program_argstr [MAX_ARGDATA], *argptr; | |
| 1364 static int args_initted = 0; | |
| 1365 | |
| 1366 void | |
| 1367 __free_program_args (void) | |
| 1368 { | |
| 1369 last_program_arg = -1; | |
| 1370 program_argc = 0; | |
| 1371 program_argv [0] = NULL; | |
| 1372 argptr = program_argstr; | |
| 1373 args_initted = 1; | |
| 1374 } | |
| 1375 | |
| 1376 static char * | |
| 1377 __add_program_arg (int argc, uint32 len) | |
| 1378 { | |
| 1379 char *res; | |
| 1380 | |
| 1381 if (! args_initted) | |
| 1382 { | |
| 1383 __free_program_args (); | |
| 1384 } | |
| 1385 | |
| 1386 if ((argc >= (MAX_ARG_COUNT - 1)) | |
| 1387 || ((argptr - program_argstr + len) > MAX_ARGDATA)) | |
| 1388 { | |
| 1389 return NULL; | |
| 1390 } | |
| 1391 | |
| 1392 if (argc != last_program_arg) | |
| 1393 { | |
| 1394 if (argc >= program_argc) | |
| 1395 { | |
| 1396 program_argc = argc + 1; | |
| 1397 program_argv [program_argc] = NULL; | |
| 1398 } | |
| 1399 program_argv [argc] = argptr; | |
| 1400 last_program_arg = argc; | |
| 1401 } | |
| 1402 | |
| 1403 res = argptr; | |
| 1404 argptr += len; | |
| 1405 | |
| 1406 return res; | |
| 1407 } | |
| 1408 | |
| 1409 void | |
| 1410 __set_program_args (int argc, char **argv) | |
| 1411 { | |
| 1412 int x; | |
| 1413 | |
| 1414 __free_program_args (); | |
| 1415 if (argc) | |
| 1416 { | |
| 1417 for (x = 0; x < argc; x++) | |
| 1418 { | |
| 1419 uint32 len = strlen (argv[x])+1; | |
| 1420 char *s = __add_program_arg (x, len); | |
| 1421 | |
| 1422 if (s == NULL) | |
| 1423 return; | |
| 1424 | |
| 1425 memcpy (s, argv[x], len); | |
| 1426 } | |
| 1427 } | |
| 1428 } | |
| 1429 | |
| 1430 char ** | |
| 1431 __get_program_args (target_register_t argcPtr) | |
| 1432 { | |
| 1433 if (!args_initted) | |
| 1434 { | |
| 1435 __free_program_args (); | |
| 1436 } | |
| 1437 __write_mem_safe ((char *) &program_argc, argcPtr, sizeof (program_argc)); | |
| 1438 return program_argv; | |
| 0 | 1439 } |
| 1440 | |
| 1441 /* Table used by the crc32 function to calcuate the checksum. */ | |
| 1442 static uint32 crc32_table[256]; | |
| 1443 static int tableInit = 0; | |
| 1444 | |
| 1445 /* | |
| 1446 Calculate a CRC-32 using LEN bytes of PTR. CRC is the initial CRC | |
| 1447 value. | |
| 1448 PTR is assumed to be a pointer in the user program. */ | |
| 1449 | |
| 1450 static uint32 | |
| 2 | 1451 crc32 (ptr, len, crc) |
| 1452 unsigned char *ptr; | |
| 1453 int len; | |
| 1454 uint32 crc; | |
| 0 | 1455 { |
| 1456 if (! tableInit) | |
| 1457 { | |
| 1458 /* Initialize the CRC table and the decoding table. */ | |
| 1459 uint32 i, j; | |
| 1460 uint32 c; | |
| 1461 | |
| 1462 tableInit = 1; | |
| 1463 for (i = 0; i < 256; i++) | |
| 2 | 1464 { |
| 1465 for (c = i << 24, j = 8; j > 0; --j) | |
| 1466 c = c & 0x80000000 ? (c << 1) ^ 0x04c11db7 : (c << 1); | |
| 1467 crc32_table[i] = c; | |
| 1468 } | |
| 0 | 1469 } |
| 1470 | |
| 1471 __mem_fault = 0; | |
| 1472 while (len--) | |
| 1473 { | |
| 1474 unsigned char ch; | |
| 1475 | |
| 1476 __read_mem_safe (&ch, (target_register_t) ptr, 1); | |
| 1477 if (__mem_fault) | |
| 2 | 1478 { |
| 1479 break; | |
| 1480 } | |
| 0 | 1481 crc = (crc << 8) ^ crc32_table[((crc >> 24) ^ ch) & 255]; |
| 1482 ptr++; | |
| 1483 } | |
| 1484 return crc; | |
| 1485 } | |
| 1486 | |
| 1487 /* Handle the 'q' request */ | |
| 1488 | |
| 1489 static void | |
| 1490 process_query (char *pkt) | |
| 1491 { | |
| 1492 remcomOutBuffer[0] = '\0'; | |
| 2 | 1493 #ifdef __ECOS__ |
| 0 | 1494 if ('C' == pkt[0] && |
| 1495 'R' == pkt[1] && | |
| 1496 'C' == pkt[2] && | |
| 1497 ':' == pkt[3]) | |
| 2 | 1498 #else // __ECOS__ |
| 1499 if (strncmp (pkt, "CRC:", 4) == 0) | |
| 1500 #endif // __ECOS__ | |
| 0 | 1501 { |
| 1502 target_register_t startmem; | |
| 1503 target_register_t length; | |
| 1504 uint32 our_crc; | |
| 1505 | |
| 1506 pkt += 4; | |
| 1507 if (__hexToInt (&pkt, &startmem) | |
| 2 | 1508 && *(pkt++) == ',' |
| 1509 && __hexToInt (&pkt, &length)) | |
| 1510 { | |
| 1511 our_crc = crc32 ((unsigned char *) startmem, length, 0xffffffff); | |
| 1512 if (__mem_fault) | |
| 1513 { | |
| 1514 strcpy (remcomOutBuffer, "E01"); | |
| 1515 } | |
| 1516 else | |
| 1517 { | |
| 1518 int numb = __intToHex (remcomOutBuffer + 1, our_crc, 32); | |
| 1519 remcomOutBuffer[0] = 'C'; | |
| 1520 remcomOutBuffer[numb + 1] = 0; | |
| 1521 } | |
| 1522 } | |
| 0 | 1523 return; |
| 1524 } | |
| 1525 else | |
| 1526 { | |
| 1527 char ch ; | |
| 1528 char * subpkt ; | |
| 1529 ch = *pkt ; | |
| 1530 subpkt = pkt + 1 ; | |
| 1531 switch (ch) | |
| 2 | 1532 { |
| 1533 case 'L' : /* threadlistquery */ | |
| 1534 STUB_PKT_GETTHREADLIST (subpkt, remcomOutBuffer, 300); | |
| 1535 break ; | |
| 1536 case 'P' : /* Thread or process information request */ | |
| 1537 STUB_PKT_GETTHREADINFO (subpkt, remcomOutBuffer, 300); | |
| 1538 break ; | |
| 1539 case 'C' : /* current thread query */ | |
| 1540 STUB_PKT_CURRTHREAD(subpkt, remcomOutBuffer, sizeof(remcomOutBuffer)); | |
| 1541 break; | |
| 1542 default: | |
| 1543 __process_target_query (pkt, remcomOutBuffer, 300); | |
| 1544 break ; | |
| 1545 } | |
| 0 | 1546 } |
| 1547 } | |
| 1548 | |
| 1549 /* Handle the 'Q' request */ | |
| 1550 | |
| 1551 static void | |
| 1552 process_set (char *pkt) | |
| 1553 { | |
| 1554 char ch ; | |
| 1555 ch = *pkt ; | |
| 1556 | |
| 1557 switch (ch) | |
| 1558 { | |
| 1559 case 'p' : /* Set current process or thread */ | |
| 1560 /* reserve the packet id even if support is not present */ | |
| 1561 /* Dont strip the 'p' off the header, there are several variations of | |
| 2 | 1562 this packet */ |
| 0 | 1563 STUB_PKT_CHANGETHREAD (pkt, remcomOutBuffer, 300) ; |
| 1564 break ; | |
| 1565 default: | |
| 1566 __process_target_set (pkt, remcomOutBuffer, 300); | |
| 1567 break ; | |
| 1568 } | |
| 1569 } | |
| 1570 #endif // CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS |
