1 //========================================================================
5 // Provides multi-threaded debug support
7 //========================================================================
8 //####ECOSGPLCOPYRIGHTBEGIN####
9 // -------------------------------------------
10 // This file is part of eCos, the Embedded Configurable Operating System.
11 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
13 // eCos is free software; you can redistribute it and/or modify it under
14 // the terms of the GNU General Public License as published by the Free
15 // Software Foundation; either version 2 or (at your option) any later version.
17 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
18 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
19 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22 // You should have received a copy of the GNU General Public License along
23 // with eCos; if not, write to the Free Software Foundation, Inc.,
24 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
26 // As a special exception, if other files instantiate templates or use macros
27 // or inline functions from this file, or you compile this file and link it
28 // with other works to produce a work based on this file, this file does not
29 // by itself cause the resulting work to be covered by the GNU General Public
30 // License. However the source code for this file must still be made available
31 // in accordance with section (3) of the GNU General Public License.
33 // This exception does not invalidate any other reasons why a work based on
34 // this file might be covered by the GNU General Public License.
36 // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
37 // at http://sources.redhat.com/ecos/ecos-license/
38 // -------------------------------------------
39 //####ECOSGPLCOPYRIGHTEND####
40 //========================================================================
41 //#####DESCRIPTIONBEGIN####
43 // Author(s): Red Hat, nickg
44 // Contributors: Red Hat, nickg
47 // Description: Provides multi-threaded debug support
50 //####DESCRIPTIONEND####
52 //========================================================================
54 // Define __ECOS__; allows all eCos specific additions to be easily identified.
59 #include <pkgconf/hal.h>
61 #if defined(CYGDBG_HAL_DEBUG_GDB_THREAD_SUPPORT) \
62 && defined(CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS)
65 /* FIXME: Scan this module for correct sizes of fields in packets */
68 #include <cyg/hal/dbg-threads-api.h>
70 #include "dbg-threads-api.h"
73 /* This file should ALWAYS define debug thread support */
74 /* Dont include the object in the link if you dont need the support */
75 /* This is NOT the internal unit debug flag, it is a feature control */
76 #if defined(DEBUG_THREADS)
80 #define DEBUG_THREADS 1
85 #define STUB_BUF_MAX 300 /* for range checking of packet lengths */
87 #include "thread-pkts.h"
90 // Use HAL rather than board.h in eCos
91 #include <cyg/hal/hal_stub.h>
97 * Export the continue and "general" (context) thread IDs from GDB.
99 int _gdb_cont_thread ;
100 int _gdb_general_thread ;
102 #if !defined(PKT_DEBUG)
105 extern void output_string(char * message) ;
108 void output_threadid(char * title,threadref * ref) ;
109 #warning "PKT_DEBUG macros engaged"
110 #define PKT_TRACE(title,packet) \
111 { output_string(title) ; output_string(packet) ; output_string("\n") ;}
113 #define PKT_TRACE(title,packet) {}
117 /* This is going to be irregular because the various implementations
118 have adopted different names for registers.
119 It would be nice to fix them to have a common convention
125 extern target_register_t * _registers ;
126 /* A pointer to the current set of registers */
127 extern target_register_t registers[]; /* The current saved registers */
128 extern target_register_t alt_registers[] ;
129 /* Thread or saved process state */
132 static void stub_copy_registers(
133 target_register_t * dest,
134 target_register_t *src
137 target_register_t * limit ;
138 limit = dest + NUMREGS ;
140 while (dest < limit) *dest++ = *src++ ;
144 void __stub_copy_registers(target_register_t * dest,
145 target_register_t *src)
147 stub_copy_registers(dest, src);
151 extern int stubhex(char ch) ;
153 /* ----- STUB_PACK_NAK ----------------------------------- */
154 /* Pack an error response into the response packet */
156 char * stub_pack_nak(char * outbuf)
162 } /* stub_pack_nak */
164 /* ----- STUB_PACK_ACK -------------------------- */
165 /* Pack an OK achnowledgement */
166 char * stub_pack_ack(char * outbuf)
171 } /* stub_pack_ack */
173 /* ------- STUB_UNPACK_INT ------------------------------- */
174 /* Unpack a few bytes and return its integer value */
175 /* This is where I wish functions could return several values
176 I would also advance the buffer pointer */
178 int stub_unpack_int(char * buff,int fieldlength)
183 { nibble = stubhex(*buff++) ;
186 if (fieldlength) retval = retval << 4 ;
189 } /* stub_unpack_int */
191 static char * unpack_byte(char * buf, int * value)
193 *value = stub_unpack_int(buf,2) ;
197 static char * unpack_int(char * buf, int * value)
199 *value = stub_unpack_int(buf,8) ;
203 /* We are NOT depending upon extensive libraries */
204 static int ishex(char ch,int *val)
206 if ((ch >= 'a') && (ch <= 'f'))
207 { *val =ch - 'a' + 10 ; return 1 ; }
208 if ((ch >= 'A') && (ch <= 'F'))
209 { *val = ch - 'A' + 10 ; return 1 ;}
210 if ((ch >= '0') && (ch <= '9'))
211 { *val = ch - '0' ; return 1 ; }
215 static char * unpack_nibble(char * buf,int * val)
222 static const char hexchars[] = "0123456789abcdef";
224 static char * pack_hex_byte(char * pkt, unsigned char byte)
226 *pkt++ = hexchars[(byte >> 4) & 0xf] ;
227 *pkt++ = hexchars[(byte & 0xf)] ;
229 } /* pack_hex_byte */
232 /* ---- STUB_PACK_VARLEN_HEX ------------------------------------- */
233 /* Format a variable length stream of hex bytes */
235 static char * pack_varlen_hex(
240 static unsigned char n[8] ;
249 while (i-- >= 0 ) /* unpack nibbles into a char array */
251 n[i] = value & 0x0f ;
254 i = 0 ; /* we had decrmented it to -1 */
255 while (n[i] == 0 ) i++ ; /* drop leading zeroes */
256 while (i++ < 8) *pkt++ = hexchars[n[i]] ; /* pack the number */
259 } /* pack_varlen_hex */
263 /* ------ STUB_UNPACK_VARLEN_HEX -------------------------------- */
264 /* Parse a stream of hex bytes which may be of variable length */
265 /* return the pointer to the next char */
266 /* modify a varparm containing the result */
267 /* A failure would look like a non-increment of the buffer pointer */
269 /* This unpacks hex strings that may have been packed using sprintf(%x) */
270 /* We assume some non-hex delimits them */
272 char * unpack_varlen_hex(
273 char * buff, /* packet to parse */
280 while (ishex(*buff,&nibble))
283 retval = retval << 4 ;
284 retval |= nibble & 0x0f ;
288 } /* stub_unpack_varlen_int */
291 /* ------ UNPACK_THREADID ------------------------------- */
292 /* A threadid is a 64 bit quantity */
294 #define BUFTHREADIDSIZ 16 /* encode 64 bits in 16 chars of hex */
296 static char * unpack_threadid(char * inbuf, threadref * id)
299 char * limit = inbuf + BUFTHREADIDSIZ ;
301 altref = (char *) id ;
303 while (inbuf < limit)
305 x = stubhex(*inbuf++) ;
306 y = stubhex(*inbuf++) ;
307 *altref++ = (x << 4) | y ;
310 } /* unpack_threadid */
314 /* Pack an integer use leading zeroes */
315 static char * pack_int(char * buf,int value)
317 buf = pack_hex_byte(buf,(value>> 24)& 0xff) ;
318 buf = pack_hex_byte(buf,(value >>16)& 0xff) ;
319 buf = pack_hex_byte(buf,(value >>8) & 0x0ff) ;
320 buf = pack_hex_byte(buf,(value & 0xff)) ;
325 /* -------- PACK_STRING ---------------------------------------------- */
326 /* This stupid string better not contain any funny characters */
327 /* Also, the GDB protocol will not cope with NULLs in the
328 string or at the end of it.
329 While is is posable to encapsulate the protocol in ays that
330 preclude filtering for # I am assuming this is a constraint.
333 static char * pack_raw_string(char * pkt,char * string)
336 while (0 != (ch = *string++)) *pkt++ = ch ;
340 static char * pack_string(
351 len = strlen(string) ;
353 if (len > 200 ) len = 200 ; /* Bigger than most GDB packets, junk??? */
354 pkt = pack_hex_byte(pkt,len) ;
358 if ((ch == '\0') || (ch == '#')) ch = '*' ; /* Protect encapsulation */
365 /* ----- STUB_PACK_THREADID --------------------------------------------- */
366 /* Convert a binary 64 bit threadid and pack it into a xmit buffer */
367 /* Return the advanced buffer pointer */
369 static char * pack_threadid(char * pkt, threadref * id)
372 unsigned char * altid ;
373 altid = (unsigned char *) id ;
374 limit = pkt + BUFTHREADIDSIZ ;
375 while (pkt < limit) pkt = pack_hex_byte(pkt,*altid++) ;
377 } /* stub_pack_threadid */
379 /* UNFORTUNATELY, not all of the extended debugging system has yet been
380 converted to 64 but thread references and process identifiers.
381 These routines do the conversion.
382 An array of bytes is the correct treatment of an opaque identifier.
383 ints have endian issues.
386 static void int_to_threadref(threadref * id, int value)
388 unsigned char * scan ;
389 scan = (unsigned char *) id ;
392 while (i--) *scan++ = 0 ;
394 *scan++ = (value >> 24) & 0xff ;
395 *scan++ = (value >> 16) & 0xff ;
396 *scan++ = (value >> 8) & 0xff ;
397 *scan++ = (value & 0xff) ;
400 static int threadref_to_int(threadref * ref)
403 unsigned char * scan ;
406 scan = (char *) ref ;
409 while (i-- > 0) value = (value << 8) | ((*scan++) & 0xff) ;
411 } /* threadref_to_int */
413 void copy_threadref(threadref * dest, threadref * src)
416 unsigned char * csrc, * cdest ;
417 csrc = (unsigned char *) src ;
418 cdest = (unsigned char *) dest ;
420 while (i--) *cdest++ = *csrc++ ;
429 unsigned char * srcp, * destp ;
431 srcp = (char *) src ;
432 destp = (char *) dest ;
435 while (i-- > 0 ) result &= (*srcp++ == *destp++) ? 1 : 0 ;
441 static char * Tpkt_threadtag = "thread:" ;
443 /* ----- STUB_PACK_TPKT_THREADID ------------------------------------ */
444 /* retreive, tag and insert a thread identifier into a T packet. */
445 /* Insert nothing if the thread identifier is not available */
447 char * stub_pack_Tpkt_threadid(char * pkt)
449 static threadref thread ;
450 int fmt = 0 ; /* old format */
451 PKT_TRACE("Tpkt-id","---") ;
452 if (dbg_currthread(&thread))
454 pkt = pack_raw_string(pkt,Tpkt_threadtag) ;
456 pkt = pack_threadid(pkt,&thread) ;
458 /* Until GDB lengthens its thread ids, we have to MASH
459 the threadid into somthing shorter. PLEASE FIX GDB */
460 pkt = pack_int(pkt,threadref_to_int(&thread)) ;
461 *pkt++ = ';' ; /* terminate variable length int */
462 *pkt = '\0' ; /* Null terminate to allow string to be printed, no++ */
464 PKT_TRACE("packedTpkt","--") ;
466 } /* stub_pack_Tpkt_threadid */
468 long stub_get_currthread (void)
472 if (dbg_currthread(&thread))
473 return threadref_to_int(&thread) ;
478 void stub_pkt_currthread(
487 if (dbg_currthread(&thread))
490 *outbuf++ = 'C' ; /* FIXME: Is this a reasonable code */
491 outbuf = pack_int(outbuf, threadref_to_int(&thread)) ; /* Short form */
493 else outbuf = stub_pack_nak(outbuf) ;
494 *outbuf = '\0' ; /* terminate response packet */
495 PKT_TRACE("stub_pkt_currthread(resp) ",base_out) ;
496 } /* stub_pkt_currthread */
498 /* ----- STUB_PKT_THREAD_ALIVE --------------------------------- */
499 /* Answer the thread alive query */
501 static int thread_alive (int id)
504 struct cygmon_thread_debug_info info ;
506 int_to_threadref(&thread, id) ;
507 if (dbg_threadinfo(&thread, &info) &&
514 void stub_pkt_thread_alive(char * inbuf,
518 char * prebuf = inbuf ;
521 if (prebuf != (inbuf = unpack_varlen_hex(inbuf,&result)))
523 if (thread_alive(result))
525 outbuf = stub_pack_ack(outbuf) ;
530 outbuf = stub_pack_nak(outbuf) ;
531 *outbuf = '\0' ; /* terminate the response message */
532 } /* stub_pkt_thread_alive */
536 /* ----- STUB_PKT_CHANGETHREAD ------------------------------- */
537 /* Switch the display of registers to that of a saved context */
539 /* Changing the context makes NO sense, although the packets define the
540 capability. Therefore, the option to change the context back does
541 call the function to change registers. Also, there is no
542 forced context switch.
543 'p' - New format, long long threadid, no special cases
544 'c' - Old format, id for continue, 32 bit threadid max, possably less
545 -1 means continue all threads
546 'g' - Old Format, id for general use (other than continue)
553 void stub_pkt_changethread(
561 PKT_TRACE("setthread-pkt ",inbuf) ;
563 /* Parse the incoming packet for a thread identifier */
564 switch (ch = *inbuf++ ) /* handle various packet formats */
566 case 'p' : /* New format: mode:8,threadid:64 */
567 inbuf = unpack_nibble(inbuf,&idefined) ;
568 inbuf = unpack_threadid(inbuf,&id) ; /* even if startflag */
570 case 'c' : /* old format , specify thread for continue */
571 if (inbuf[0] == '-' && inbuf[1] == '1') /* Hc-1 */
572 _gdb_cont_thread = 0 ;
574 inbuf = unpack_varlen_hex(inbuf, &_gdb_cont_thread) ;
576 if (_gdb_cont_thread == 0 || /* revert to any old thread */
577 thread_alive(_gdb_cont_thread)) /* specified thread is alive */
578 outbuf = stub_pack_ack(outbuf) ;
580 outbuf = stub_pack_nak(outbuf) ;
582 case 'g' : /* old format, specify thread for general operations */
583 /* OLD format: parse a variable length hex string */
584 /* OLD format consider special thread ids */
586 inbuf = unpack_varlen_hex(inbuf, &_gdb_general_thread) ;
587 int_to_threadref(&id, _gdb_general_thread) ;
588 switch (_gdb_general_thread)
590 case 0 : /* pick a thread, any thread */
591 idefined = 2 ; /* select original interrupted context */
593 case -1 : /* all threads */
597 idefined = 1 ; /* select the specified thread */
603 outbuf = stub_pack_nak(outbuf) ;
605 } /* handle various packet formats */
610 /* Packet not supported, already NAKed, no further action */
613 /* Switch back to interrupted context */
614 _registers = ®isters[0] ;
617 /* copy the saved registers into the backup registers */
618 stub_copy_registers(alt_registers,registers) ;
619 /* The OS will now update the values it has in a saved process context*/
620 if (dbg_getthreadreg(&id,NUMREGS,&alt_registers[0]))
622 /* switch the registers pointer */
623 _registers = &alt_registers[0] ;
624 outbuf = stub_pack_ack(outbuf) ;
627 outbuf = stub_pack_nak(outbuf) ;
630 /* switch to interrupted context */
631 outbuf = stub_pack_ack(outbuf) ;
634 outbuf = stub_pack_nak(outbuf) ;
637 *outbuf = '\0' ; /* Terminate response pkt */
638 } /* stub_pkt_changethread */
641 /* ---- STUB_PKT_GETTHREADLIST ------------------------------- */
642 /* Get a portion of the threadlist or process list */
643 /* This may be part of a multipacket transaction */
644 /* It would be hard to tell in the response packet the difference
645 between the end of list and an error in threadid encoding.
648 void stub_pkt_getthreadlist(char * inbuf,
655 int start_flag , batchsize , result , count ;
656 static threadref lastthread, nextthread ;
659 char * r_base = outbuf ;
661 PKT_TRACE("pkt_getthreadlist: ",inbuf) ;
664 inbuf = unpack_nibble(inbuf,&start_flag) ;
665 inbuf = unpack_byte(inbuf,&batchsize) ;
666 inbuf = unpack_threadid(inbuf,&lastthread) ; /* even if startflag */
668 /* Start building response packet */
669 limit = outbuf + (bufmax - BUFTHREADIDSIZ - 10) ; /* id output packing limit */
673 /* Default values for count and done fields, save ptr to repatch */
674 count_ptr = outbuf ; /* save to repatch count */
675 outbuf = pack_hex_byte(outbuf,0) ;
676 done_ptr = outbuf ; /* Backpatched later */
677 *outbuf++ = '0' ; /* Done = 0 by default */
678 outbuf = pack_threadid(outbuf,&lastthread) ;
680 /* Loop through the threadid packing */
681 while ((outbuf < limit) && (count < batchsize))
683 result = dbg_threadlist(start_flag,&lastthread,&nextthread) ;
684 start_flag = 0 ; /* redundant but effective */
686 { *done_ptr = '1' ; /* pack the done flag */
690 if (threadmatch(&lastthread,&nextthread))
692 output_string("FAIL: Threadlist, not incrementing\n") ;
698 outbuf = pack_threadid(outbuf,&nextthread) ;
699 copy_threadref(&lastthread,&nextthread) ;
701 pack_hex_byte(count_ptr,count) ;/* backpatch, Pack the count field */
703 PKT_TRACE("pkt_getthreadlist(resp) ",r_base) ;
704 } /* pkt_getthreadlist */
709 /* ----- STUB_PKT_GETTHREADINFO ---------------------------------------- */
710 /* Get the detailed information about a specific thread or process */
717 threadid:1, # always request threadid
724 void stub_pkt_getthreadinfo(
732 struct cygmon_thread_debug_info info ;
734 info.context_exists = 0 ;
735 info.thread_display = 0 ;
736 info.unique_thread_name = 0 ;
737 info.more_display = 0 ;
739 /* Assume the packet identification chars have already been
740 discarded by the packet demultiples routines */
741 PKT_TRACE("PKT getthreadinfo",inbuf) ;
743 inbuf = unpack_int(inbuf,&mask) ;
744 inbuf = unpack_threadid(inbuf,&thread) ;
746 result = dbg_threadinfo(&thread,&info) ; /* Make system call */
752 outbuf = pack_int(outbuf,mask) ;
753 outbuf = pack_threadid(outbuf,&info.thread_id) ; /* echo threadid */
754 if (mask & 2) /* context-exists */
756 outbuf = pack_int(outbuf,2) ; /* tag */
757 outbuf = pack_hex_byte(outbuf,2) ; /* length */
758 outbuf = pack_hex_byte(outbuf,info.context_exists) ;
760 if ((mask & 4) && info.thread_display)/* display */
762 outbuf = pack_int(outbuf,4) ; /* tag */
763 outbuf = pack_string(outbuf,info.thread_display) ;
765 if ((mask & 8) && info.unique_thread_name) /* unique_name */
767 outbuf = pack_int(outbuf,8) ;
768 outbuf = pack_string(outbuf,info.unique_thread_name) ;
770 if ((mask & 16) && info.more_display) /* more display */
772 outbuf = pack_int(outbuf,16) ; /* tag 16 */
773 outbuf = pack_string(outbuf,info.more_display) ;
778 PKT_TRACE("FAIL: dbg_threadinfo\n", "") ;
779 outbuf = stub_pack_nak(outbuf) ;
782 } /* stub_pkt_getthreadinfo */
784 int stub_lock_scheduler(int lock, /* 0 to unlock, 1 to lock */
785 int mode, /* 0 for step, 1 for continue */
786 long id) /* current thread */
790 int_to_threadref(&thread, id) ;
791 return dbg_scheduler(&thread, lock, mode) ;
796 /* ------ MATCHED GDB SIDE PACKET ENCODING AND PARSING ----------------- */
798 char * pack_nibble(char * buf, int nibble)
800 *buf++ = hexchars[(nibble & 0x0f)] ;
805 static char * unpack_short(char * buf,int * value)
807 *value = stub_unpack_int(buf,4) ;
811 static char * pack_short(
815 buf = pack_hex_byte(buf,(value >> 8) & 0xff) ;
816 buf = pack_hex_byte(buf,(value & 0xff)) ;
822 /* Generally, I dont bury xmit and receive calls inside packet formatters
829 /* ----- PACK_SETTHREAD_REQUEST ------------------------------------- */
830 /* Encoding: ??? decode gdb/remote.c
831 'Q':8,'p':8,idefined:8,threadid:32 ;
834 char * pack_setthread_request(
836 char fmt, /* c,g or, p */
838 threadref * threadid )
843 { /* pack the long form */
844 buf = pack_nibble(buf,idformat) ;
845 buf = pack_threadid(buf,threadid) ;
848 { /* pack the shorter form - Serious truncation */
849 /* There are reserved identifieds 0 , -1 */
850 int quickref = threadref_to_int(threadid) ;
851 buf = pack_varlen_hex(buf,quickref) ;
853 *buf++ = '\0' ; /* end_of_packet */
855 } /* pack_setthread_request */
859 /* -------- PACK_THREADLIST-REQUEST --------------------------------- */
860 /* Format: i'Q':8,i"L":8,initflag:8,batchsize:16,lastthreadid:32 */
863 char * pack_threadlist_request(
867 threadref * nextthread
872 pkt = pack_nibble(pkt,startflag) ; /* initflag 1 bytes */
873 pkt = pack_hex_byte(pkt,threadcount) ; /* threadcount 2 bytes */
874 pkt = pack_threadid(pkt,nextthread) ; /* 64 bit thread identifier */
877 } /* remote_threadlist_request */
882 /* ---------- PARSE_THREADLIST_RESPONSE ------------------------------------ */
883 /* Encoding: 'q':8,'M':8,count:16,done:8,argthreadid:64,(threadid:64)* */
885 int parse_threadlist_response(
887 threadref * original_echo,
888 threadref * resultlist,
892 int count, resultcount , done ;
895 /* assume the 'q' and 'M chars have been stripped */
896 PKT_TRACE("parse-threadlist-response ",pkt) ;
897 limit = pkt + (STUB_BUF_MAX - BUFTHREADIDSIZ) ; /* done parse past here */
898 pkt = unpack_byte(pkt,&count) ; /* count field */
899 pkt = unpack_nibble(pkt,&done) ;
900 /* The first threadid is the argument threadid */
901 pkt = unpack_threadid(pkt,original_echo) ; /* should match query packet */
902 while ((count-- > 0) && (pkt < limit))
904 pkt = unpack_threadid(pkt,resultlist++) ;
907 if (doneflag) *doneflag = done ;
908 return resultcount ; /* successvalue */
909 } /* parse_threadlist_response */
911 struct gdb_ext_thread_info
917 char more_display[256] ;
921 /* ----- PACK_THREAD_INFO_REQUEST -------------------------------- */
924 threadid:1, # always request threadid
931 /* Encoding: 'Q':8,'P':8,mask:32,threadid:64 */
933 char * pack_threadinfo_request(char * pkt,
940 pkt = pack_int(pkt,mode) ; /* mode */
941 pkt = pack_threadid(pkt,id) ; /* threadid */
942 *pkt = '\0' ; /* terminate */
944 } /* pack_thread_info_request */
948 static char * unpack_string(
953 while (length--) *dest++ = *src++ ;
956 } /* unpack_string */
959 void output_threadid(char * title,threadref * ref)
962 pack_threadid(&hexid[0],ref) ; /* Convert threead id into hex */
964 output_string(title) ;
965 output_string(&hexid[0]) ;
966 output_string("\n") ;
969 /* ------ REMOTE_UPK_THREAD_INFO_RESPONSE ------------------------------- */
970 /* Unpack the response of a detailed thread info packet */
971 /* Encoding: i'Q':8,i'R':8,argmask:16,threadid:64,(tag:8,length:16,data:x)* */
973 #define TAG_THREADID 1
975 #define TAG_DISPLAY 4
976 #define TAG_THREADNAME 8
977 #define TAG_MOREDISPLAY 16
980 int remote_upk_thread_info_response(
982 threadref * expectedref ,
983 struct gdb_ext_thread_info * info)
988 char * limit = pkt + 500 ; /* plausable parsing limit */
991 PKT_TRACE("upk-threadinfo ",pkt) ;
993 /* info->threadid = 0 ; FIXME: implement zero_threadref */
995 info->display[0] = '\0' ;
996 info->shortname[0] = '\0' ;
997 info->more_display[0] = '\0' ;
999 /* Assume the characters indicating the packet type have been stripped */
1000 pkt = unpack_int(pkt,&mask) ; /* arg mask */
1001 pkt = unpack_threadid(pkt , &ref) ;
1003 if (! threadmatch(&ref,expectedref))
1004 { /* This is an answer to a different request */
1005 output_string("FAIL Thread mismatch\n") ;
1006 output_threadid("ref ",&ref) ;
1007 output_threadid("expected ",expectedref) ;
1010 copy_threadref(&info->threadid,&ref) ;
1012 /* Loop on tagged fields , try to bail if somthing goes wrong */
1013 if (mask==0) output_string("OOPS NO MASK \n") ;
1015 while ((pkt < limit) && mask && *pkt) /* packets are terminated with nulls */
1017 pkt = unpack_int(pkt,&tag) ; /* tag */
1018 pkt = unpack_byte(pkt,&length) ; /* length */
1019 if (! (tag & mask)) /* tags out of synch with mask */
1021 output_string("FAIL: threadinfo tag mismatch\n") ;
1025 if (tag == TAG_THREADID)
1027 output_string("unpack THREADID\n") ;
1030 output_string("FAIL: length of threadid is not 16\n") ;
1034 pkt = unpack_threadid(pkt,&ref) ;
1035 mask = mask & ~ TAG_THREADID ;
1038 if (tag == TAG_EXISTS)
1040 info->active = stub_unpack_int(pkt,length) ;
1042 mask = mask & ~(TAG_EXISTS) ;
1045 output_string("FAIL: 'exists' length too long\n") ;
1051 if (tag == TAG_THREADNAME)
1053 pkt = unpack_string(pkt,&info->shortname[0],length) ;
1054 mask = mask & ~TAG_THREADNAME ;
1057 if (tag == TAG_DISPLAY)
1059 pkt = unpack_string(pkt,&info->display[0],length) ;
1060 mask = mask & ~TAG_DISPLAY ;
1063 if (tag == TAG_MOREDISPLAY)
1065 pkt = unpack_string(pkt,&info->more_display[0],length) ;
1066 mask = mask & ~TAG_MOREDISPLAY ;
1069 output_string("FAIL: unknown info tag\n") ;
1070 break ; /* Not a tag we know about */
1073 } /* parse-thread_info_response */
1076 /* ---- REMOTE_PACK_CURRTHREAD_REQUEST ---------------------------- */
1077 /* This is a request to emit the T packet */
1079 /* FORMAT: 'q':8,'C' */
1081 char * remote_pack_currthread_request(char * pkt )
1087 } /* remote_pack_currthread_request */
1090 /* ------- REMOTE_UPK_CURTHREAD_RESPONSE ----------------------- */
1091 /* Unpack the interesting part of a T packet */
1094 int remote_upk_currthread_response(
1096 int *thr ) /* Parse a T packet */
1099 PKT_TRACE("upk-currthreadresp ",pkt) ;
1103 static char threadtag[8] = "thread" ;
1109 /* Unpack as a t packet */
1110 while (((ch = *pkt++) != ':') /* scan for : thread */
1111 && (ch != '\0')) /* stop at end of packet */
1116 while ((ch = *pkt++) == threadtag[i++]) ;
1117 if (i == 8) /* string match "thread" */
1119 pkt = unpack_varlen_hex(pkt,&quickid) ;
1127 pkt = unpack_threadid(pkt, thr) ;
1131 } /* remote_upk_currthread_response */
1134 /* -------- REMOTE_UPK-SIMPLE_ACK --------------------------------- */
1135 /* Decode a response which is eother "OK" or "Enn"
1136 fillin error code, fillin pkfag-1== undef, 0==nak, 1 == ack ;
1137 return advanced packet pointer */
1140 char * remote_upk_simple_ack(
1147 int retval = -1 ; /* Undefined ACK , a protocol error */
1148 if (ch == 'E') /* NAK */
1150 buf = unpack_byte(buf,&lclerr) ;
1151 retval = 0 ; /* transaction failed, explicitly */
1154 if ((ch == 'O') && (*buf++ == 'K')) /* ACK */
1155 retval = 1 ; /* transaction succeeded */
1159 } /* remote-upk_simple_ack */
1162 /* -------- PACK_THREADALIVE_REQUEST ------------------------------- */
1164 char * pack_threadalive_request(
1166 threadref * threadid)
1169 buf = pack_threadid(buf,threadid) ;
1172 } /* pack_threadalive_request */
1174 #endif /* GDB_MOCKUP */
1176 /* ---------------------------------------------------------------------- */
1177 /* UNIT_TESTS SUBSECTION */
1178 /* ---------------------------------------------------------------------- */
1182 extern void output_string(char * message) ;
1183 static char test_req[400] ;
1184 static char t_response[400] ;
1188 /* ----- DISPLAY_THREAD_INFO ---------------------------------------------- */
1189 /* Use local cygmon string output utiities */
1191 void display_thread_info(struct gdb_ext_thread_info * info)
1194 output_threadid("Threadid: ",&info->threadid) ;
1196 output_string("Name: ") ; output_string(info->shortname) ; output_string("\n");
1197 /* format display state */
1198 output_string("State: ") ; output_string(info->display) ; output_string("\n") ;
1199 /* additional data */
1200 output_string("other: ");output_string(info->more_display);
1201 output_string("\n\n");
1202 } /* display_thread_info */
1205 /* --- CURRTHREAD-TEST -------------------------------------------- */
1206 static int currthread_test(threadref * thread)
1210 output_string("TEST: currthread\n") ;
1211 remote_pack_currthread_request(test_req) ;
1212 stub_pkt_currthread(test_req+2,t_response,STUB_BUF_MAX) ;
1213 result = remote_upk_currthread_response(t_response+2, &threadid) ;
1216 output_string("PASS getcurthread\n") ;
1217 /* FIXME: print the thread */
1220 output_string("FAIL getcurrthread\n") ;
1222 } /* currthread_test */
1224 /* ------ SETTHREAD_TEST ------------------------------------------- */
1225 /* use a known thread from previous test */
1227 static int setthread_test(threadref * thread)
1229 int result, errcode ;
1230 output_string("TEST: setthread\n") ;
1232 pack_setthread_request(test_req,'p',1,thread) ;
1233 stub_pkt_changethread(test_req,t_response,STUB_BUF_MAX) ;
1234 remote_upk_simple_ack(t_response,&result,&errcode) ;
1238 output_string("FAIL setthread\n") ;
1241 output_string("PASS setthread\n") ;
1244 output_string("FAIL setthread -unrecognized response\n") ;
1248 } /* setthread_test */
1251 /* ------ THREADACTIVE_TEST ---------------------- */
1252 /* use known thread */
1253 /* pack threadactive packet */
1254 /* process threadactive packet */
1255 /* parse threadactive response */
1259 int threadactive_test(threadref * thread)
1263 output_string("TEST: threadactive\n") ;
1264 pack_threadalive_request(test_req,thread) ;
1265 stub_pkt_thread_alive(test_req+1,t_response,STUB_BUF_MAX);
1266 remote_upk_simple_ack(t_response,&result,&errcode) ;
1270 output_string("FAIL threadalive\n") ;
1273 output_string("PASS threadalive\n") ;
1276 output_string("FAIL threadalive -unrecognized response\n") ;
1280 } /* threadactive_test */
1282 /* ------ REMOTE_GET_THREADINFO -------------------------------------- */
1283 int remote_get_threadinfo(
1284 threadref * threadid,
1285 int fieldset , /* TAG mask */
1286 struct gdb_ext_thread_info * info
1290 pack_threadinfo_request(test_req,fieldset,threadid) ;
1291 stub_pkt_getthreadinfo(test_req+2,t_response,STUB_BUF_MAX) ;
1292 result = remote_upk_thread_info_response(t_response+2,threadid,info) ;
1294 } /* remote_get-thrreadinfo */
1297 static struct gdb_ext_thread_info test_info ;
1299 static int get_and_display_threadinfo(threadref * thread)
1303 /* output_string("TEST: get and display threadinfo\n") ; */
1305 mode = TAG_THREADID | TAG_EXISTS | TAG_THREADNAME
1306 | TAG_MOREDISPLAY | TAG_DISPLAY ;
1307 result = remote_get_threadinfo(thread,mode,&test_info) ;
1308 if (result) display_thread_info(&test_info) ;
1309 #if 0 /* silent subtest */
1311 output_string("PASS: get_and_display threadinfo\n") ;
1313 output_string("FAIL: get_and_display threadinfo\n") ;
1316 } /* get-and-display-threadinfo */
1320 /* ----- THREADLIST_TEST ------------------------------------------ */
1321 #define TESTLISTSIZE 16
1323 static threadref test_threadlist[TESTLISTSIZE] ;
1325 static int threadlist_test(void)
1327 int done, i , result_count ;
1331 static threadref nextthread ;
1332 static threadref echo_nextthread ;
1334 output_string("TEST: threadlist\n") ;
1339 if (loopcount++ > 10)
1342 output_string("FAIL: Threadlist test -infinite loop-\n") ;
1345 pack_threadlist_request(test_req,startflag,TLRSIZ,&nextthread) ;
1346 startflag = 0 ; /* clear for later iterations */
1347 stub_pkt_getthreadlist(test_req+2,t_response,STUB_BUF_MAX);
1348 result_count = parse_threadlist_response(t_response+2,
1350 &test_threadlist[0],&done) ;
1351 if (! threadmatch(&echo_nextthread,&nextthread))
1353 output_string("FAIL: threadlist did not echo arg thread\n");
1357 if (result_count <= 0)
1360 { output_string("FAIL threadlist_test, failed to get list");
1365 if (result_count > TLRSIZ)
1367 output_string("FAIL: threadlist response longer than requested\n") ;
1371 /* Setup to resume next batch of thread references , set nestthread */
1372 copy_threadref(&nextthread,&test_threadlist[result_count-1]) ;
1373 /* output_threadid("last-of-batch",&nextthread) ; */
1375 while (result_count--)
1377 if (0) /* two display alternatives */
1378 output_threadid("truncatedisplay",&test_threadlist[i++]) ;
1380 get_and_display_threadinfo(&test_threadlist[i++]) ;
1385 output_string("FAIL: threadlist test\n") ;
1386 else output_string("PASS: Threadlist test\n") ;
1388 } /* threadlist_test */
1391 static threadref testthread ;
1394 int test_thread_support(void)
1397 output_string("TESTING Thread support infrastructure\n") ;
1398 stub_pack_Tpkt_threadid(test_req) ;
1399 PKT_TRACE("packing the threadid -> ",test_req) ;
1400 result &= currthread_test(&testthread) ;
1401 result &= get_and_display_threadinfo(&testthread) ;
1402 result &= threadlist_test() ;
1403 result &= setthread_test(&testthread) ;
1405 output_string("PASS: UNITTEST Thread support\n") ;
1407 output_string("FAIL: UNITTEST Thread support\n") ;
1409 } /* test-thread_support */
1410 #endif /* UNIT_TEST */
1413 #endif // ifdef CYGDBG_HAL_DEBUG_GDB_THREAD_SUPPORT...
1414 // #endif // __ECOS__