comparison packages/hal/common/current/src/thread-packets.c @ 0:3111d98ba7b3 ecos-v1_1-release

Initial commit of eCos version 1.1
author jlarmour
date Tue, 11 May 1999 11:16:07 +0000
parents
children 443894e2e912
comparison
equal deleted inserted replaced
-1:000000000000 0:3111d98ba7b3
1
2 /*
3 * Copyright (c) 1998 Cygnus Support
4 *
5 * The authors hereby grant permission to use, copy, modify, distribute,
6 * and license this software and its documentation for any purpose, provided
7 * that existing copyright notices are retained in all copies and that this
8 * notice is included verbatim in any distributions. No written agreement,
9 * license, or royalty fee is required for any of the authorized uses.
10 * Modifications to this software may be copyrighted by their authors
11 * and need not follow the licensing terms described here, provided that
12 * the new terms are clearly indicated on the first page of each file where
13 * they apply.
14 */
15
16 #include <pkgconf/hal.h>
17
18 #if defined(CYGDBG_HAL_DEBUG_GDB_THREAD_SUPPORT) \
19 && defined(CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS)
20
21 /* FIXME: Scan this module for correct sizes of fields in packets */
22 #define DEBUG_THREADS 1
23 #include "cyg/hal/dbg-threads-api.h"
24
25 /* This file should ALWAYS define debug thread support */
26 /* Dont include the object in the link if you dont need the support */
27 /* This is NOT the internal unit debug flag, it is a feature control */
28 #if defined(DEBUG_THREADS)
29 #undef DEBUG_THREADS
30 #define DEBUG_THREADS 1
31 #endif
32
33 #define UNIT_TEST 0
34 #define GDB_MOCKUP 0
35
36
37 #define STUB_BUF_MAX 300 /* for range checking of packet lengths */
38
39 #include "thread-pkts.h"
40
41 // Use HAL rather than board.h in eCos
42 #define PKT_DEBUG 0
43 #include <cyg/hal/hal_stub.h>
44 //#include "board.h"
45
46 #if !defined(PKT_DEBUG)
47 #define PKT_DEBUG 0
48 #endif
49 extern void output_string(char * message) ;
50
51 #if PKT_DEBUG
52 void output_threadid(char * title,threadref * ref) ;
53 #warning "PKT_DEBUG macros engaged"
54 #define PKT_TRACE(title,packet) \
55 { output_string(title) ; output_string(packet) ; output_string("\n") ;}
56 #else
57 #define PKT_TRACE(title,packet) {}
58 #endif
59
60
61 /* This is going to be irregular because the various implementations
62 have adopted different names for registers.
63 It would be nice to fix them to have a common convention
64 _stub_registers
65 stub_registers
66 alt_stub_registers
67 */
68
69 extern target_register_t * _registers ;
70 /* A pointer to the current set of registers */
71 extern target_register_t registers[NUMREGS]; /* The current saved registers */
72 extern target_register_t alt_registers[NUMREGS] ;
73 /* Thread or saved process state */
74
75
76 void __stub_copy_registers(
77 target_register_t * dest,
78 target_register_t *src
79 )
80 {
81 target_register_t * limit ;
82 limit = dest + NUMREGS ;
83
84 while (dest < limit) *dest++ = *src++ ;
85 }
86
87 extern int stubhex(char ch) ;
88
89 /* ----- STUB_PACK_NAK ----------------------------------- */
90 /* Pack an error response into the response packet */
91
92 char * stub_pack_nak(char * outbuf)
93 {
94 *outbuf++ = 'E' ;
95 *outbuf++ = '0' ;
96 *outbuf++ = '2' ;
97 return outbuf ;
98 } /* stub_pack_nak */
99
100 /* ----- STUB_PACK_ACK -------------------------- */
101 /* Pack an OK achnowledgement */
102 char * stub_pack_ack(char * outbuf)
103 {
104 *outbuf++ = 'O' ;
105 *outbuf++ = 'K' ;
106 return outbuf ;
107 } /* stub_pack_ack */
108
109 /* ------- STUB_UNPACK_INT ------------------------------- */
110 /* Unpack a few bytes and return its integer value */
111 /* This is where I wish functions could return several values
112 I would also advance the buffer pointer */
113
114 int stub_unpack_int(char * buff,int fieldlength)
115 {
116 int retval = 0 ;
117 int nibble ;
118 while (fieldlength)
119 { nibble = stubhex(*buff++) ;
120 retval |= nibble ;
121 fieldlength-- ;
122 if (fieldlength) retval = retval << 4 ;
123 }
124 return retval ;
125 } /* stub_unpack_int */
126
127 static char * unpack_byte(char * buf, int * value)
128 {
129 *value = stub_unpack_int(buf,2) ;
130 return buf + 2 ;
131 }
132
133 static char * unpack_int(char * buf, int * value)
134 {
135 *value = stub_unpack_int(buf,8) ;
136 return buf + 8 ;
137 }
138
139 /* We are NOT depending upun extensive libraries */
140 static int ishex(char ch,int *val)
141 {
142 if ((ch >= 'a') && (ch <= 'f'))
143 { *val =ch - 'a' + 10 ; return 1 ; }
144 if ((ch >= 'A') && (ch <= 'F'))
145 { *val = ch - 'A' + 10 ; return 1 ;}
146 if ((ch >= '0') && (ch <= '9'))
147 { *val = ch - '0' ; return 1 ; }
148 return 0 ;
149 } /* ishex */
150
151 static char * unpack_nibble(char * buf,int * val)
152 {
153 ishex(*buf++,val) ;
154 return buf ;
155 }
156
157
158 static const char hexchars[] = "0123456789abcdef";
159
160 static char * pack_hex_byte(char * pkt, unsigned char byte)
161 {
162 *pkt++ = hexchars[(byte >> 4) & 0xf] ;
163 *pkt++ = hexchars[(byte & 0xf)] ;
164 return pkt ;
165 } /* pack_hex_byte */
166
167 #if 0 // Currenly unused by eCos stub.
168 /* ---- STUB_PACK_VARLEN_HEX ------------------------------------- */
169 /* Format a variable length stream of hex bytes */
170
171 static char * pack_varlen_hex(
172 char * pkt,
173 unsigned int value)
174 {
175 int i ;
176 static unsigned char n[8] ;
177 if (value == 0)
178 {
179 *pkt++ = '0' ;
180 return pkt ;
181 }
182 else
183 {
184 i = 8 ;
185 while (i-- >= 0 ) /* unpack nibbles into a char array */
186 {
187 n[i] = value & 0x0f ;
188 value = value >> 4 ;
189 }
190 i = 0 ; /* we had descrmented it to -1 */
191 while (n[i] == 0 ) i++ ; /* drop leading zeroes */
192 while (i++ < 8) *pkt++ = hexchars[n[i]] ; /* pack the number */
193 }
194 return pkt ;
195 } /* pack_varlen_hex */
196 #endif
197
198 /* ------ STUB_UNPACK_VARLEN_HEX -------------------------------- */
199 /* Parse a stream of hex bytes which may be of variable length */
200 /* return the pointer to the next char */
201 /* modify a varparm containing the result */
202 /* A failure would look like a non-increment of the buffer pointer */
203
204 /* This unpacks hex strings that may have been packed using sprintf(%x) */
205 /* We assume some non-hex delimits them */
206
207 char * unpack_varlen_hex(
208 char * buff, /* packet to parse */
209 int * result)
210 {
211 int nibble ;
212 int retval ;
213 retval = 0 ;
214
215 while (ishex(*buff,&nibble))
216 {
217 buff++ ;
218 retval = retval << 4 ;
219 retval |= nibble & 0x0f ;
220 }
221 *result = retval ;
222 return buff ;
223 } /* stub_unpack_varlen_int */
224
225
226 /* ------ UNPACK_THREADID ------------------------------- */
227 /* A threadid is a 64 bit quantity */
228
229 #define BUFTHREADIDSIZ 16 /* encode 64 bits in 16 chars of hex */
230
231 static char * unpack_threadid(char * inbuf, threadref * id)
232 {
233 char * altref ;
234 char * limit = inbuf + BUFTHREADIDSIZ ;
235 int x,y ;
236 altref = (char *) id ;
237
238 while (inbuf < limit)
239 {
240 x = stubhex(*inbuf++) ;
241 y = stubhex(*inbuf++) ;
242 *altref++ = (x << 4) | y ;
243 }
244 return inbuf ;
245 } /* unpack_threadid */
246
247
248
249 /* Pack an integer use leading zeroes */
250 static char * pack_int(char * buf,int value)
251 {
252 buf = pack_hex_byte(buf,(value>> 24)& 0xff) ;
253 buf = pack_hex_byte(buf,(value >>16)& 0xff) ;
254 buf = pack_hex_byte(buf,(value >>8) & 0x0ff) ;
255 buf = pack_hex_byte(buf,(value & 0xff)) ;
256 return buf ;
257 } /* pack_int */
258
259
260 /* -------- PACK_STRING ---------------------------------------------- */
261 /* This stupid string better not contain any funny characters */
262 /* Also, the GDB protocol will not cope with NULLs in the
263 string or at the end of it.
264 While is is posable to encapsulate the protocol in ays that
265 preclude filtering for # I am assuming this is a constraint.
266 */
267
268 static char * pack_raw_string(char * pkt,char * string)
269 {
270 char ch ;
271 while (0 != (ch = *string++)) *pkt++ = ch ;
272 return pkt ;
273 }
274
275 static char * pack_string(
276 char * pkt,
277 char * string)
278 {
279 char ch ;
280 int len = 0;
281 char *s = string;
282 while( *s++ ) len++;
283 if (len > 200 ) len = 200 ; /* Bigger than most GDB packets, junk??? */
284 pkt = pack_hex_byte(pkt,len) ;
285 while (len-- > 0)
286 {
287 ch = *string++ ;
288 if ((ch == '\0') || (ch == '#')) ch = '*' ; /* Protect encapsulation */
289 *pkt++ = ch ;
290 }
291 return pkt ;
292 } /* pack_string */
293
294
295 /* ----- STUB_PACK_THREADID --------------------------------------------- */
296 /* Convert a binary 64 bit threadid and pack it into a xmit buffer */
297 /* Return the advanced buffer pointer */
298
299 static char * pack_threadid(char * pkt, threadref * id)
300 {
301 char * limit ;
302 unsigned char * altid ;
303 altid = (unsigned char *) id ;
304 limit = pkt + BUFTHREADIDSIZ ;
305 while (pkt < limit) pkt = pack_hex_byte(pkt,*altid++) ;
306 return pkt ;
307 } /* stub_pack_threadid */
308
309 /* UNFORTUNATLY, not all ow the extended debugging system has yet been
310 converted to 64 but thread referenecces and process identifiers.
311 These routines do the conversion.
312 An array of bytes is the correct treatment of an opaque identifier.
313 ints have endian issues.
314 */
315
316 static void int_to_threadref(threadref * id, int value)
317 {
318 unsigned char * scan ;
319 scan = (unsigned char *) id ;
320 {
321 int i = 4 ;
322 while (i--) *scan++ = 0 ;
323 }
324 *scan++ = (value >> 24) & 0xff ;
325 *scan++ = (value >> 16) & 0xff ;
326 *scan++ = (value >> 8) & 0xff ;
327 *scan++ = (value & 0xff) ;
328 }
329
330 static int threadref_to_int(threadref * ref)
331 {
332 int value = 0 ;
333 unsigned char * scan ;
334 int i ;
335
336 scan = (char *) ref ;
337 scan += 4 ;
338 i = 4 ;
339 while (i-- > 0) value = (value << 8) | ((*scan++) & 0xff) ;
340 return value ;
341 } /* threadref_to_int */
342
343 void copy_threadref(threadref * dest, threadref * src)
344 {
345 int i ;
346 unsigned char * csrc, * cdest ;
347 csrc = (unsigned char *) src ;
348 cdest = (unsigned char *) dest ;
349 i = 8 ;
350 while (i--) *cdest++ = *csrc++ ;
351 }
352
353
354 int threadmatch(
355 threadref * dest ,
356 threadref * src
357 )
358 {
359 unsigned char * srcp, * destp ;
360 int i , result ;
361 srcp = (char *) src ;
362 destp = (char *) dest ;
363 i = 8 ;
364 result = 1 ;
365 while (i-- > 0 ) result &= (*srcp++ == *destp++) ? 1 : 0 ;
366 return result ;
367 } /* threadmatch */
368
369
370
371 static char * Tpkt_threadtag = "thread:" ;
372
373 /* ----- STUB_PACK_TPKT_THREADID ------------------------------------ */
374 /* retreive, tag and insert a thread identifier into a T packet. */
375 /* Insert nothing if the thread identifier is not available */
376
377 char * stub_pack_Tpkt_threadid(char * pkt)
378 {
379 static threadref thread ;
380 int fmt = 0 ; /* old format */
381 PKT_TRACE("Tpkt-id","---") ;
382 if (dbg_currthread(&thread))
383 {
384 pkt = pack_raw_string(pkt,Tpkt_threadtag) ;
385 if (fmt)
386 pkt = pack_threadid(pkt,&thread) ;
387 else
388 /* Until GDB lengthens its thread ids, we have to MASH
389 the threadid into somthing shorter. PLEASE FIX GDB */
390 pkt = pack_int(pkt,threadref_to_int(&thread)) ;
391 *pkt++ = ';' ; /* terminate variable length int */
392 *pkt = '\0' ; /* Null terminate to allow string to be printed, no++ */
393 }
394 PKT_TRACE("packedTpkt","--") ;
395 return pkt ;
396 } /* stub_pack_Tpkt_threadid */
397
398
399 void stub_pkt_currthread(
400 char * inbuf,
401 char * outbuf,
402 int bufmax)
403 {
404 threadref thread ;
405 char * base_out ;
406 base_out = outbuf ;
407
408 if (dbg_currthread(&thread))
409 {
410 *outbuf++ = 'q' ;
411 *outbuf++ = 'P' ; /* FIXME: Is this a reasanable code */
412 outbuf = pack_threadid(outbuf,&thread) ; /* Long form */
413 }
414 else outbuf = stub_pack_nak(outbuf) ;
415 *outbuf = '\0' ; /* terminate response packet */
416 PKT_TRACE("stub_pkt_currthread(resp) ",base_out) ;
417 } /* stub_pkt_currthread */
418
419 /* ----- STUB_PKT_THREAD_ALIVE --------------------------------- */
420 /* Answer the thread alive query */
421
422 void stub_pkt_thread_alive(char * inbuf,
423 char * outbuf,
424 int bufmax)
425 {
426 char * prebuf = inbuf ;
427 int result ;
428 threadref thread ;
429 struct cygmon_thread_debug_info info ;
430
431 if (prebuf != (inbuf = unpack_varlen_hex(inbuf,&result)))
432 {
433 int_to_threadref(&thread,result) ;
434 /* pack old format into internal format */
435 if ((dbg_threadinfo(&thread,&info))
436 && info.context_exists)
437 { outbuf = stub_pack_ack(outbuf) ;
438 *outbuf = '\0' ;
439 return ;
440 }
441 }
442 outbuf = stub_pack_nak(outbuf) ;
443 *outbuf = '\0' ; /* terminate the response message */
444 } /* stub_pkt_thread_alive */
445
446
447
448 /* ----- STUB_PKT_CHANGETHREAD ------------------------------- */
449 /* Switch the display of registers to that of a saved context */
450
451 /* Changing the context makes NO sense, although the packets define the
452 capability. Therefore, the option to change the context back does
453 call the function to change registers. Also, there is no
454 forced context switch.
455 'p' - New format, long long threadid, no special cases
456 'c' - Old format, id for continue,32 bit threadid max, possably less
457 -1 contimue means continue all threads
458 'g' - Old Format, id for general use (other than continue)
459
460 replies:
461 OK for success
462 ENN for error
463 */
464
465 void stub_pkt_changethread(
466 char * inbuf,
467 char * outbuf,
468 int bufmax)
469 {
470 threadref id ;
471 int idefined = -1 ;
472 char ch ;
473 PKT_TRACE("setthread-pkt ",inbuf) ;
474
475 /* Parse the incoming packet for a thread identifier */
476 switch (ch = *inbuf++ ) /* handle various packet formats */
477 {
478 case 'p' : /* New format: mode:8,threadid:64 */
479 inbuf = unpack_nibble(inbuf,&idefined) ;
480 inbuf = unpack_threadid(inbuf,&id) ; /* even if startflag */
481 break ;
482 case 'c' : /* old format , specify thread for continue */
483 outbuf = stub_pack_nak(outbuf) ; /* Not supported */
484 break ;
485 case 'g' : /* old format, specify thread for general operations */
486 /* OLD format: parse a variable length hex string */
487 /* OLD format consider special thread ids */
488 {
489 int oldthreadid ;
490 inbuf = unpack_varlen_hex(inbuf,&oldthreadid) ;
491 int_to_threadref(&id,oldthreadid) ;
492 switch (oldthreadid)
493 {
494 case 0 : /* pick a thread, any thread */
495 idefined = 2 ; /* select original interrupted context */
496 break ;
497 case -1 : /* all threads */
498 idefined = 2 ;
499 break ;
500 default :
501 idefined = 1 ; /* select the specified thread */
502 break ;
503 }
504 }
505 break ;
506 default:
507 outbuf = stub_pack_nak(outbuf) ;
508 break ;
509 } /* handle various packet formats */
510
511
512 switch (idefined)
513 {
514 case -1 :
515 /* Packet not supported, already NAKed, no further action */
516 break ;
517 case 0 :
518 /* Switch back to interrupted context */
519 _registers = &registers[0] ;
520 break ;
521 case 1 :
522 /* copy the saved registers into the backup registers */
523 __stub_copy_registers(alt_registers,registers) ;
524 /* The OS will now update the values it has in a saved process context*/
525 if (dbg_getthreadreg(&id,NUMREGS,&alt_registers[0]))
526 {
527 /* switch the registers pointer */
528 _registers = &alt_registers[0] ;
529 outbuf = stub_pack_ack(outbuf) ;
530 }
531 else
532 outbuf = stub_pack_nak(outbuf) ;
533 break ;
534 case 2 : break ; /* switch to interrupted context */
535 default:
536 outbuf = stub_pack_nak(outbuf) ;
537 break ;
538 }
539 *outbuf = '\0' ; /* Terminate response pkt */
540 } /* stub_pkt-changethread */
541
542
543 /* ---- STUB_PKT_GETTHREADLIST ------------------------------- */
544 /* Get a portion of the threadlist or process list */
545 /* This may be part of a multipacket transaction */
546 /* It would be hard to tell in the response packet the difference
547 between the end of list and an error in threadid encoding.
548 */
549
550 void stub_pkt_getthreadlist(char * inbuf,
551 char * outbuf,
552 int bufmax)
553 {
554 char * count_ptr ;
555 char * done_ptr ;
556 char * limit ;
557 int start_flag , batchsize , result , count ;
558 static threadref lastthread, nextthread ;
559
560 #if PKT_DEBUG
561 char * r_base = outbuf ;
562 #endif
563 PKT_TRACE("pkt_getthreadlist: ",inbuf) ;
564
565 count = 0 ;
566 inbuf = unpack_nibble(inbuf,&start_flag) ;
567 inbuf = unpack_byte(inbuf,&batchsize) ;
568 inbuf = unpack_threadid(inbuf,&lastthread) ; /* even if startflag */
569
570 /* Start building response packet */
571 limit = outbuf + (bufmax - BUFTHREADIDSIZ - 10) ; /* id output packing limit */
572 *outbuf++ = 'Q' ;
573 *outbuf++ = 'M' ;
574
575 /* Default values for count and done fields, save ptr to repatch */
576 count_ptr = outbuf ; /* save to repatch count */
577 outbuf = pack_hex_byte(outbuf,0) ;
578 done_ptr = outbuf ; /* Backpatched later */
579 *outbuf++ = '0' ; /* Done = 0 by default */
580 outbuf = pack_threadid(outbuf,&lastthread) ;
581
582 /* Loop through the threadid packing */
583 while ((outbuf < limit) && (count < batchsize))
584 {
585 result = dbg_threadlist(start_flag,&lastthread,&nextthread) ;
586 start_flag = 0 ; /* redundent but effective */
587 if (!result)
588 { *done_ptr = '1' ; /* pack the done flag */
589 break ;
590 }
591 #if 0 /* DEBUG */
592 if (threadmatch(&lastthread,&nextthread))
593 {
594 output_string("FAIL: Threadlist, not incrementing\n") ;
595 *done_ptr = '1' ;
596 break ;
597 }
598 #endif
599 count++ ;
600 outbuf = pack_threadid(outbuf,&nextthread) ;
601 copy_threadref(&lastthread,&nextthread) ;
602 }
603 pack_hex_byte(count_ptr,count) ;/* backpatch, Pack the count field */
604 *outbuf = '\0' ;
605 PKT_TRACE("pkt_getthreadlist(resp) ",r_base) ;
606 } /* pkt_getthreadlist */
607
608
609
610
611 /* ----- STUB_PKT_GETTHREADINFO ---------------------------------------- */
612 /* Get the detailed information about a specific thread or process */
613
614 /*
615 Encoding:
616 'Q':8,'P':8,mask:16
617
618 Mask Fields
619 threadid:1, # always request threadid
620 context_exists:2,
621 display:4,
622 unique_name:8,
623 more_display:16
624 */
625
626 void stub_pkt_getthreadinfo(
627 char * inbuf,
628 char * outbuf,
629 int bufmax)
630 {
631 int mask ;
632 int result ;
633 threadref thread ;
634 struct cygmon_thread_debug_info info ;
635
636 info.context_exists = 0 ;
637 info.thread_display = 0 ;
638 info.unique_thread_name = 0 ;
639 info.more_display = 0 ;
640
641 /* Assume the packet identification chars have already been
642 discarded by the packet demultiples routines */
643 PKT_TRACE("PKT getthreadinfo",inbuf) ;
644
645 inbuf = unpack_int(inbuf,&mask) ;
646 inbuf = unpack_threadid(inbuf,&thread) ;
647
648 result = dbg_threadinfo(&thread,&info) ; /* Make system call */
649
650 if (result)
651 {
652 *outbuf++ = 'q' ;
653 *outbuf++ = 'p' ;
654 outbuf = pack_int(outbuf,mask) ;
655 outbuf = pack_threadid(outbuf,&info.thread_id) ; /* echo threadid */
656 if (mask & 2) /* context-exists */
657 {
658 outbuf = pack_int(outbuf,2) ; /* tag */
659 outbuf = pack_hex_byte(outbuf,2) ; /* length */
660 outbuf = pack_hex_byte(outbuf,info.context_exists) ;
661 }
662 if ((mask & 4) && info.thread_display)/* display */
663 {
664 outbuf = pack_int(outbuf,4) ; /* tag */
665 outbuf = pack_string(outbuf,info.thread_display) ;
666 }
667 if ((mask & 8) && info.unique_thread_name) /* unique_name */
668 {
669 outbuf = pack_int(outbuf,8) ;
670 outbuf = pack_string(outbuf,info.unique_thread_name) ;
671 }
672 if ((mask & 16) && info.more_display) /* more display */
673 {
674 outbuf = pack_int(outbuf,16) ; /* tag 16 */
675 outbuf = pack_string(outbuf,info.more_display) ;
676 }
677 }
678 else
679 {
680 PKT_TRACE("FAIL: dbg_threadinfo\n", "") ;
681 outbuf = stub_pack_nak(outbuf) ;
682 }
683 *outbuf = '\0' ;
684 } /* stub_pkt_getthreadinfo */
685
686
687
688
689 #if GDB_MOCKUP
690 /* ------ MATCHED GDB SIDE PACKET ENCODING AND PARSING ----------------- */
691
692 char * pack_nibble(char * buf, int nibble)
693 {
694 *buf++ = hexchars[(nibble & 0x0f)] ;
695 return buf ;
696 } /* pack_nibble */
697
698 #if 0
699 static char * unpack_short(char * buf,int * value)
700 {
701 *value = stub_unpack_int(buf,4) ;
702 return buf + 4 ;
703 }
704
705 static char * pack_short(
706 char * buf,
707 unsigned int value)
708 {
709 buf = pack_hex_byte(buf,(value >> 8) & 0xff) ;
710 buf = pack_hex_byte(buf,(value & 0xff)) ;
711 return buf ;
712 } /* pack_short */
713 #endif
714
715
716 /* Generally, I dont bury xmit and receive calls inside packet formatters
717 and parsers
718 */
719
720
721
722
723 /* ----- PACK_SETTHREAD_REQUEST ------------------------------------- */
724 /* Encoding: ??? decode gdb/remote.c
725 'Q':8,'p':8,idefined:8,threadid:32 ;
726 */
727
728 char * pack_setthread_request(
729 char * buf,
730 char fmt, /* c,g or, p */
731 int idformat ,
732 threadref * threadid )
733 {
734 *buf++ = fmt ;
735
736 if (fmt == 'p')
737 { /* pack the long form */
738 buf = pack_nibble(buf,idformat) ;
739 buf = pack_threadid(buf,threadid) ;
740 }
741 else
742 { /* pack the shorter form - Serious truncation */
743 /* There are reserved identifieds 0 , -1 */
744 int quickref = threadref_to_int(threadid) ;
745 buf = pack_varlen_hex(buf,quickref) ;
746 }
747 *buf++ = '\0' ; /* end_of_packet */
748 return buf ;
749 } /* pack_setthread_request */
750
751
752
753 /* -------- PACK_THREADLIST-REQUEST --------------------------------- */
754 /* Format: i'Q':8,i"L":8,initflag:8,batchsize:16,lastthreadid:32 */
755
756
757 char * pack_threadlist_request(
758 char * pkt,
759 int startflag,
760 int threadcount,
761 threadref * nextthread
762 )
763 {
764 *pkt++ = 'q' ;
765 *pkt++ = 'L' ;
766 pkt = pack_nibble(pkt,startflag) ; /* initflag 1 bytes */
767 pkt = pack_hex_byte(pkt,threadcount) ; /* threadcount 2 bytes */
768 pkt = pack_threadid(pkt,nextthread) ; /* 64 bit thread identifier */
769 *pkt = '\0' ;
770 return pkt ;
771 } /* remote_threadlist_request */
772
773
774
775
776 /* ---------- PARSE_THREADLIST_RESPONSE ------------------------------------ */
777 /* Encoding: 'q':8,'M':8,count:16,done:8,argthreadid:64,(threadid:64)* */
778
779 int parse_threadlist_response(
780 char * pkt,
781 threadref * original_echo,
782 threadref * resultlist,
783 int * doneflag)
784 {
785 char * limit ;
786 int count, resultcount , done ;
787 resultcount = 0 ;
788
789 /* assume the 'q' and 'M chars have been stripped */
790 PKT_TRACE("parse-threadlist-response ",pkt) ;
791 limit = pkt + (STUB_BUF_MAX - BUFTHREADIDSIZ) ; /* done parse past here */
792 pkt = unpack_byte(pkt,&count) ; ; /* count field */
793 pkt = unpack_nibble(pkt,&done) ;
794 /* The first threadid is the argument threadid */
795 pkt = unpack_threadid(pkt,original_echo) ; /* should match query packet */
796 while ((count-- > 0) && (pkt < limit))
797 {
798 pkt = unpack_threadid(pkt,resultlist++) ;
799 resultcount++ ;
800 }
801 if (doneflag) *doneflag = done ;
802 return resultcount ; /* successvalue */
803 } /* parse_threadlist_response */
804
805 struct gdb_ext_thread_info
806 {
807 threadref threadid ;
808 int active ;
809 char display[256] ;
810 char shortname[32] ;
811 char more_display[256] ;
812 } ;
813
814
815 /* ----- PACK_THREAD_INFO_REQUEST -------------------------------- */
816
817 /*
818 threadid:1, # always request threadid
819 context_exists:2,
820 display:4,
821 unique_name:8,
822 more_display:16
823 */
824
825 /* Encoding: 'Q':8,'P':8,mask:32,threadid:64 */
826
827 char * pack_threadinfo_request(char * pkt,
828 int mode,
829 threadref * id
830 )
831 {
832 *pkt++ = 'Q' ;
833 *pkt++ = 'P' ;
834 pkt = pack_int(pkt,mode) ; /* mode */
835 pkt = pack_threadid(pkt,id) ; /* threadid */
836 *pkt = '\0' ; /* terminate */
837 return pkt ;
838 } /* pack_thread_info_request */
839
840
841
842 static char * unpack_string(
843 char * src,
844 char * dest,
845 int length)
846 {
847 while (length--) *dest++ = *src++ ;
848 *dest = '\0' ;
849 return src ;
850 } /* unpack_string */
851
852
853 void output_threadid(char * title,threadref * ref)
854 {
855 char hexid[20] ;
856 pack_threadid(&hexid[0],ref) ; /* Convert threead id into hex */
857 hexid[16] = 0 ;
858 output_string(title) ; output_string(&hexid[0]) ; output_string("\n");
859 }
860
861 /* ------ REMOTE_UPK_THREAD_INFO_RESPONSE ------------------------------- */
862 /* Unpack the response of a detailed thread info packet */
863 /* Encoding: i'Q':8,i'R':8,argmask:16,threadid:64,(tag:8,length:16,data:x)* */
864
865 #define TAG_THREADID 1
866 #define TAG_EXISTS 2
867 #define TAG_DISPLAY 4
868 #define TAG_THREADNAME 8
869 #define TAG_MOREDISPLAY 16
870
871
872 int remote_upk_thread_info_response(
873 char * pkt,
874 threadref * expectedref ,
875 struct gdb_ext_thread_info * info)
876 {
877 int mask, length ;
878 unsigned int tag ;
879 threadref ref ;
880 char * limit = pkt + 500 ; /* plausable parsing limit */
881 int retval = 1 ;
882
883 PKT_TRACE("upk-threadinfo ",pkt) ;
884
885 /* info->threadid = 0 ; FIXME: implement zero_threadref */
886 info->active = 0 ;
887 info->display[0] = '\0' ;
888 info->shortname[0] = '\0' ;
889 info->more_display[0] = '\0' ;
890
891 /* Assume the characters indicating the packet type have been stripped */
892 pkt = unpack_int(pkt,&mask) ; /* arg mask */
893 pkt = unpack_threadid(pkt , &ref) ;
894
895 if (! threadmatch(&ref,expectedref))
896 { /* This is an answer to a different request */
897 output_string("FAIL Thread mismatch\n") ;
898 output_threadid("ref ",&ref) ;
899 output_threadid("expected ",expectedref) ;
900 return 0 ;
901 }
902 copy_threadref(&info->threadid,&ref) ;
903
904 /* Loop on tagged fields , try to bail if somthing goes wrong */
905 if (mask==0) output_string("OOPS NO MASK \n") ;
906
907 while ((pkt < limit) && mask && *pkt) /* packets are terminated with nulls */
908 {
909 pkt = unpack_int(pkt,&tag) ; /* tag */
910 pkt = unpack_byte(pkt,&length) ; /* length */
911 if (! (tag & mask)) /* tags out of synch with mask */
912 {
913 output_string("FAIL: threadinfo tag mismatch\n") ;
914 retval = 0 ;
915 break ;
916 }
917 if (tag == TAG_THREADID)
918 {
919 output_string("unpack THREADID\n") ;
920 if (length != 16)
921 {
922 output_string("FAIL: length of threadid is not 16\n") ;
923 retval = 0 ;
924 break ;
925 }
926 pkt = unpack_threadid(pkt,&ref) ;
927 mask = mask & ~ TAG_THREADID ;
928 continue ;
929 }
930 if (tag == TAG_EXISTS)
931 {
932 info->active = stub_unpack_int(pkt,length) ;
933 pkt += length ;
934 mask = mask & ~(TAG_EXISTS) ;
935 if (length > 8)
936 {
937 output_string("FAIL: 'exists' length too long\n");
938 retval = 0 ;
939 break ;
940 }
941 continue ;
942 }
943 if (tag == TAG_THREADNAME)
944 {
945 pkt = unpack_string(pkt,&info->shortname[0],length) ;
946 mask = mask & ~TAG_THREADNAME ;
947 continue ;
948 }
949 if (tag == TAG_DISPLAY)
950 {
951 pkt = unpack_string(pkt,&info->display[0],length) ;
952 mask = mask & ~TAG_DISPLAY ;
953 continue ;
954 }
955 if (tag == TAG_MOREDISPLAY)
956 {
957 pkt = unpack_string(pkt,&info->more_display[0],length) ;
958 mask = mask & ~TAG_MOREDISPLAY ;
959 continue ;
960 }
961 output_string("FAIL: unknown info tag\n") ;
962 break ; /* Not a tag we know about */
963 }
964 return retval ;
965 } /* parse-thread_info_response */
966
967
968 /* ---- REMOTE_PACK-CURRTHREAD_REQUEST ---------------------------- */
969 /* This is a request to emit the T packet */
970
971 /* FORMAT: 'q':8,'C' */
972
973 char * remote_pack_currthread_request(char * pkt )
974 {
975 *pkt++ = 'q' ;
976 *pkt++ = 'C' ;
977 *pkt = '\0' ;
978 return pkt ;
979 } /* remote_pack-currthread_request */
980
981
982 /* ------- REMOTE_UPK_CURTHREAD_RESPONSE ----------------------- */
983 /* Unpack the interesting part of a T packet */
984
985
986 int remote_upk_currthread_response(
987 char * pkt,
988 threadref * ref ) /* Parse a T packet */
989 {
990 int retval = 0 ;
991 PKT_TRACE("upk-currthreadresp ",pkt) ;
992
993 #if 0
994 {
995 static char threadtag[8] = "thread" ;
996 int retval = 0 ;
997 int i , found ;
998 char ch ;
999 int quickid ;
1000
1001 /* Unpack as a t packet */
1002 while (((ch = *pkt++) != ':') /* scan for : thread */
1003 && (ch != '\0')) /* stop at end of packet */
1004
1005 {
1006 found = 0 ;
1007 i = 0 ;
1008 while ((ch = *pkt++) == threadtag[i++]) ;
1009 if (i == 8) /* string match "thread" */
1010 {
1011 pkt = unpack_varlen_hex(pkt,&quickid) ;
1012 retval = 1;
1013 break ;
1014 }
1015 retval = 0 ;
1016 }
1017 }
1018 #else
1019 pkt = unpack_threadid(pkt,ref) ;
1020 retval = 1 ;
1021 #endif
1022 return retval ;
1023 } /* remote_upk_currthread_response */
1024
1025
1026 /* -------- REMOTE_UPK-SIMPLE_ACK --------------------------------- */
1027 /* Decode a response which is eother "OK" or "Enn"
1028 fillin error code, fillin pkfag-1== undef, 0==nak, 1 == ack ;
1029 return advanced packet pointer */
1030
1031
1032 char * remote_upk_simple_ack(
1033 char * buf,
1034 int * pkflag,
1035 int * errcode)
1036 {
1037 int lclerr = 0 ;
1038 char ch = *buf++ ;
1039 int retval = -1 ; /* Undefined ACK , a protocol error */
1040 if (ch == 'E') /* NAK */
1041 {
1042 buf = unpack_byte(buf,&lclerr) ;
1043 retval = 0 ; /* transaction failed, explicitly */
1044 }
1045 else
1046 if ((ch == 'O') && (*buf++ == 'K')) /* ACK */
1047 retval = 1 ; /* transaction succeeded */
1048 *pkflag = retval ;
1049 *errcode = lclerr ;
1050 return buf ;
1051 } /* remote-upk_simple_ack */
1052
1053
1054 /* -------- PACK_THREADALIVE_REQUEST ------------------------------- */
1055
1056 char * pack_threadalive_request(
1057 char * buf,
1058 threadref * threadid)
1059 {
1060 *buf++ = 'T' ;
1061 buf = pack_threadid(buf,threadid) ;
1062 *buf = '\0' ;
1063 return buf ;
1064 } /* pack_threadalive_request */
1065
1066 #endif /* GDB_MOCKUP */
1067
1068 /* ---------------------------------------------------------------------- */
1069 /* UNIT_TESTS SUBSECTION */
1070 /* ---------------------------------------------------------------------- */
1071
1072
1073 #if UNIT_TEST
1074 extern void output_string(char * message) ;
1075 static char test_req[400] ;
1076 static char t_response[400] ;
1077
1078
1079
1080 /* ----- DISPLAY_THREAD_INFO ---------------------------------------------- */
1081 /* Use local cygmon string output utiities */
1082
1083 void display_thread_info(struct gdb_ext_thread_info * info)
1084 {
1085
1086 output_threadid("Threadid: ",&info->threadid) ;
1087 /* short name */
1088 output_string("Name: ") ; output_string(info->shortname) ; output_string("\n");
1089 /* format display state */
1090 output_string("State: ") ; output_string(info->display) ; output_string("\n") ;
1091 /* additional data */
1092 output_string("other: ");output_string(info->more_display);
1093 output_string("\n\n");
1094 } /* display_thread_info */
1095
1096
1097 /* --- CURRTHREAD-TEST -------------------------------------------- */
1098 static int currthread_test(threadref * thread)
1099 {
1100 int result ;
1101 output_string("TEST: currthread\n") ;
1102 remote_pack_currthread_request(test_req) ;
1103 stub_pkt_currthread(test_req+2,t_response,STUB_BUF_MAX) ;
1104 result = remote_upk_currthread_response(t_response+2,thread) ;
1105 if (result)
1106 {
1107 output_string("PASS getcurthread\n") ;
1108 /* FIXME: print the thread */
1109 }
1110 else
1111 output_string("FAIL getcurrthread\n") ;
1112 return result ;
1113 } /* currthread_test */
1114
1115 /* ------ SETTHREAD_TEST ------------------------------------------- */
1116 /* use a known thread from previous test */
1117
1118 static int setthread_test(threadref * thread)
1119 {
1120 int result, errcode ;
1121 output_string("TEST: setthread\n") ;
1122
1123 pack_setthread_request(test_req,'p',1,thread) ;
1124 stub_pkt_changethread(test_req,t_response,STUB_BUF_MAX) ;
1125 remote_upk_simple_ack(t_response,&result,&errcode) ;
1126 switch (result)
1127 {
1128 case 0 :
1129 output_string("FAIL setthread\n") ;
1130 break ;
1131 case 1 :
1132 output_string("PASS setthread\n") ;
1133 break ;
1134 default :
1135 output_string("FAIL setthread -unrecognized response\n") ;
1136 break ;
1137 }
1138 return result ;
1139 } /* setthread_test */
1140
1141
1142 /* ------ THREADACTIVE_TEST ---------------------- */
1143 /* use known thread */
1144 /* pack threadactive packet */
1145 /* process threadactive packet */
1146 /* parse threadactive response */
1147 /* check results */
1148
1149
1150 int threadactive_test(threadref * thread)
1151 {
1152 int result ;
1153 int errcode ;
1154 output_string("TEST: threadactive\n") ;
1155 pack_threadalive_request(test_req,thread) ;
1156 stub_pkt_thread_alive(test_req+1,t_response,STUB_BUF_MAX);
1157 remote_upk_simple_ack(t_response,&result,&errcode) ;
1158 switch (result)
1159 {
1160 case 0 :
1161 output_string("FAIL threadalive\n") ;
1162 break ;
1163 case 1 :
1164 output_string("PASS threadalive\n") ;
1165 break ;
1166 default :
1167 output_string("FAIL threadalive -unrecognized response\n") ;
1168 break ;
1169 }
1170 return result ;
1171 } /* threadactive_test */
1172
1173 /* ------ REMOTE_GET_THREADINFO -------------------------------------- */
1174 int remote_get_threadinfo(
1175 threadref * threadid,
1176 int fieldset , /* TAG mask */
1177 struct gdb_ext_thread_info * info
1178 )
1179 {
1180 int result ;
1181 pack_threadinfo_request(test_req,fieldset,threadid) ;
1182 stub_pkt_getthreadinfo(test_req+2,t_response,STUB_BUF_MAX) ;
1183 result = remote_upk_thread_info_response(t_response+2,threadid,info) ;
1184 return result ;
1185 } /* remote_get-thrreadinfo */
1186
1187
1188 static struct gdb_ext_thread_info test_info ;
1189
1190 static int get_and_display_threadinfo(threadref * thread)
1191 {
1192 int mode ;
1193 int result ;
1194 /* output_string("TEST: get and display threadinfo\n") ; */
1195
1196 mode = TAG_THREADID | TAG_EXISTS | TAG_THREADNAME
1197 | TAG_MOREDISPLAY | TAG_DISPLAY ;
1198 result = remote_get_threadinfo(thread,mode,&test_info) ;
1199 if (result) display_thread_info(&test_info) ;
1200 #if 0 /* silent subtest */
1201 if (result)
1202 output_string("PASS: get_and_display threadinfo\n") ;
1203 else
1204 output_string("FAIL: get_and_display threadinfo\n") ;
1205 #endif
1206 return result ;
1207 } /* get-and-display-threadinfo */
1208
1209
1210
1211 /* ----- THREADLIST_TEST ------------------------------------------ */
1212 #define TESTLISTSIZE 16
1213 #define TLRSIZ 2
1214 static threadref test_threadlist[TESTLISTSIZE] ;
1215
1216 static int threadlist_test(void)
1217 {
1218 int done, i , result_count ;
1219 int startflag = 1 ;
1220 int result = 1 ;
1221 int loopcount = 0 ;
1222 static threadref nextthread ;
1223 static threadref echo_nextthread ;
1224
1225 output_string("TEST: threadlist\n") ;
1226
1227 done = 0 ;
1228 while (! done)
1229 {
1230 if (loopcount++ > 10)
1231 {
1232 result = 0 ;
1233 output_string("FAIL: Threadlist test -infinite loop-\n") ;
1234 break ;
1235 }
1236 pack_threadlist_request(test_req,startflag,TLRSIZ,&nextthread) ;
1237 startflag = 0 ; /* clear for later iterations */
1238 stub_pkt_getthreadlist(test_req+2,t_response,STUB_BUF_MAX);
1239 result_count = parse_threadlist_response(t_response+2,
1240 &echo_nextthread,
1241 &test_threadlist[0],&done) ;
1242 if (! threadmatch(&echo_nextthread,&nextthread))
1243 {
1244 output_string("FAIL: threadlist did not echo arg thread\n");
1245 result = 0 ;
1246 break ;
1247 }
1248 if (result_count <= 0)
1249 {
1250 if (done != 0)
1251 { output_string("FAIL threadlist_test, failed to get list");
1252 result = 0 ;
1253 }
1254 break ;
1255 }
1256 if (result_count > TLRSIZ)
1257 {
1258 output_string("FAIL: threadlist response longer than requested\n") ;
1259 result = 0 ;
1260 break ;
1261 }
1262 /* Setup to resume next batch of thread references , set nestthread */
1263 copy_threadref(&nextthread,&test_threadlist[result_count-1]) ;
1264 /* output_threadid("last-of-batch",&nextthread) ; */
1265 i = 0 ;
1266 while (result_count--)
1267 {
1268 if (0) /* two display alternatives */
1269 output_threadid("truncatedisplay",&test_threadlist[i++]) ;
1270 else
1271 get_and_display_threadinfo(&test_threadlist[i++]) ;
1272 }
1273
1274 }
1275 if (!result)
1276 output_string("FAIL: threadlist test\n") ;
1277 else output_string("PASS: Threadlist test\n") ;
1278 return result ;
1279 } /* threadlist_test */
1280
1281
1282 static threadref testthread ;
1283
1284
1285 int test_thread_support(void)
1286 {
1287 int result = 1 ;
1288 output_string("TESTING Thread support infrastructure\n") ;
1289 stub_pack_Tpkt_threadid(test_req) ;
1290 PKT_TRACE("packing the threadid -> ",test_req) ;
1291 result &= currthread_test(&testthread) ;
1292 result &= get_and_display_threadinfo(&testthread) ;
1293 result &= threadlist_test() ;
1294 result &= setthread_test(&testthread) ;
1295 if (result)
1296 output_string("PASS: UNITTEST Thread support\n") ;
1297 else
1298 output_string("FAIL: UNITTEST Thread support\n") ;
1299 return result ;
1300 } /* test-thread_support */
1301 #endif /* UNIT_TEST */
1302
1303 #endif // ifdef CYGDBG_HAL_DEBUG_GDB_THREAD_SUPPORT...