|
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 |
|
2
|
1089 return -1; |
|
0
|
1090 } |
|
|
1091 |
|
|
1092 /* kill the program */ |
|
|
1093 case 'k' : |
|
|
1094 __process_exit_vec (); |
|
|
1095 return 1; |
|
2
|
1096 |
|
|
1097 case 'r': /* Reset */ |
|
0
|
1098 __reset (); |
|
|
1099 break; |
|
2
|
1100 |
|
0
|
1101 case 'H': |
|
|
1102 STUB_PKT_CHANGETHREAD (packet+1, remcomOutBuffer, 300) ; |
|
|
1103 break ; |
|
|
1104 case 'T' : |
|
|
1105 STUB_PKT_THREAD_ALIVE (packet+1, remcomOutBuffer, 300) ; |
|
|
1106 break ; |
|
2
|
1107 case 'B': |
|
|
1108 /* breakpoint */ |
|
0
|
1109 { |
|
2
|
1110 target_register_t addr; |
|
|
1111 char mode; |
|
|
1112 char *ptr = &packet[1]; |
|
|
1113 if (__hexToInt (&ptr, &addr) && *(ptr++) == ',') |
|
|
1114 { |
|
|
1115 mode = *(ptr++); |
|
|
1116 if (mode == 'C') |
|
|
1117 __remove_breakpoint (addr); |
|
|
1118 else |
|
|
1119 __set_breakpoint (addr); |
|
|
1120 strcpy (remcomOutBuffer, "OK"); |
|
|
1121 } |
|
|
1122 else |
|
|
1123 { |
|
|
1124 strcpy (remcomOutBuffer, "E01"); |
|
|
1125 } |
|
|
1126 break; |
|
|
1127 } |
|
0
|
1128 |
|
2
|
1129 case 'b': /* bBB... Set baud rate to BB... */ |
|
|
1130 { |
|
|
1131 target_register_t baudrate; |
|
0
|
1132 |
|
2
|
1133 char *ptr = &packet[1]; |
|
|
1134 if (!__hexToInt (&ptr, &baudrate)) |
|
|
1135 { |
|
|
1136 strcpy (remcomOutBuffer, "B01"); |
|
|
1137 break; |
|
|
1138 } |
|
|
1139 |
|
|
1140 __putpacket ("OK"); /* Ack before changing speed */ |
|
|
1141 __set_baud_rate (baudrate); |
|
|
1142 break; |
|
0
|
1143 } |
|
2
|
1144 default: |
|
|
1145 __process_target_packet (packet, remcomOutBuffer, 300); |
|
|
1146 break; |
|
0
|
1147 } |
|
|
1148 |
|
|
1149 /* reply to the request */ |
|
2
|
1150 __putpacket (remcomOutBuffer); |
|
0
|
1151 return 0; |
|
|
1152 } |
|
|
1153 |
|
|
1154 static void |
|
|
1155 send_t_packet (int sigval) |
|
|
1156 { |
|
|
1157 __build_t_packet (sigval, remcomOutBuffer); |
|
2
|
1158 __putpacket (remcomOutBuffer); |
|
0
|
1159 } |
|
|
1160 |
|
|
1161 /* |
|
|
1162 * This function does all command procesing for interfacing to gdb. |
|
|
1163 */ |
|
|
1164 |
|
|
1165 static int |
|
|
1166 process_exception (int sigval) |
|
|
1167 { |
|
|
1168 int status; |
|
|
1169 |
|
|
1170 /* Nasty. */ |
|
|
1171 if (ungot_char < 0) |
|
|
1172 send_t_packet (sigval); |
|
|
1173 |
|
|
1174 do { |
|
|
1175 getpacket (remcomInBuffer); |
|
2
|
1176 status = __process_packet (remcomInBuffer); |
|
0
|
1177 } while (status == 0); |
|
|
1178 |
|
|
1179 if (status < 0) |
|
|
1180 return 0; |
|
|
1181 else |
|
|
1182 return 1; |
|
|
1183 } |
|
|
1184 |
|
|
1185 void |
|
|
1186 __send_exit_status (int status) |
|
|
1187 { |
|
|
1188 remcomOutBuffer[0] = 'W'; |
|
|
1189 remcomOutBuffer[1] = hexchars[(status >> 4) & 0xf]; |
|
|
1190 remcomOutBuffer[2] = hexchars[status & 0xf]; |
|
|
1191 remcomOutBuffer[3] = 0; |
|
2
|
1192 __putpacket (remcomOutBuffer); |
|
0
|
1193 } |
|
|
1194 |
|
2
|
1195 /* Read up to MAXLEN bytes from the remote GDB client, and store in DEST |
|
|
1196 (which is a pointer in the user program). BLOCK indicates what mode |
|
|
1197 is being used; if it is set, we will wait for MAXLEN bytes to be |
|
|
1198 entered. Otherwise, the function will return immediately with whatever |
|
|
1199 bytes are waiting to be read. |
|
|
1200 |
|
|
1201 The value returned is the number of bytes read. A -1 indicates that an |
|
|
1202 error of some sort occurred. */ |
|
|
1203 |
|
0
|
1204 int |
|
2
|
1205 __get_gdb_input (target_register_t dest, int maxlen, int block) |
|
0
|
1206 { |
|
|
1207 char buf[4]; |
|
|
1208 int len, i; |
|
2
|
1209 char d; |
|
0
|
1210 |
|
|
1211 buf[0] = 'I'; |
|
|
1212 buf[1] = '0'; |
|
|
1213 buf[2] = block ? '0' : '1'; |
|
|
1214 buf[3] = 0; |
|
2
|
1215 __putpacket (buf); |
|
0
|
1216 getpacket (remcomInBuffer); |
|
|
1217 if (remcomInBuffer[0] != 'I') |
|
|
1218 return -1; |
|
|
1219 len = stubhex (remcomInBuffer[1]) * 16 + stubhex (remcomInBuffer[2]); |
|
|
1220 for (i = 0; i < len; i++) |
|
|
1221 { |
|
2
|
1222 d = stubhex (remcomInBuffer[3 + i * 2]) * 16; |
|
|
1223 d |= stubhex (remcomInBuffer[3 + i * 2 + 1]); |
|
|
1224 __write_mem_safe (&d, dest + i, 1); |
|
0
|
1225 } |
|
2
|
1226 /* Write the trailing \0. */ |
|
|
1227 d = '\0'; |
|
|
1228 __write_mem_safe (&d, dest + i, 1); |
|
0
|
1229 return len; |
|
|
1230 } |
|
|
1231 |
|
|
1232 void |
|
|
1233 __output_hex_value (target_register_t i) |
|
|
1234 { |
|
|
1235 char buf[32], *ptr=buf+31; |
|
|
1236 unsigned int x; |
|
|
1237 |
|
|
1238 *ptr = 0; |
|
2
|
1239 for (x = 0; x < (sizeof (i) * 2); x++) |
|
0
|
1240 { |
|
|
1241 *(--ptr) = hexchars[i & 15]; |
|
|
1242 i = i >> 4; |
|
|
1243 } |
|
|
1244 while (*ptr) |
|
|
1245 { |
|
|
1246 putDebugChar (*(ptr++)); |
|
|
1247 } |
|
|
1248 } |
|
|
1249 |
|
2
|
1250 /* Write the C-style string pointed to by STR to the GDB comm port. */ |
|
|
1251 void |
|
|
1252 __putDebugStr (char *str) |
|
|
1253 { |
|
|
1254 while (*str) |
|
|
1255 { |
|
|
1256 putDebugChar (*str); |
|
|
1257 str++; |
|
|
1258 } |
|
|
1259 } |
|
|
1260 |
|
|
1261 /* Send STRING_LEN bytes of STR to GDB, using 'O' packets. |
|
|
1262 STR is assumed to be in the program being debugged. */ |
|
|
1263 |
|
0
|
1264 int |
|
2
|
1265 __output_gdb_string (target_register_t str, int string_len) |
|
0
|
1266 { |
|
2
|
1267 /* We will arbitrarily limit output packets to less than 400 bytes. */ |
|
|
1268 static char buf[400]; |
|
0
|
1269 int x; |
|
|
1270 int len; |
|
|
1271 |
|
|
1272 if (string_len == 0) |
|
2
|
1273 { |
|
|
1274 /* We can't do strlen on a user pointer. */ |
|
|
1275 return -1; |
|
|
1276 } |
|
0
|
1277 |
|
2
|
1278 len = string_len; |
|
|
1279 while (len > 0) |
|
0
|
1280 { |
|
2
|
1281 int packetlen = ((len < 175) ? len : 175); |
|
|
1282 buf[0] = 'O'; |
|
|
1283 for (x = 0; x < packetlen; x++) |
|
|
1284 { |
|
|
1285 char c; |
|
|
1286 |
|
|
1287 __read_mem_safe (&c, str + x, 1); |
|
|
1288 buf[x*2+1] = hexchars[(c >> 4) & 0xf]; |
|
|
1289 buf[x*2+2] = hexchars[c % 16]; |
|
|
1290 } |
|
|
1291 str += x; |
|
|
1292 len -= x; |
|
|
1293 buf[x*2+1] = 0; |
|
|
1294 __putpacket (buf); |
|
0
|
1295 } |
|
|
1296 return string_len; |
|
|
1297 } |
|
|
1298 |
|
|
1299 static void |
|
|
1300 do_nothing (void) |
|
|
1301 { |
|
|
1302 /* mmmm */ |
|
|
1303 } |
|
|
1304 |
|
|
1305 static int |
|
|
1306 syscall_do_nothing (int junk) |
|
|
1307 { |
|
|
1308 return 0; |
|
|
1309 } |
|
|
1310 |
|
|
1311 /* Start the stub running. */ |
|
|
1312 void |
|
2
|
1313 __switch_to_stub (void) |
|
0
|
1314 { |
|
|
1315 __process_exception_vec = process_exception; |
|
|
1316 } |
|
|
1317 |
|
2
|
1318 #if ! defined(BOARD_SPECIFIC_STUB_INIT) |
|
|
1319 void |
|
|
1320 initialize_stub (void) |
|
|
1321 { |
|
|
1322 set_debug_traps (); |
|
|
1323 /* FIXME: This function should be renamed to specifically init the |
|
|
1324 hardware required by debug operations. If initHardware is implemented at |
|
|
1325 all, it should be called before main (). |
|
|
1326 */ |
|
|
1327 initHardware () ; |
|
|
1328 /* This acks any stale packets , NOT an effective solution */ |
|
|
1329 putDebugChar ('+'); |
|
|
1330 } |
|
|
1331 #endif |
|
|
1332 |
|
0
|
1333 void |
|
|
1334 ungetDebugChar (int c) |
|
|
1335 { |
|
|
1336 ungot_char = c; |
|
|
1337 } |
|
|
1338 |
|
2
|
1339 void |
|
|
1340 __kill_program (int sigval) |
|
0
|
1341 { |
|
|
1342 remcomOutBuffer[0] = 'X'; |
|
|
1343 remcomOutBuffer[1] = hexchars[(sigval >> 4) & 15]; |
|
|
1344 remcomOutBuffer[2] = hexchars[sigval & 15]; |
|
|
1345 remcomOutBuffer[3] = 0; |
|
2
|
1346 __putpacket (remcomOutBuffer); |
|
|
1347 } |
|
|
1348 |
|
|
1349 #define MAX_ARG_COUNT 20 |
|
|
1350 #define MAX_ARGDATA 128 |
|
|
1351 |
|
|
1352 static char *program_argv [MAX_ARG_COUNT]; |
|
|
1353 static int program_argc; |
|
|
1354 static int last_program_arg; |
|
|
1355 static char program_argstr [MAX_ARGDATA], *argptr; |
|
|
1356 static int args_initted = 0; |
|
|
1357 |
|
|
1358 void |
|
|
1359 __free_program_args (void) |
|
|
1360 { |
|
|
1361 last_program_arg = -1; |
|
|
1362 program_argc = 0; |
|
|
1363 program_argv [0] = NULL; |
|
|
1364 argptr = program_argstr; |
|
|
1365 args_initted = 1; |
|
|
1366 } |
|
|
1367 |
|
|
1368 static char * |
|
|
1369 __add_program_arg (int argc, uint32 len) |
|
|
1370 { |
|
|
1371 char *res; |
|
|
1372 |
|
|
1373 if (! args_initted) |
|
|
1374 { |
|
|
1375 __free_program_args (); |
|
|
1376 } |
|
|
1377 |
|
|
1378 if ((argc >= (MAX_ARG_COUNT - 1)) |
|
|
1379 || ((argptr - program_argstr + len) > MAX_ARGDATA)) |
|
|
1380 { |
|
|
1381 return NULL; |
|
|
1382 } |
|
|
1383 |
|
|
1384 if (argc != last_program_arg) |
|
|
1385 { |
|
|
1386 if (argc >= program_argc) |
|
|
1387 { |
|
|
1388 program_argc = argc + 1; |
|
|
1389 program_argv [program_argc] = NULL; |
|
|
1390 } |
|
|
1391 program_argv [argc] = argptr; |
|
|
1392 last_program_arg = argc; |
|
|
1393 } |
|
|
1394 |
|
|
1395 res = argptr; |
|
|
1396 argptr += len; |
|
|
1397 |
|
|
1398 return res; |
|
|
1399 } |
|
|
1400 |
|
|
1401 void |
|
|
1402 __set_program_args (int argc, char **argv) |
|
|
1403 { |
|
|
1404 int x; |
|
|
1405 |
|
|
1406 __free_program_args (); |
|
|
1407 if (argc) |
|
|
1408 { |
|
|
1409 for (x = 0; x < argc; x++) |
|
|
1410 { |
|
|
1411 uint32 len = strlen (argv[x])+1; |
|
|
1412 char *s = __add_program_arg (x, len); |
|
|
1413 |
|
|
1414 if (s == NULL) |
|
|
1415 return; |
|
|
1416 |
|
|
1417 memcpy (s, argv[x], len); |
|
|
1418 } |
|
|
1419 } |
|
|
1420 } |
|
|
1421 |
|
|
1422 char ** |
|
|
1423 __get_program_args (target_register_t argcPtr) |
|
|
1424 { |
|
|
1425 if (!args_initted) |
|
|
1426 { |
|
|
1427 __free_program_args (); |
|
|
1428 } |
|
|
1429 __write_mem_safe ((char *) &program_argc, argcPtr, sizeof (program_argc)); |
|
|
1430 return program_argv; |
|
0
|
1431 } |
|
|
1432 |
|
|
1433 /* Table used by the crc32 function to calcuate the checksum. */ |
|
|
1434 static uint32 crc32_table[256]; |
|
|
1435 static int tableInit = 0; |
|
|
1436 |
|
|
1437 /* |
|
|
1438 Calculate a CRC-32 using LEN bytes of PTR. CRC is the initial CRC |
|
|
1439 value. |
|
|
1440 PTR is assumed to be a pointer in the user program. */ |
|
|
1441 |
|
|
1442 static uint32 |
|
2
|
1443 crc32 (ptr, len, crc) |
|
|
1444 unsigned char *ptr; |
|
|
1445 int len; |
|
|
1446 uint32 crc; |
|
0
|
1447 { |
|
|
1448 if (! tableInit) |
|
|
1449 { |
|
|
1450 /* Initialize the CRC table and the decoding table. */ |
|
|
1451 uint32 i, j; |
|
|
1452 uint32 c; |
|
|
1453 |
|
|
1454 tableInit = 1; |
|
|
1455 for (i = 0; i < 256; i++) |
|
2
|
1456 { |
|
|
1457 for (c = i << 24, j = 8; j > 0; --j) |
|
|
1458 c = c & 0x80000000 ? (c << 1) ^ 0x04c11db7 : (c << 1); |
|
|
1459 crc32_table[i] = c; |
|
|
1460 } |
|
0
|
1461 } |
|
|
1462 |
|
|
1463 __mem_fault = 0; |
|
|
1464 while (len--) |
|
|
1465 { |
|
|
1466 unsigned char ch; |
|
|
1467 |
|
|
1468 __read_mem_safe (&ch, (target_register_t) ptr, 1); |
|
|
1469 if (__mem_fault) |
|
2
|
1470 { |
|
|
1471 break; |
|
|
1472 } |
|
0
|
1473 crc = (crc << 8) ^ crc32_table[((crc >> 24) ^ ch) & 255]; |
|
|
1474 ptr++; |
|
|
1475 } |
|
|
1476 return crc; |
|
|
1477 } |
|
|
1478 |
|
|
1479 /* Handle the 'q' request */ |
|
|
1480 |
|
|
1481 static void |
|
|
1482 process_query (char *pkt) |
|
|
1483 { |
|
|
1484 remcomOutBuffer[0] = '\0'; |
|
2
|
1485 #ifdef __ECOS__ |
|
0
|
1486 if ('C' == pkt[0] && |
|
|
1487 'R' == pkt[1] && |
|
|
1488 'C' == pkt[2] && |
|
|
1489 ':' == pkt[3]) |
|
2
|
1490 #else // __ECOS__ |
|
|
1491 if (strncmp (pkt, "CRC:", 4) == 0) |
|
|
1492 #endif // __ECOS__ |
|
0
|
1493 { |
|
|
1494 target_register_t startmem; |
|
|
1495 target_register_t length; |
|
|
1496 uint32 our_crc; |
|
|
1497 |
|
|
1498 pkt += 4; |
|
|
1499 if (__hexToInt (&pkt, &startmem) |
|
2
|
1500 && *(pkt++) == ',' |
|
|
1501 && __hexToInt (&pkt, &length)) |
|
|
1502 { |
|
|
1503 our_crc = crc32 ((unsigned char *) startmem, length, 0xffffffff); |
|
|
1504 if (__mem_fault) |
|
|
1505 { |
|
|
1506 strcpy (remcomOutBuffer, "E01"); |
|
|
1507 } |
|
|
1508 else |
|
|
1509 { |
|
|
1510 int numb = __intToHex (remcomOutBuffer + 1, our_crc, 32); |
|
|
1511 remcomOutBuffer[0] = 'C'; |
|
|
1512 remcomOutBuffer[numb + 1] = 0; |
|
|
1513 } |
|
|
1514 } |
|
0
|
1515 return; |
|
|
1516 } |
|
|
1517 else |
|
|
1518 { |
|
|
1519 char ch ; |
|
|
1520 char * subpkt ; |
|
|
1521 ch = *pkt ; |
|
|
1522 subpkt = pkt + 1 ; |
|
|
1523 switch (ch) |
|
2
|
1524 { |
|
|
1525 case 'L' : /* threadlistquery */ |
|
|
1526 STUB_PKT_GETTHREADLIST (subpkt, remcomOutBuffer, 300); |
|
|
1527 break ; |
|
|
1528 case 'P' : /* Thread or process information request */ |
|
|
1529 STUB_PKT_GETTHREADINFO (subpkt, remcomOutBuffer, 300); |
|
|
1530 break ; |
|
|
1531 case 'C' : /* current thread query */ |
|
|
1532 STUB_PKT_CURRTHREAD(subpkt, remcomOutBuffer, sizeof(remcomOutBuffer)); |
|
|
1533 break; |
|
|
1534 default: |
|
|
1535 __process_target_query (pkt, remcomOutBuffer, 300); |
|
|
1536 break ; |
|
|
1537 } |
|
0
|
1538 } |
|
|
1539 } |
|
|
1540 |
|
|
1541 /* Handle the 'Q' request */ |
|
|
1542 |
|
|
1543 static void |
|
|
1544 process_set (char *pkt) |
|
|
1545 { |
|
|
1546 char ch ; |
|
|
1547 ch = *pkt ; |
|
|
1548 |
|
|
1549 switch (ch) |
|
|
1550 { |
|
|
1551 case 'p' : /* Set current process or thread */ |
|
|
1552 /* reserve the packet id even if support is not present */ |
|
|
1553 /* Dont strip the 'p' off the header, there are several variations of |
|
2
|
1554 this packet */ |
|
0
|
1555 STUB_PKT_CHANGETHREAD (pkt, remcomOutBuffer, 300) ; |
|
|
1556 break ; |
|
|
1557 default: |
|
|
1558 __process_target_set (pkt, remcomOutBuffer, 300); |
|
|
1559 break ; |
|
|
1560 } |
|
|
1561 } |
|
|
1562 #endif // CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS |