|
0
|
1 /**************************************************************************** |
|
|
2 |
|
|
3 THIS SOFTWARE IS NOT COPYRIGHTED |
|
|
4 |
|
|
5 HP offers the following for use in the public domain. HP makes no |
|
|
6 warranty with regard to the software or it's performance and the |
|
|
7 user accepts the software "AS IS" with all faults. |
|
|
8 |
|
|
9 HP DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED, WITH REGARD |
|
|
10 TO THIS SOFTWARE INCLUDING BUT NOT LIMITED TO THE WARRANTIES |
|
|
11 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. |
|
|
12 |
|
|
13 ****************************************************************************/ |
|
|
14 |
|
|
15 /**************************************************************************** |
|
|
16 * Header: remcom.c,v 1.34 91/03/09 12:29:49 glenne Exp $ |
|
|
17 * |
|
|
18 * Module name: remcom.c $ |
|
|
19 * Revision: 1.34 $ |
|
|
20 * Date: 91/03/09 12:29:49 $ |
|
|
21 * Contributor: Lake Stevens Instrument Division$ |
|
|
22 * |
|
|
23 * Description: low level support for gdb debugger. $ |
|
|
24 * |
|
|
25 * Considerations: only works on target hardware $ |
|
|
26 * |
|
|
27 * Written by: Glenn Engel $ |
|
|
28 * ModuleState: Experimental $ |
|
|
29 * |
|
|
30 * NOTES: See Below $ |
|
|
31 * |
|
|
32 * Modified for SPARC by Stu Grossman, Cygnus Support. |
|
|
33 * Modified for generic CygMON stub support by Bob Manson, Cygnus Solutions. |
|
|
34 * |
|
|
35 * To enable debugger support, two things need to happen. One, a |
|
|
36 * call to set_debug_traps() is necessary in order to allow any breakpoints |
|
|
37 * or error conditions to be properly intercepted and reported to gdb. |
|
|
38 * Two, a breakpoint needs to be generated to begin communication. This |
|
|
39 * is most easily accomplished by a call to breakpoint(). Breakpoint() |
|
|
40 * simulates a breakpoint by executing a trap #1. |
|
|
41 * |
|
|
42 ************* |
|
|
43 * |
|
|
44 * The following gdb commands are supported: |
|
|
45 * |
|
|
46 * command function Return value |
|
|
47 * |
|
|
48 * g return the value of the CPU registers hex data or ENN |
|
|
49 * G set the value of the CPU registers OK or ENN |
|
|
50 * |
|
|
51 * mAA..AA,LLLL Read LLLL bytes at address AA..AA hex data or ENN |
|
|
52 * MAA..AA,LLLL: Write LLLL bytes at address AA.AA OK or ENN |
|
|
53 * |
|
|
54 * c Resume at current address SNN ( signal NN) |
|
|
55 * cAA..AA Continue at address AA..AA SNN |
|
|
56 * |
|
|
57 * s Step one instruction SNN |
|
|
58 * sAA..AA Step one instruction from AA..AA SNN |
|
|
59 * |
|
|
60 * k kill |
|
|
61 * |
|
|
62 * ? What was the last sigval ? SNN (signal NN) |
|
|
63 * |
|
|
64 * bBB..BB Set baud rate to BB..BB OK or BNN, then sets |
|
|
65 * baud rate |
|
|
66 * |
|
|
67 * All commands and responses are sent with a packet which includes a |
|
|
68 * checksum. A packet consists of |
|
|
69 * |
|
|
70 * $<packet info>#<checksum>. |
|
|
71 * |
|
|
72 * where |
|
|
73 * <packet info> :: <characters representing the command or response> |
|
|
74 * <checksum> :: < two hex digits computed as modulo 256 sum of <packetinfo>> |
|
|
75 * |
|
|
76 * When a packet is received, it is first acknowledged with either '+' or '-'. |
|
|
77 * '+' indicates a successful transfer. '-' indicates a failed transfer. |
|
|
78 * |
|
|
79 * Example: |
|
|
80 * |
|
|
81 * Host: Reply: |
|
|
82 * $m0,10#2a +$00010203040506070809101112131415#42 |
|
|
83 * |
|
|
84 ****************************************************************************/ |
|
|
85 |
|
|
86 #include <pkgconf/hal.h> |
|
|
87 |
|
|
88 #ifdef CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS |
|
|
89 |
|
|
90 #include <cyg/hal/hal_stub.h> |
|
|
91 |
|
|
92 #define SIGHUP 1 /* hangup */ |
|
|
93 #define SIGINT 2 /* interrupt */ |
|
|
94 #define SIGQUIT 3 /* quit */ |
|
|
95 #define SIGILL 4 /* illegal instruction (not reset when caught) */ |
|
|
96 #define SIGTRAP 5 /* trace trap (not reset when caught) */ |
|
|
97 #define SIGIOT 6 /* IOT instruction */ |
|
|
98 #define SIGABRT 6 /* used by abort, replace SIGIOT in the future */ |
|
|
99 #define SIGEMT 7 /* EMT instruction */ |
|
|
100 #define SIGFPE 8 /* floating point exception */ |
|
|
101 #define SIGKILL 9 /* kill (cannot be caught or ignored) */ |
|
|
102 #define SIGBUS 10 /* bus error */ |
|
|
103 #define SIGSEGV 11 /* segmentation violation */ |
|
|
104 #define SIGSYS 12 /* bad argument to system call */ |
|
|
105 #define SIGPIPE 13 /* write on a pipe with no one to read it */ |
|
|
106 #define SIGALRM 14 /* alarm clock */ |
|
|
107 #define SIGTERM 15 /* software termination signal from kill */ |
|
|
108 |
|
|
109 #include <cyg/hal/hal_arch.h> // HAL header |
|
|
110 |
|
|
111 #ifdef CYGDBG_HAL_DEBUG_GDB_THREAD_SUPPORT |
|
|
112 #define DEBUG_THREADS 1 // FIXME: put in header file? |
|
|
113 #else |
|
|
114 #define DEBUG_THREADS 0 // FIXME: put in header file? |
|
|
115 #endif |
|
|
116 |
|
|
117 #define uint32 cyg_uint32 |
|
|
118 #include "thread-pkts.h" |
|
|
119 |
|
|
120 /************************************************************************/ |
|
|
121 /* BUFMAX defines the maximum number of characters in inbound/outbound buffers*/ |
|
|
122 /* at least NUMREGBYTES*2 are needed for register packets */ |
|
|
123 #define BUFMAX 2048 |
|
|
124 |
|
|
125 static int process_exception (int sigval); |
|
|
126 static void do_nothing (void); /* and do it gracefully */ |
|
|
127 static int syscall_do_nothing (int); |
|
|
128 static void kill_program (int sigval); |
|
|
129 static void process_query (char *pkt); |
|
|
130 static void process_set (char *pkt); |
|
|
131 |
|
|
132 volatile __PFI __process_exception_vec = process_exception; |
|
|
133 volatile __PFV __process_exit_vec = do_nothing; |
|
|
134 volatile __PFI __process_syscall_vec = syscall_do_nothing; |
|
|
135 volatile __PFI __process_signal_vec = NULL; |
|
|
136 volatile __PFI __interruptible_control = NULL; |
|
|
137 |
|
|
138 static const char hexchars[] = "0123456789abcdef"; |
|
|
139 |
|
|
140 extern target_register_t registers[]; /* The current saved registers */ |
|
|
141 extern target_register_t * _registers ; |
|
|
142 extern HAL_SavedRegisters *_hal_registers; |
|
|
143 |
|
|
144 int __process_target_query(char * pkt, char * out, int maxOut) |
|
|
145 { return 0 ; } |
|
|
146 int __process_target_set(char * pkt, char * out, int maxout) |
|
|
147 { return 0 ; } |
|
|
148 int __process_target_packet(char * pkt, char * out, int maxout) |
|
|
149 { return 0 ; } |
|
|
150 |
|
|
151 |
|
|
152 /* Return the value corresponding to register REG of the active thread. */ |
|
|
153 static target_register_t thread_get_register (regnames_t reg) |
|
|
154 { |
|
|
155 return _registers[reg]; |
|
|
156 } |
|
|
157 |
|
|
158 |
|
|
159 /* Store VALUE in the register corresponding to WHICH of the active thread. */ |
|
|
160 static void thread_put_register (regnames_t which, target_register_t value) |
|
|
161 { |
|
|
162 _registers[which] = value; |
|
|
163 } |
|
|
164 |
|
|
165 |
|
|
166 char |
|
|
167 __tohex (int c) |
|
|
168 { |
|
|
169 return hexchars [c & 15]; |
|
|
170 } |
|
|
171 |
|
|
172 target_register_t *__our_registers; |
|
|
173 |
|
|
174 #ifndef NUMREGS_GDB |
|
|
175 #define NUMREGS_GDB NUMREGS |
|
|
176 #endif |
|
|
177 |
|
|
178 static char *strcpy( char *s, const char *t) |
|
|
179 { |
|
|
180 char *r = s; |
|
|
181 |
|
|
182 while( *t ) *s++ = *t++; |
|
|
183 |
|
|
184 return r; |
|
|
185 } |
|
|
186 |
|
|
187 static int strlen( const char *s ) |
|
|
188 { |
|
|
189 int r = 0; |
|
|
190 while( *s++ ) r++; |
|
|
191 return r; |
|
|
192 } |
|
|
193 |
|
|
194 // Use this function to disable serial interrupts whenever reply |
|
|
195 // characters are expected from GDB. The reason we want to control |
|
|
196 // whether the target can be interrupted or not is simply that GDB on |
|
|
197 // the host will be sending acknowledge characters/commands while the |
|
|
198 // stub is running - if serial interrupts were still active, the |
|
|
199 // characters would never reach the (polling) getDebugChar. |
|
|
200 static void |
|
|
201 interruptible (int state) |
|
|
202 { |
|
|
203 static int current_state = 0; |
|
|
204 |
|
|
205 if (__interruptible_control) { |
|
|
206 if (state) { |
|
|
207 current_state--; |
|
|
208 if (0 >= current_state) { |
|
|
209 current_state = 0; |
|
|
210 __interruptible_control (1); |
|
|
211 } |
|
|
212 } else { |
|
|
213 current_state++; |
|
|
214 if (1 == current_state) |
|
|
215 __interruptible_control (0); |
|
|
216 } |
|
|
217 } |
|
|
218 } |
|
|
219 |
|
|
220 |
|
|
221 /* One pushback character. */ |
|
|
222 int ungot_char = -1; |
|
|
223 |
|
|
224 static int |
|
|
225 readDebugChar (void) |
|
|
226 { |
|
|
227 if (ungot_char > 0) |
|
|
228 { |
|
|
229 int result = ungot_char; |
|
|
230 ungot_char = -1; |
|
|
231 return result; |
|
|
232 } |
|
|
233 else |
|
|
234 return getDebugChar (); |
|
|
235 } |
|
|
236 |
|
|
237 struct gdb_packet |
|
|
238 { |
|
|
239 /* The checksum calculated so far. */ |
|
|
240 int checksum; |
|
|
241 /* The checksum we've received from the remote side. */ |
|
|
242 int xmitcsum; |
|
|
243 /* Contents of the accumulated packet. */ |
|
|
244 char *contents; |
|
|
245 /* Number of characters received. */ |
|
|
246 int length; |
|
|
247 /* |
|
|
248 * state is the current state: |
|
|
249 * 0 = looking for start of packet |
|
|
250 * 1 = got start of packet, looking for # terminator |
|
|
251 * 2 = looking for first byte of checksum |
|
|
252 * 3 = looking for second byte of checksum (indicating end of packet) |
|
|
253 */ |
|
|
254 char state; |
|
|
255 }; |
|
|
256 |
|
|
257 /* Convert ch from a hex digit to an int. */ |
|
|
258 |
|
|
259 int |
|
|
260 stubhex(unsigned char ch) |
|
|
261 { |
|
|
262 if (ch >= 'a' && ch <= 'f') |
|
|
263 return ch-'a'+10; |
|
|
264 if (ch >= '0' && ch <= '9') |
|
|
265 return ch-'0'; |
|
|
266 if (ch >= 'A' && ch <= 'F') |
|
|
267 return ch-'A'+10; |
|
|
268 return -1; |
|
|
269 } |
|
|
270 |
|
|
271 static void |
|
|
272 getpacket(char *buffer) |
|
|
273 { |
|
|
274 struct gdb_packet packet; |
|
|
275 |
|
|
276 packet.state = 0; |
|
|
277 packet.contents = buffer; |
|
|
278 while (__add_char_to_packet (readDebugChar () & 0x7f, &packet) != 1) |
|
|
279 { |
|
|
280 /* Empty */ |
|
|
281 } |
|
|
282 } |
|
|
283 |
|
|
284 int |
|
|
285 __add_char_to_packet (int ch, struct gdb_packet *packet) |
|
|
286 { |
|
|
287 if (packet->state == 0) |
|
|
288 { |
|
|
289 if (ch == '$') |
|
|
290 { |
|
|
291 packet->state = 1; |
|
|
292 packet->length = 0; |
|
|
293 packet->checksum = 0; |
|
|
294 packet->xmitcsum = -1; |
|
|
295 } |
|
|
296 return 0; |
|
|
297 } |
|
|
298 |
|
|
299 if (packet->state == 1) |
|
|
300 { |
|
|
301 if (ch == '#') |
|
|
302 { |
|
|
303 packet->contents[packet->length] = 0; |
|
|
304 packet->state = 2; |
|
|
305 } |
|
|
306 else |
|
|
307 { |
|
|
308 if (packet->length == BUFMAX) { |
|
|
309 packet->state = 0; |
|
|
310 return -1; |
|
|
311 } |
|
|
312 packet->checksum += ch; |
|
|
313 packet->contents[packet->length++] = ch; |
|
|
314 } |
|
|
315 return 0; |
|
|
316 } |
|
|
317 |
|
|
318 if (packet->state == 2) |
|
|
319 { |
|
|
320 packet->xmitcsum = stubhex (ch) << 4; |
|
|
321 packet->state = 3; |
|
|
322 return 0; |
|
|
323 } |
|
|
324 |
|
|
325 if (packet->state == 3) |
|
|
326 { |
|
|
327 packet->xmitcsum |= stubhex(ch); |
|
|
328 if ((packet->checksum & 255) != packet->xmitcsum) |
|
|
329 { |
|
|
330 putDebugChar ('-'); /* failed checksum */ |
|
|
331 packet->state = 0; |
|
|
332 return -1; |
|
|
333 } |
|
|
334 else |
|
|
335 { |
|
|
336 putDebugChar('+'); /* successful transfer */ |
|
|
337 /* if a sequence char is present, reply the sequence ID */ |
|
|
338 if (packet->contents[2] == ':') |
|
|
339 { |
|
|
340 int count = packet->length; |
|
|
341 int i; |
|
|
342 putDebugChar (packet->contents[0]); |
|
|
343 putDebugChar (packet->contents[1]); |
|
|
344 /* remove sequence chars from buffer */ |
|
|
345 for (i=3; i <= count; i++) |
|
|
346 packet->contents[i-3] = packet->contents[i]; |
|
|
347 } |
|
|
348 return 1; |
|
|
349 } |
|
|
350 } |
|
|
351 /* We should never get here. */ |
|
|
352 packet->state = 0; |
|
|
353 return -1; |
|
|
354 } |
|
|
355 |
|
|
356 /* send the packet in buffer. */ |
|
|
357 |
|
|
358 static void |
|
|
359 putpacket(unsigned char *buffer) |
|
|
360 { |
|
|
361 unsigned char checksum; |
|
|
362 int count; |
|
|
363 unsigned char ch; |
|
|
364 |
|
|
365 interruptible (0); |
|
|
366 |
|
|
367 /* $<packet info>#<checksum>. */ |
|
|
368 do |
|
|
369 { |
|
|
370 putDebugChar ('$'); |
|
|
371 checksum = 0; |
|
|
372 count = 0; |
|
|
373 |
|
|
374 while ((ch = buffer[count])) |
|
|
375 { |
|
|
376 putDebugChar (ch); |
|
|
377 checksum += ch; |
|
|
378 count += 1; |
|
|
379 } |
|
|
380 |
|
|
381 putDebugChar ('#'); |
|
|
382 putDebugChar (hexchars[(checksum >> 4) & 0xf]); |
|
|
383 putDebugChar (hexchars[checksum & 0xf]); |
|
|
384 |
|
|
385 } |
|
|
386 while ((readDebugChar () & 0x7f) != '+'); |
|
|
387 |
|
|
388 interruptible (1); |
|
|
389 } |
|
|
390 |
|
|
391 static char remcomInBuffer[BUFMAX]; |
|
|
392 static char remcomOutBuffer[BUFMAX]; |
|
|
393 |
|
|
394 /* Indicate to caller of mem2hex or hex2mem that there has been an |
|
|
395 error. */ |
|
|
396 volatile int __mem_fault = 0; |
|
|
397 |
|
|
398 static int |
|
|
399 __copy_mem_safe (unsigned char *dst, unsigned char *src, int count) |
|
|
400 { |
|
|
401 int res; |
|
|
402 |
|
|
403 __set_mem_fault_trap (1); |
|
|
404 while (count--) |
|
|
405 *(dst++) = *(src++); |
|
|
406 res = __mem_fault; |
|
|
407 __set_mem_fault_trap (0); |
|
|
408 return res ? 1 : 0; |
|
|
409 } |
|
|
410 |
|
|
411 int |
|
|
412 __read_mem_safe (unsigned char *dst, target_register_t src, int count) |
|
|
413 { |
|
|
414 return __copy_mem_safe (dst, (unsigned char*) src, count); |
|
|
415 } |
|
|
416 |
|
|
417 int |
|
|
418 __write_mem_safe (unsigned char *src, target_register_t dst, int count) |
|
|
419 { |
|
|
420 return __copy_mem_safe ((unsigned char*) dst, src, count); |
|
|
421 } |
|
|
422 |
|
|
423 /* Convert the memory pointed to by mem into hex, placing result in buf. |
|
|
424 * Return a pointer to the last char put in buf (null), in case of mem fault, |
|
|
425 * return 0. |
|
|
426 * If MAY_FAULT is non-zero, then we will handle memory faults by returning |
|
|
427 * a 0, else treat a fault like any other fault in the stub. |
|
|
428 */ |
|
|
429 |
|
|
430 unsigned char * |
|
|
431 __mem2hex(mem, buf, count, may_fault) |
|
|
432 unsigned char *mem; |
|
|
433 unsigned char *buf; |
|
|
434 int count; |
|
|
435 int may_fault; |
|
|
436 { |
|
|
437 unsigned char ch; |
|
|
438 |
|
|
439 __set_mem_fault_trap(may_fault); |
|
|
440 |
|
|
441 while (count-- > 0) |
|
|
442 { |
|
|
443 ch = *mem++; |
|
|
444 if (__mem_fault) |
|
|
445 return 0; |
|
|
446 *buf++ = hexchars[(ch >> 4) & 0xf]; |
|
|
447 *buf++ = hexchars[ch & 0xf]; |
|
|
448 } |
|
|
449 |
|
|
450 *buf = 0; |
|
|
451 |
|
|
452 __set_mem_fault_trap(0); |
|
|
453 |
|
|
454 return buf; |
|
|
455 } |
|
|
456 |
|
|
457 /* convert the hex array pointed to by buf into binary to be placed in mem |
|
|
458 * return a pointer to the character AFTER the last byte written */ |
|
|
459 |
|
|
460 static char * |
|
|
461 hex2mem(unsigned char *buf, unsigned char *mem, int count, int may_fault) |
|
|
462 { |
|
|
463 int i; |
|
|
464 unsigned char ch; |
|
|
465 |
|
|
466 __set_mem_fault_trap (may_fault); |
|
|
467 |
|
|
468 for (i=0; i<count; i++) |
|
|
469 { |
|
|
470 ch = stubhex(*buf++) << 4; |
|
|
471 ch |= stubhex(*buf++); |
|
|
472 *mem++ = ch; |
|
|
473 if (__mem_fault) |
|
|
474 return 0; |
|
|
475 } |
|
|
476 |
|
|
477 __set_mem_fault_trap(0); |
|
|
478 |
|
|
479 return mem; |
|
|
480 } |
|
|
481 |
|
|
482 /* |
|
|
483 * While we find nice hex chars, build an int. |
|
|
484 * Return number of chars processed. |
|
|
485 */ |
|
|
486 |
|
|
487 static unsigned int |
|
|
488 __hexToInt(char **ptr, target_register_t *intValue) |
|
|
489 { |
|
|
490 int numChars = 0; |
|
|
491 int hexValue; |
|
|
492 |
|
|
493 *intValue = 0; |
|
|
494 |
|
|
495 while (**ptr) |
|
|
496 { |
|
|
497 hexValue = stubhex(**ptr); |
|
|
498 if (hexValue < 0) |
|
|
499 break; |
|
|
500 |
|
|
501 *intValue = (*intValue << 4) | hexValue; |
|
|
502 numChars ++; |
|
|
503 |
|
|
504 (*ptr)++; |
|
|
505 } |
|
|
506 |
|
|
507 return (numChars); |
|
|
508 } |
|
|
509 |
|
|
510 /* |
|
|
511 * Complement of __hexToInt: take an int of size "numBits", |
|
|
512 * convert it to a hex string. Return length of (unterminated) output. |
|
|
513 */ |
|
|
514 |
|
|
515 unsigned int |
|
|
516 __intToHex (char *ptr, target_register_t intValue, int numBits) |
|
|
517 { |
|
|
518 int numChars = 0; |
|
|
519 |
|
|
520 if (intValue == 0) |
|
|
521 { |
|
|
522 *(ptr++) = '0'; |
|
|
523 *(ptr++) = '0'; |
|
|
524 return 2; |
|
|
525 } |
|
|
526 |
|
|
527 numBits = (numBits + 7) / 8; |
|
|
528 while (numBits) |
|
|
529 { |
|
|
530 int v = (intValue >> ((numBits - 1) * 8)); |
|
|
531 if (v || (numBits == 1)) |
|
|
532 { |
|
|
533 v = v & 255; |
|
|
534 *(ptr++) = __tohex ((v / 16) & 15); |
|
|
535 *(ptr++) = __tohex (v & 15); |
|
|
536 numChars += 2; |
|
|
537 } |
|
|
538 numBits--; |
|
|
539 } |
|
|
540 |
|
|
541 return (numChars); |
|
|
542 } |
|
|
543 |
|
|
544 void |
|
|
545 __handle_exception (void) |
|
|
546 { |
|
|
547 void breakinst(void); |
|
|
548 int sigval; |
|
|
549 |
|
|
550 interruptible (0); |
|
|
551 |
|
|
552 // Expand the HAL_SavedRegisters structure into the GDB register |
|
|
553 // array format. |
|
|
554 HAL_GET_GDB_REGISTERS (®isters[0], _hal_registers); |
|
|
555 _registers = ®isters[0]; |
|
|
556 |
|
|
557 /* reply to host that an exception has occurred */ |
|
|
558 sigval = __computeSignal (__get_trap_number ()); |
|
|
559 |
|
|
560 if (__is_breakpoint_function ()) |
|
|
561 __skipinst (); |
|
|
562 |
|
|
563 #if 0 //def SIGSYSCALL |
|
|
564 if(sigval == SIGSYSCALL) |
|
|
565 { |
|
|
566 int val; |
|
|
567 /* Do the skipinst FIRST. */ |
|
|
568 __skipinst (); |
|
|
569 val = __process_syscall_vec (__get_syscall_num ()); |
|
|
570 if (val == 0) |
|
|
571 return; |
|
|
572 else if (val < 0) |
|
|
573 sigval = -val; |
|
|
574 } |
|
|
575 |
|
|
576 #endif |
|
|
577 |
|
|
578 while (__process_exception_vec (sigval)); |
|
|
579 |
|
|
580 |
|
|
581 // Compact register array again. |
|
|
582 HAL_SET_GDB_REGISTERS (_hal_registers, ®isters[0]); |
|
|
583 |
|
|
584 interruptible (1); |
|
|
585 } |
|
|
586 |
|
|
587 static int |
|
|
588 process_packet (char *packet) |
|
|
589 { |
|
|
590 //diag_printf("pkt %s\n",packet); |
|
|
591 remcomOutBuffer[0] = 0; |
|
|
592 |
|
|
593 switch (packet[0]) |
|
|
594 { |
|
|
595 case '?': |
|
|
596 { |
|
|
597 int sigval = __computeSignal (__get_trap_number ()); |
|
|
598 remcomOutBuffer[0] = 'S'; |
|
|
599 remcomOutBuffer[1] = hexchars[(sigval >> 4) & 0xf]; |
|
|
600 remcomOutBuffer[2] = hexchars[sigval & 0xf]; |
|
|
601 remcomOutBuffer[3] = 0; |
|
|
602 break; |
|
|
603 } |
|
|
604 |
|
|
605 case 'd': |
|
|
606 /* toggle debug flag */ |
|
|
607 break; |
|
|
608 |
|
|
609 case 'q': |
|
|
610 /* general query packet */ |
|
|
611 process_query (&packet[1]); |
|
|
612 break; |
|
|
613 |
|
|
614 case 'Q': |
|
|
615 /* general set packet */ |
|
|
616 process_set (&packet[1]); |
|
|
617 break; |
|
|
618 |
|
|
619 case 'g': /* return the value of the CPU registers */ |
|
|
620 { |
|
|
621 char *ptr = remcomOutBuffer; |
|
|
622 int x; |
|
|
623 |
|
|
624 for (x = 0; x < NUMREGS_GDB; x++) |
|
|
625 { |
|
|
626 /* We need to compensate for the value offset within the |
|
|
627 register. */ |
|
|
628 target_register_t addr = thread_get_register (x); |
|
|
629 char *vptr = ((char *)&addr) + sizeof(addr) - REGSIZE(x); |
|
|
630 |
|
|
631 ptr = __mem2hex(vptr, ptr, REGSIZE(x), 0); |
|
|
632 } |
|
|
633 break; |
|
|
634 } |
|
|
635 |
|
|
636 case 'P': |
|
|
637 case 'G': /* set the value of the CPU registers - return OK */ |
|
|
638 { |
|
|
639 int x; |
|
|
640 int sr = 0, er = NUMREGS_GDB; |
|
|
641 char *ptr = &packet[1]; |
|
|
642 |
|
|
643 if (packet[0] == 'P') |
|
|
644 { |
|
|
645 target_register_t regno; |
|
|
646 |
|
|
647 if (__hexToInt (&ptr, ®no) |
|
|
648 && (*ptr++ == '=')) |
|
|
649 { |
|
|
650 sr = regno; |
|
|
651 er = regno + 1; |
|
|
652 } |
|
|
653 else |
|
|
654 { |
|
|
655 strcpy (remcomOutBuffer, "P01"); |
|
|
656 break; |
|
|
657 } |
|
|
658 } |
|
|
659 |
|
|
660 for (x = sr; x < er; x++) |
|
|
661 { |
|
|
662 target_register_t value = 0; |
|
|
663 |
|
|
664 char *vptr = ((char *)&value) + sizeof(value) - REGSIZE(x); |
|
|
665 hex2mem(ptr, vptr, REGSIZE (x), 0); |
|
|
666 thread_put_register (x, value); |
|
|
667 ptr += REGSIZE(x) * 2; |
|
|
668 } |
|
|
669 |
|
|
670 strcpy (remcomOutBuffer, "OK"); |
|
|
671 break; |
|
|
672 } |
|
|
673 |
|
|
674 case 'm': /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */ |
|
|
675 /* Try to read %x,%x. */ |
|
|
676 { |
|
|
677 target_register_t addr, length; |
|
|
678 char *ptr = &packet[1]; |
|
|
679 |
|
|
680 if (__hexToInt(&ptr, &addr) |
|
|
681 && *ptr++ == ',' |
|
|
682 && __hexToInt(&ptr, &length)) |
|
|
683 { |
|
|
684 if (__mem2hex ((char *)addr, remcomOutBuffer, length, 1)) |
|
|
685 break; |
|
|
686 |
|
|
687 strcpy (remcomOutBuffer, "E03"); |
|
|
688 } |
|
|
689 else |
|
|
690 strcpy(remcomOutBuffer,"E01"); |
|
|
691 break; |
|
|
692 } |
|
|
693 |
|
|
694 case 'M': /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */ |
|
|
695 /* Try to read '%x,%x:'. */ |
|
|
696 { |
|
|
697 target_register_t addr, length; |
|
|
698 char *ptr = &packet[1]; |
|
|
699 |
|
|
700 if (__hexToInt(&ptr, &addr) |
|
|
701 && *ptr++ == ',' |
|
|
702 && __hexToInt(&ptr, &length) |
|
|
703 && *ptr++ == ':') |
|
|
704 { |
|
|
705 if (hex2mem(ptr, (char *)addr, length, 1)) |
|
|
706 strcpy(remcomOutBuffer, "OK"); |
|
|
707 else |
|
|
708 strcpy(remcomOutBuffer, "E03"); |
|
|
709 } |
|
|
710 else |
|
|
711 strcpy(remcomOutBuffer, "E02"); |
|
|
712 break; |
|
|
713 } |
|
|
714 |
|
|
715 case 'S': |
|
|
716 case 's': /* sAA..AA Step from address AA..AA(optional) */ |
|
|
717 case 'C': |
|
|
718 case 'c': /* cAA..AA Continue at address AA..AA(optional) */ |
|
|
719 /* try to read optional parameter, pc unchanged if no parm */ |
|
|
720 |
|
|
721 { |
|
|
722 char *ptr = &packet[1]; |
|
|
723 target_register_t addr; |
|
|
724 target_register_t foo = 99999; |
|
|
725 target_register_t sigval; |
|
|
726 |
|
|
727 //diag_printf("stepping\n"); |
|
|
728 sigval = foo; |
|
|
729 if (packet[0] == 'C' || packet[0] == 'S') |
|
|
730 { |
|
|
731 __hexToInt (&ptr, &sigval); |
|
|
732 if (*ptr == ';') |
|
|
733 ptr++; |
|
|
734 } |
|
|
735 |
|
|
736 if (__hexToInt(&ptr, &addr)) |
|
|
737 set_pc (addr); |
|
|
738 |
|
|
739 /* Need to flush the instruction cache here, as we may have deposited a |
|
|
740 breakpoint, and the icache probably has no way of knowing that a data ref to |
|
|
741 some location may have changed something that is in the instruction cache. |
|
|
742 */ |
|
|
743 |
|
|
744 flush_i_cache (); |
|
|
745 |
|
|
746 if (sigval != foo) |
|
|
747 { |
|
|
748 if (__process_signal_vec != NULL) |
|
|
749 { |
|
|
750 if (! __process_signal_vec (sigval)) |
|
|
751 return -1; |
|
|
752 } |
|
|
753 sigval = SIGKILL; /* Always nuke the program */ |
|
|
754 kill_program (sigval); |
|
|
755 return 0; |
|
|
756 } |
|
|
757 |
|
|
758 /* Set machine state to force a single step. */ |
|
|
759 if (packet[0] == 's' || packet[0] == 'S') |
|
|
760 single_step (); |
|
|
761 |
|
|
762 return -1; |
|
|
763 } |
|
|
764 |
|
|
765 /* kill the program */ |
|
|
766 case 'k' : |
|
|
767 __process_exit_vec (); |
|
|
768 return 1; |
|
|
769 #if 0 |
|
|
770 case 't': /* Test feature */ |
|
|
771 __asm__ (" std %f30,[%sp]"); |
|
|
772 break; |
|
|
773 #endif |
|
|
774 case 'r': /* Reset */ |
|
|
775 __reset (); |
|
|
776 break; |
|
|
777 case 'H': |
|
|
778 STUB_PKT_CHANGETHREAD (packet+1, remcomOutBuffer, 300) ; |
|
|
779 break ; |
|
|
780 case 'T' : |
|
|
781 STUB_PKT_THREAD_ALIVE (packet+1, remcomOutBuffer, 300) ; |
|
|
782 break ; |
|
|
783 |
|
|
784 case 'b': /* bBB... Set baud rate to BB... */ |
|
|
785 { |
|
|
786 target_register_t baudrate; |
|
|
787 |
|
|
788 char *ptr = &packet[1]; |
|
|
789 if (!__hexToInt(&ptr, &baudrate)) |
|
|
790 { |
|
|
791 strcpy(remcomOutBuffer,"B01"); |
|
|
792 break; |
|
|
793 } |
|
|
794 |
|
|
795 putpacket ("OK"); /* Ack before changing speed */ |
|
|
796 __set_baud_rate (baudrate); |
|
|
797 break; |
|
|
798 } |
|
|
799 } |
|
|
800 |
|
|
801 /* reply to the request */ |
|
|
802 putpacket (remcomOutBuffer); |
|
|
803 return 0; |
|
|
804 } |
|
|
805 |
|
|
806 static void |
|
|
807 send_t_packet (int sigval) |
|
|
808 { |
|
|
809 __build_t_packet (sigval, remcomOutBuffer); |
|
|
810 putpacket(remcomOutBuffer); |
|
|
811 } |
|
|
812 |
|
|
813 /* |
|
|
814 * This function does all command procesing for interfacing to gdb. |
|
|
815 */ |
|
|
816 |
|
|
817 static int |
|
|
818 process_exception (int sigval) |
|
|
819 { |
|
|
820 int status; |
|
|
821 |
|
|
822 /* Nasty. */ |
|
|
823 if (ungot_char < 0) |
|
|
824 send_t_packet (sigval); |
|
|
825 |
|
|
826 /* Undo effect of previous single step. */ |
|
|
827 clear_single_step (); |
|
|
828 |
|
|
829 do { |
|
|
830 getpacket (remcomInBuffer); |
|
|
831 status = process_packet (remcomInBuffer); |
|
|
832 } while (status == 0); |
|
|
833 |
|
|
834 |
|
|
835 /* Install breakpoints that may have been set to perform single stepping. */ |
|
|
836 install_breakpoints (); |
|
|
837 |
|
|
838 if (status < 0) |
|
|
839 return 0; |
|
|
840 else |
|
|
841 return 1; |
|
|
842 } |
|
|
843 |
|
|
844 void |
|
|
845 __send_exit_status (int status) |
|
|
846 { |
|
|
847 remcomOutBuffer[0] = 'W'; |
|
|
848 remcomOutBuffer[1] = hexchars[(status >> 4) & 0xf]; |
|
|
849 remcomOutBuffer[2] = hexchars[status & 0xf]; |
|
|
850 remcomOutBuffer[3] = 0; |
|
|
851 putpacket (remcomOutBuffer); |
|
|
852 } |
|
|
853 |
|
|
854 int |
|
|
855 __get_gdb_input (char *dest, int maxlen, int block) |
|
|
856 { |
|
|
857 char buf[4]; |
|
|
858 int len, i; |
|
|
859 |
|
|
860 buf[0] = 'I'; |
|
|
861 buf[1] = '0'; |
|
|
862 buf[2] = block ? '0' : '1'; |
|
|
863 buf[3] = 0; |
|
|
864 putpacket (buf); |
|
|
865 getpacket (remcomInBuffer); |
|
|
866 if (remcomInBuffer[0] != 'I') |
|
|
867 return -1; |
|
|
868 len = stubhex (remcomInBuffer[1]) * 16 + stubhex (remcomInBuffer[2]); |
|
|
869 for (i = 0; i < len; i++) |
|
|
870 { |
|
|
871 dest[i] = stubhex (remcomInBuffer[3 + i * 2]) * 16; |
|
|
872 dest[i] |= stubhex (remcomInBuffer[3 + i * 2 + 1]); |
|
|
873 } |
|
|
874 dest[i] = '\0'; |
|
|
875 return len; |
|
|
876 } |
|
|
877 |
|
|
878 void |
|
|
879 __output_hex_value (target_register_t i) |
|
|
880 { |
|
|
881 char buf[32], *ptr=buf+31; |
|
|
882 unsigned int x; |
|
|
883 |
|
|
884 *ptr = 0; |
|
|
885 for (x = 0; x < (sizeof(i) * 2); x++) |
|
|
886 { |
|
|
887 *(--ptr) = hexchars[i & 15]; |
|
|
888 i = i >> 4; |
|
|
889 } |
|
|
890 while (*ptr) |
|
|
891 { |
|
|
892 putDebugChar (*(ptr++)); |
|
|
893 } |
|
|
894 } |
|
|
895 |
|
|
896 int |
|
|
897 __output_gdb_string(const char *str, int string_len) |
|
|
898 { |
|
|
899 static char buf[1024]; |
|
|
900 int x; |
|
|
901 int len; |
|
|
902 |
|
|
903 if (string_len == 0) |
|
|
904 string_len = strlen (str); |
|
|
905 |
|
|
906 len = string_len * 2 + 1; |
|
|
907 |
|
|
908 buf[0] = 'O'; |
|
|
909 for (x = 0; x < string_len; x++) |
|
|
910 { |
|
|
911 char c = str[x]; |
|
|
912 buf[x*2+1] = hexchars[(c >> 4) & 0xf]; |
|
|
913 buf[x*2+2] = hexchars[c % 16]; |
|
|
914 } |
|
|
915 buf[x*2+1] = 0; |
|
|
916 putpacket (buf); |
|
|
917 return string_len; |
|
|
918 } |
|
|
919 |
|
|
920 static void |
|
|
921 do_nothing (void) |
|
|
922 { |
|
|
923 /* mmmm */ |
|
|
924 } |
|
|
925 |
|
|
926 static int |
|
|
927 syscall_do_nothing (int junk) |
|
|
928 { |
|
|
929 return 0; |
|
|
930 } |
|
|
931 |
|
|
932 /* Start the stub running. */ |
|
|
933 void |
|
|
934 __switch_to_stub () |
|
|
935 { |
|
|
936 __process_exception_vec = process_exception; |
|
|
937 } |
|
|
938 |
|
|
939 void |
|
|
940 ungetDebugChar (int c) |
|
|
941 { |
|
|
942 ungot_char = c; |
|
|
943 } |
|
|
944 |
|
|
945 static void |
|
|
946 kill_program (int sigval) |
|
|
947 { |
|
|
948 remcomOutBuffer[0] = 'X'; |
|
|
949 remcomOutBuffer[1] = hexchars[(sigval >> 4) & 15]; |
|
|
950 remcomOutBuffer[2] = hexchars[sigval & 15]; |
|
|
951 remcomOutBuffer[3] = 0; |
|
|
952 putpacket (remcomOutBuffer); |
|
|
953 } |
|
|
954 |
|
|
955 /* Table used by the crc32 function to calcuate the checksum. */ |
|
|
956 static uint32 crc32_table[256]; |
|
|
957 static int tableInit = 0; |
|
|
958 |
|
|
959 /* |
|
|
960 Calculate a CRC-32 using LEN bytes of PTR. CRC is the initial CRC |
|
|
961 value. |
|
|
962 PTR is assumed to be a pointer in the user program. */ |
|
|
963 |
|
|
964 static uint32 |
|
|
965 crc32 (unsigned char *ptr, int len, uint32 crc) |
|
|
966 { |
|
|
967 if (! tableInit) |
|
|
968 { |
|
|
969 /* Initialize the CRC table and the decoding table. */ |
|
|
970 uint32 i, j; |
|
|
971 uint32 c; |
|
|
972 |
|
|
973 tableInit = 1; |
|
|
974 for (i = 0; i < 256; i++) |
|
|
975 { |
|
|
976 for (c = i << 24, j = 8; j > 0; --j) |
|
|
977 c = c & 0x80000000 ? (c << 1) ^ 0x04c11db7 : (c << 1); |
|
|
978 crc32_table[i] = c; |
|
|
979 } |
|
|
980 } |
|
|
981 |
|
|
982 __mem_fault = 0; |
|
|
983 while (len--) |
|
|
984 { |
|
|
985 unsigned char ch; |
|
|
986 |
|
|
987 __read_mem_safe (&ch, (target_register_t) ptr, 1); |
|
|
988 if (__mem_fault) |
|
|
989 { |
|
|
990 break; |
|
|
991 } |
|
|
992 crc = (crc << 8) ^ crc32_table[((crc >> 24) ^ ch) & 255]; |
|
|
993 ptr++; |
|
|
994 } |
|
|
995 return crc; |
|
|
996 } |
|
|
997 |
|
|
998 /* Handle the 'q' request */ |
|
|
999 |
|
|
1000 static void |
|
|
1001 process_query (char *pkt) |
|
|
1002 { |
|
|
1003 remcomOutBuffer[0] = '\0'; |
|
|
1004 if ('C' == pkt[0] && |
|
|
1005 'R' == pkt[1] && |
|
|
1006 'C' == pkt[2] && |
|
|
1007 ':' == pkt[3]) |
|
|
1008 { |
|
|
1009 target_register_t startmem; |
|
|
1010 target_register_t length; |
|
|
1011 uint32 our_crc; |
|
|
1012 |
|
|
1013 pkt += 4; |
|
|
1014 if (__hexToInt (&pkt, &startmem) |
|
|
1015 && *(pkt++) == ',' |
|
|
1016 && __hexToInt (&pkt, &length)) |
|
|
1017 { |
|
|
1018 our_crc = crc32 ((unsigned char *) startmem, length, 0xffffffff); |
|
|
1019 if (__mem_fault) |
|
|
1020 { |
|
|
1021 strcpy (remcomOutBuffer, "E01"); |
|
|
1022 } |
|
|
1023 else |
|
|
1024 { |
|
|
1025 int numb = __intToHex (remcomOutBuffer + 1, our_crc, 32); |
|
|
1026 remcomOutBuffer[0] = 'C'; |
|
|
1027 remcomOutBuffer[numb + 1] = 0; |
|
|
1028 } |
|
|
1029 } |
|
|
1030 return; |
|
|
1031 } |
|
|
1032 else |
|
|
1033 { |
|
|
1034 char ch ; |
|
|
1035 char * subpkt ; |
|
|
1036 ch = *pkt ; |
|
|
1037 subpkt = pkt + 1 ; |
|
|
1038 switch (ch) |
|
|
1039 { |
|
|
1040 case 'L' : /* threadlistquery */ |
|
|
1041 STUB_PKT_GETTHREADLIST (subpkt, remcomOutBuffer, 300); |
|
|
1042 break ; |
|
|
1043 case 'P' : /* Thread or process information request */ |
|
|
1044 STUB_PKT_GETTHREADINFO (subpkt, remcomOutBuffer, 300); |
|
|
1045 break ; |
|
|
1046 default: |
|
|
1047 __process_target_query (pkt, remcomOutBuffer, 300); |
|
|
1048 break ; |
|
|
1049 } |
|
|
1050 } |
|
|
1051 } |
|
|
1052 |
|
|
1053 /* Handle the 'Q' request */ |
|
|
1054 |
|
|
1055 static void |
|
|
1056 process_set (char *pkt) |
|
|
1057 { |
|
|
1058 char ch ; |
|
|
1059 ch = *pkt ; |
|
|
1060 |
|
|
1061 switch (ch) |
|
|
1062 { |
|
|
1063 case 'p' : /* Set current process or thread */ |
|
|
1064 /* reserve the packet id even if support is not present */ |
|
|
1065 /* Dont strip the 'p' off the header, there are several variations of |
|
|
1066 this packet */ |
|
|
1067 STUB_PKT_CHANGETHREAD (pkt, remcomOutBuffer, 300) ; |
|
|
1068 break ; |
|
|
1069 default: |
|
|
1070 __process_target_set (pkt, remcomOutBuffer, 300); |
|
|
1071 break ; |
|
|
1072 } |
|
|
1073 } |
|
|
1074 |
|
|
1075 #endif // CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS |