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.
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(target_register_t *dest,
133 target_register_t *src)
135 target_register_t *limit;
136 limit = dest + NUMREGS;
138 while (dest < limit) *dest++ = *src++;
142 void __stub_copy_registers(target_register_t *dest,
143 target_register_t *src)
145 stub_copy_registers(dest, src);
149 extern int stubhex(char ch);
151 /* ----- STUB_PACK_NAK ----------------------------------- */
152 /* Pack an error response into the response packet */
154 char *stub_pack_nak(char *outbuf)
160 } /* stub_pack_nak */
162 /* ----- STUB_PACK_ACK -------------------------- */
163 /* Pack an OK achnowledgement */
164 char *stub_pack_ack(char *outbuf)
169 } /* stub_pack_ack */
171 /* ------- STUB_UNPACK_INT ------------------------------- */
172 /* Unpack a few bytes and return its integer value */
173 /* This is where I wish functions could return several values
174 I would also advance the buffer pointer */
176 int stub_unpack_int(char *buff, int fieldlength)
181 { nibble = stubhex(*buff++);
184 if (fieldlength) retval = retval << 4;
187 } /* stub_unpack_int */
189 static char *unpack_byte(char *buf, int *value)
191 *value = stub_unpack_int(buf, 2);
195 static char *unpack_int(char *buf, int *value)
197 *value = stub_unpack_int(buf, 8);
201 /* We are NOT depending upon extensive libraries */
202 static int ishex(char ch, int *val)
204 if ((ch >= 'a') && (ch <= 'f')) {
205 *val = ch - 'a' + 10;
208 if ((ch >= 'A') && (ch <= 'F')) {
209 *val = ch - 'A' + 10;
212 if ((ch >= '0') && (ch <= '9')) {
219 static char *unpack_nibble(char *buf, int *val)
226 static const char hexchars[] = "0123456789abcdef";
228 static char *pack_hex_byte(char *pkt, unsigned char byte)
230 *pkt++ = hexchars[(byte >> 4) & 0xf];
231 *pkt++ = hexchars[(byte & 0xf)];
233 } /* pack_hex_byte */
236 /* ---- STUB_PACK_VARLEN_HEX ------------------------------------- */
237 /* Format a variable length stream of hex bytes */
239 static char *pack_varlen_hex(
244 static unsigned char n[8];
253 while (i-- >= 0 ) /* unpack nibbles into a char array */
258 i = 0; /* we had decrmented it to -1 */
259 while (n[i] == 0 ) i++; /* drop leading zeroes */
260 while (i++ < 8) *pkt++ = hexchars[n[i]]; /* pack the number */
263 } /* pack_varlen_hex */
267 /* ------ STUB_UNPACK_VARLEN_HEX -------------------------------- */
268 /* Parse a stream of hex bytes which may be of variable length */
269 /* return the pointer to the next char */
270 /* modify a varparm containing the result */
271 /* A failure would look like a non-increment of the buffer pointer */
273 /* This unpacks hex strings that may have been packed using sprintf(%x) */
274 /* We assume some non-hex delimits them */
276 char *unpack_varlen_hex(
277 char *buff, /* packet to parse */
284 while (ishex(*buff, &nibble))
287 retval = retval << 4;
288 retval |= nibble & 0x0f;
292 } /* stub_unpack_varlen_int */
295 /* ------ UNPACK_THREADID ------------------------------- */
296 /* A threadid is a 64 bit quantity */
298 #define BUFTHREADIDSIZ 16 /* encode 64 bits in 16 chars of hex */
300 static char *unpack_threadid(char *inbuf, threadref *id)
303 char *limit = inbuf + BUFTHREADIDSIZ;
307 while (inbuf < limit)
309 x = stubhex(*inbuf++);
310 y = stubhex(*inbuf++);
311 *altref++ = (x << 4) | y;
314 } /* unpack_threadid */
318 /* Pack an integer use leading zeroes */
319 static char *pack_int(char *buf, int value)
321 buf = pack_hex_byte(buf, (value >> 24) & 0xff);
322 buf = pack_hex_byte(buf, (value >> 16) & 0xff);
323 buf = pack_hex_byte(buf, (value >> 8) & 0x0ff);
324 buf = pack_hex_byte(buf, value & 0xff);
329 /* -------- PACK_STRING ---------------------------------------------- */
330 /* This stupid string better not contain any funny characters */
331 /* Also, the GDB protocol will not cope with NULLs in the
332 string or at the end of it.
333 While is is posable to encapsulate the protocol in ays that
334 preclude filtering for # I am assuming this is a constraint.
337 static char *pack_raw_string(char *pkt, char *string)
340 while (0 != (ch = *string++)) *pkt++ = ch;
344 static char *pack_string(
355 len = strlen(string);
357 if (len > 200 ) len = 200; /* Bigger than most GDB packets, junk??? */
358 pkt = pack_hex_byte(pkt, len);
362 if ((ch == '\0') || (ch == '#')) ch = '*'; /* Protect encapsulation */
369 /* ----- STUB_PACK_THREADID --------------------------------------------- */
370 /* Convert a binary 64 bit threadid and pack it into a xmit buffer */
371 /* Return the advanced buffer pointer */
373 static char *pack_threadid(char *pkt, threadref *id)
376 unsigned char *altid;
377 altid = (unsigned char *)id;
378 limit = pkt + BUFTHREADIDSIZ;
379 while (pkt < limit) pkt = pack_hex_byte(pkt, *altid++);
381 } /* stub_pack_threadid */
383 /* UNFORTUNATELY, not all of the extended debugging system has yet been
384 converted to 64 but thread references and process identifiers.
385 These routines do the conversion.
386 An array of bytes is the correct treatment of an opaque identifier.
387 ints have endian issues.
390 static void int_to_threadref(threadref *id, int value)
393 scan = (unsigned char *)id;
396 while (i--) *scan++ = 0;
398 *scan++ = (value >> 24) & 0xff;
399 *scan++ = (value >> 16) & 0xff;
400 *scan++ = (value >> 8) & 0xff;
401 *scan++ = (value & 0xff);
404 static int threadref_to_int(threadref *ref)
413 while (i-- > 0) value = (value << 8) | ((*scan++) & 0xff);
415 } /* threadref_to_int */
417 void copy_threadref(threadref *dest, threadref *src)
420 unsigned char *csrc, *cdest;
421 csrc = (unsigned char *)src;
422 cdest = (unsigned char *)dest;
424 while (i--) *cdest++ = *csrc++;
433 unsigned char *srcp, *destp;
436 destp = (char *)dest;
439 while (i-- > 0 ) result &= (*srcp++ == *destp++) ? 1 : 0;
445 static char *Tpkt_threadtag = "thread:";
447 /* ----- STUB_PACK_TPKT_THREADID ------------------------------------ */
448 /* retreive, tag and insert a thread identifier into a T packet. */
449 /* Insert nothing if the thread identifier is not available */
451 char *stub_pack_Tpkt_threadid(char *pkt)
453 static threadref thread;
454 int fmt = 0; /* old format */
455 PKT_TRACE("Tpkt-id", "---");
456 if (dbg_currthread(&thread))
458 pkt = pack_raw_string(pkt, Tpkt_threadtag);
460 pkt = pack_threadid(pkt, &thread);
462 /* Until GDB lengthens its thread ids, we have to MASH
463 the threadid into somthing shorter. PLEASE FIX GDB */
464 pkt = pack_int(pkt, threadref_to_int(&thread));
465 *pkt++ = ';' ; /* terminate variable length int */
466 *pkt = '\0'; /* Null terminate to allow string to be printed, no++ */
468 PKT_TRACE("packedTpkt", "--");
470 } /* stub_pack_Tpkt_threadid */
472 long stub_get_currthread (void)
476 if (dbg_currthread(&thread))
477 return threadref_to_int(&thread);
482 void stub_pkt_currthread(
491 if (dbg_currthread(&thread))
494 *outbuf++ = 'C'; /* FIXME: Is this a reasonable code */
495 outbuf = pack_int(outbuf, threadref_to_int(&thread)); /* Short form */
497 else outbuf = stub_pack_nak(outbuf);
498 *outbuf = '\0'; /* terminate response packet */
499 PKT_TRACE("stub_pkt_currthread(resp) ", base_out);
500 } /* stub_pkt_currthread */
502 /* ----- STUB_PKT_THREAD_ALIVE --------------------------------- */
503 /* Answer the thread alive query */
505 static int thread_alive (int id)
508 struct cygmon_thread_debug_info info;
510 int_to_threadref(&thread, id);
511 if (dbg_threadinfo(&thread, &info) &&
518 void stub_pkt_thread_alive(char *inbuf,
522 char *prebuf = inbuf;
525 if (prebuf != (inbuf = unpack_varlen_hex(inbuf, &result)))
527 if (thread_alive(result))
529 outbuf = stub_pack_ack(outbuf);
534 outbuf = stub_pack_nak(outbuf);
535 *outbuf = '\0'; /* terminate the response message */
536 } /* stub_pkt_thread_alive */
540 /* ----- STUB_PKT_CHANGETHREAD ------------------------------- */
541 /* Switch the display of registers to that of a saved context */
543 /* Changing the context makes NO sense, although the packets define the
544 capability. Therefore, the option to change the context back does
545 call the function to change registers. Also, there is no
546 forced context switch.
547 'p' - New format, long long threadid, no special cases
548 'c' - Old format, id for continue, 32 bit threadid max, possably less
549 -1 means continue all threads
550 'g' - Old Format, id for general use (other than continue)
557 void stub_pkt_changethread(
565 PKT_TRACE("setthread-pkt ", inbuf);
567 /* Parse the incoming packet for a thread identifier */
568 switch (ch = *inbuf++ ) /* handle various packet formats */
570 case 'p' : /* New format: mode:8, threadid:64 */
571 inbuf = unpack_nibble(inbuf, &idefined);
572 inbuf = unpack_threadid(inbuf, &id); /* even if startflag */
574 case 'c' : /* old format, specify thread for continue */
575 if (inbuf[0] == '-' && inbuf[1] == '1') /* Hc-1 */
576 _gdb_cont_thread = 0;
578 inbuf = unpack_varlen_hex(inbuf, &_gdb_cont_thread);
580 if (_gdb_cont_thread == 0 || /* revert to any old thread */
581 thread_alive(_gdb_cont_thread)) /* specified thread is alive */
582 outbuf = stub_pack_ack(outbuf);
584 outbuf = stub_pack_nak(outbuf);
586 case 'g' : /* old format, specify thread for general operations */
587 /* OLD format: parse a variable length hex string */
588 /* OLD format consider special thread ids */
590 inbuf = unpack_varlen_hex(inbuf, &_gdb_general_thread);
591 int_to_threadref(&id, _gdb_general_thread);
592 switch (_gdb_general_thread)
594 case 0 : /* pick a thread, any thread */
595 idefined = 2; /* select original interrupted context */
597 case -1 : /* all threads */
601 idefined = 1; /* select the specified thread */
607 outbuf = stub_pack_nak(outbuf);
609 } /* handle various packet formats */
614 /* Packet not supported, already NAKed, no further action */
617 /* Switch back to interrupted context */
618 _registers = ®isters[0];
621 /* copy the saved registers into the backup registers */
622 stub_copy_registers(alt_registers, registers);
623 /* The OS will now update the values it has in a saved process context*/
624 if (dbg_getthreadreg(&id, NUMREGS, &alt_registers[0]))
626 /* switch the registers pointer */
627 _registers = &alt_registers[0];
628 outbuf = stub_pack_ack(outbuf);
631 outbuf = stub_pack_nak(outbuf);
634 /* switch to interrupted context */
635 outbuf = stub_pack_ack(outbuf);
638 outbuf = stub_pack_nak(outbuf);
641 *outbuf = '\0'; /* Terminate response pkt */
642 } /* stub_pkt_changethread */
645 /* ---- STUB_PKT_GETTHREADLIST ------------------------------- */
646 /* Get a portion of the threadlist or process list */
647 /* This may be part of a multipacket transaction */
648 /* It would be hard to tell in the response packet the difference
649 between the end of list and an error in threadid encoding.
652 void stub_pkt_getthreadlist(char *inbuf,
659 int start_flag = 0, batchsize, result, count;
660 static threadref lastthread, nextthread;
663 char *r_base = outbuf;
665 PKT_TRACE("pkt_getthreadlist: ", inbuf);
668 inbuf = unpack_nibble(inbuf, &start_flag);
669 inbuf = unpack_byte(inbuf, &batchsize);
670 inbuf = unpack_threadid(inbuf, &lastthread); /* even if startflag */
672 /* Start building response packet */
673 limit = outbuf + (bufmax - BUFTHREADIDSIZ - 10); /* id output packing limit */
677 /* Default values for count and done fields, save ptr to repatch */
678 count_ptr = outbuf; /* save to repatch count */
679 outbuf = pack_hex_byte(outbuf, 0);
680 done_ptr = outbuf; /* Backpatched later */
681 *outbuf++ = '0'; /* Done = 0 by default */
682 outbuf = pack_threadid(outbuf, &lastthread);
684 /* Loop through the threadid packing */
685 while ((outbuf < limit) && (count < batchsize)) {
686 result = dbg_threadlist(start_flag, &lastthread, &nextthread);
687 start_flag = 0; /* redundant but effective */
689 *done_ptr = '1'; /* pack the done flag */
693 if (threadmatch(&lastthread, &nextthread)) {
694 output_string("FAIL: Threadlist, not incrementing\n");
700 outbuf = pack_threadid(outbuf, &nextthread);
701 copy_threadref(&lastthread, &nextthread);
703 pack_hex_byte(count_ptr, count);/* backpatch, Pack the count field */
705 PKT_TRACE("pkt_getthreadlist(resp) ", r_base);
706 } /* pkt_getthreadlist */
711 /* ----- STUB_PKT_GETTHREADINFO ---------------------------------------- */
712 /* Get the detailed information about a specific thread or process */
716 'Q':8, 'P':8, mask:16
719 threadid:1, # always request threadid
726 void stub_pkt_getthreadinfo(
734 struct cygmon_thread_debug_info info;
736 info.context_exists = 0;
737 info.thread_display = 0;
738 info.unique_thread_name = 0;
739 info.more_display = 0;
741 /* Assume the packet identification chars have already been
742 discarded by the packet demultiples routines */
743 PKT_TRACE("PKT getthreadinfo", inbuf);
745 inbuf = unpack_int(inbuf, &mask);
746 inbuf = unpack_threadid(inbuf, &thread);
748 result = dbg_threadinfo(&thread, &info); /* Make system call */
754 outbuf = pack_int(outbuf, mask);
755 outbuf = pack_threadid(outbuf, &info.thread_id); /* echo threadid */
756 if (mask & 2) /* context-exists */
758 outbuf = pack_int(outbuf, 2); /* tag */
759 outbuf = pack_hex_byte(outbuf, 2); /* length */
760 outbuf = pack_hex_byte(outbuf, info.context_exists);
762 if ((mask & 4) && info.thread_display)/* display */
764 outbuf = pack_int(outbuf, 4); /* tag */
765 outbuf = pack_string(outbuf, info.thread_display);
767 if ((mask & 8) && info.unique_thread_name) /* unique_name */
769 outbuf = pack_int(outbuf, 8);
770 outbuf = pack_string(outbuf, info.unique_thread_name);
772 if ((mask & 16) && info.more_display) /* more display */
774 outbuf = pack_int(outbuf, 16); /* tag 16 */
775 outbuf = pack_string(outbuf, info.more_display);
780 PKT_TRACE("FAIL: dbg_threadinfo\n", "");
781 outbuf = stub_pack_nak(outbuf);
784 } /* stub_pkt_getthreadinfo */
786 int stub_lock_scheduler(int lock, /* 0 to unlock, 1 to lock */
787 int mode, /* 0 for step, 1 for continue */
788 long id) /* current thread */
792 int_to_threadref(&thread, id);
793 return dbg_scheduler(&thread, lock, mode);
798 /* ------ MATCHED GDB SIDE PACKET ENCODING AND PARSING ----------------- */
800 char *pack_nibble(char *buf, int nibble)
802 *buf++ = hexchars[(nibble & 0x0f)];
807 static char *unpack_short(char *buf, int *value)
809 *value = stub_unpack_int(buf, 4);
813 static char *pack_short(
817 buf = pack_hex_byte(buf, (value >> 8) & 0xff);
818 buf = pack_hex_byte(buf, (value & 0xff));
824 /* Generally, I dont bury xmit and receive calls inside packet formatters
831 /* ----- PACK_SETTHREAD_REQUEST ------------------------------------- */
832 /* Encoding: ??? decode gdb/remote.c
833 'Q':8, 'p':8, idefined:8, threadid:32;
836 char *pack_setthread_request(
838 char fmt, /* c, g or, p */
840 threadref * threadid )
845 { /* pack the long form */
846 buf = pack_nibble(buf, idformat);
847 buf = pack_threadid(buf, threadid) ;
850 { /* pack the shorter form - Serious truncation */
851 /* There are reserved identifieds 0, -1 */
852 int quickref = threadref_to_int(threadid);
853 buf = pack_varlen_hex(buf, quickref);
855 *buf++ = '\0'; /* end_of_packet */
857 } /* pack_setthread_request */
861 /* -------- PACK_THREADLIST-REQUEST --------------------------------- */
862 /* Format: i'Q':8, i"L":8, initflag:8, batchsize:16, lastthreadid:32 */
865 char *pack_threadlist_request(
869 threadref *nextthread
874 pkt = pack_nibble(pkt, startflag); /* initflag 1 bytes */
875 pkt = pack_hex_byte(pkt, threadcount); /* threadcount 2 bytes */
876 pkt = pack_threadid(pkt, nextthread); /* 64 bit thread identifier */
879 } /* remote_threadlist_request */
884 /* ---------- PARSE_THREADLIST_RESPONSE ------------------------------------ */
885 /* Encoding: 'q':8, 'M':8, count:16, done:8, argthreadid:64, (threadid:64)* */
887 int parse_threadlist_response(
889 threadref *original_echo,
890 threadref *resultlist,
894 int count, resultcount, done;
897 /* assume the 'q' and 'M chars have been stripped */
898 PKT_TRACE("parse-threadlist-response ", pkt);
899 limit = pkt + (STUB_BUF_MAX - BUFTHREADIDSIZ); /* done parse past here */
900 pkt = unpack_byte(pkt, &count) ; /* count field */
901 pkt = unpack_nibble(pkt, &done);
902 /* The first threadid is the argument threadid */
903 pkt = unpack_threadid(pkt, original_echo); /* should match query packet */
904 while ((count-- > 0) && (pkt < limit))
906 pkt = unpack_threadid(pkt, resultlist++);
909 if (doneflag) *doneflag = done;
910 return resultcount; /* successvalue */
911 } /* parse_threadlist_response */
913 struct gdb_ext_thread_info
919 char more_display[256];
923 /* ----- PACK_THREAD_INFO_REQUEST -------------------------------- */
926 threadid:1, # always request threadid
933 /* Encoding: 'Q':8, 'P':8, mask:32, threadid:64 */
935 char *pack_threadinfo_request(char *pkt,
942 pkt = pack_int(pkt, mode); /* mode */
943 pkt = pack_threadid(pkt, id); /* threadid */
944 *pkt = '\0'; /* terminate */
946 } /* pack_thread_info_request */
950 static char *unpack_string(
955 while (length--) *dest++ = *src++;
958 } /* unpack_string */
961 void output_threadid(char *title, threadref *ref)
964 pack_threadid(&hexid[0], ref); /* Convert threead id into hex */
966 output_string(title);
967 output_string(&hexid[0]);
971 /* ------ REMOTE_UPK_THREAD_INFO_RESPONSE ------------------------------- */
972 /* Unpack the response of a detailed thread info packet */
973 /* Encoding: i'Q':8, i'R':8, argmask:16, threadid:64, (tag:8, length:16, data:x)* */
975 #define TAG_THREADID 1
977 #define TAG_DISPLAY 4
978 #define TAG_THREADNAME 8
979 #define TAG_MOREDISPLAY 16
982 int remote_upk_thread_info_response(
984 threadref *expectedref,
985 struct gdb_ext_thread_info *info)
990 char *limit = pkt + 500; /* plausable parsing limit */
993 PKT_TRACE("upk-threadinfo ", pkt);
995 /* info->threadid = 0; FIXME: implement zero_threadref */
997 info->display[0] = '\0';
998 info->shortname[0] = '\0';
999 info->more_display[0] = '\0';
1001 /* Assume the characters indicating the packet type have been stripped */
1002 pkt = unpack_int(pkt, &mask); /* arg mask */
1003 pkt = unpack_threadid(pkt, &ref);
1005 if (! threadmatch(&ref, expectedref))
1006 { /* This is an answer to a different request */
1007 output_string("FAIL Thread mismatch\n");
1008 output_threadid("ref ", &ref);
1009 output_threadid("expected ", expectedref);
1012 copy_threadref(&info->threadid, &ref);
1014 /* Loop on tagged fields, try to bail if somthing goes wrong */
1015 if (mask==0) output_string("OOPS NO MASK \n");
1017 while ((pkt < limit) && mask && *pkt) /* packets are terminated with nulls */
1019 pkt = unpack_int(pkt, &tag); /* tag */
1020 pkt = unpack_byte(pkt, &length); /* length */
1021 if (! (tag & mask)) /* tags out of synch with mask */
1023 output_string("FAIL: threadinfo tag mismatch\n");
1027 if (tag == TAG_THREADID)
1029 output_string("unpack THREADID\n");
1032 output_string("FAIL: length of threadid is not 16\n");
1036 pkt = unpack_threadid(pkt, &ref);
1037 mask = mask & ~ TAG_THREADID;
1040 if (tag == TAG_EXISTS)
1042 info->active = stub_unpack_int(pkt, length);
1044 mask = mask & ~(TAG_EXISTS);
1047 output_string("FAIL: 'exists' length too long\n");
1053 if (tag == TAG_THREADNAME)
1055 pkt = unpack_string(pkt, &info->shortname[0], length);
1056 mask = mask & ~TAG_THREADNAME;
1059 if (tag == TAG_DISPLAY)
1061 pkt = unpack_string(pkt, &info->display[0], length);
1062 mask = mask & ~TAG_DISPLAY;
1065 if (tag == TAG_MOREDISPLAY)
1067 pkt = unpack_string(pkt, &info->more_display[0], length);
1068 mask = mask & ~TAG_MOREDISPLAY;
1071 output_string("FAIL: unknown info tag\n");
1072 break; /* Not a tag we know about */
1075 } /* parse-thread_info_response */
1078 /* ---- REMOTE_PACK_CURRTHREAD_REQUEST ---------------------------- */
1079 /* This is a request to emit the T packet */
1081 /* FORMAT: 'q':8, 'C' */
1083 char *remote_pack_currthread_request(char *pkt )
1089 } /* remote_pack_currthread_request */
1092 /* ------- REMOTE_UPK_CURTHREAD_RESPONSE ----------------------- */
1093 /* Unpack the interesting part of a T packet */
1096 int remote_upk_currthread_response(
1098 int *thr ) /* Parse a T packet */
1101 PKT_TRACE("upk-currthreadresp ", pkt);
1105 static char threadtag[8] = "thread";
1111 /* Unpack as a t packet */
1112 while (((ch = *pkt++) != ':') /* scan for : thread */
1113 && (ch != '\0')) /* stop at end of packet */
1118 while ((ch = *pkt++) == threadtag[i++]);
1119 if (i == 8) /* string match "thread" */
1121 pkt = unpack_varlen_hex(pkt, &quickid);
1129 pkt = unpack_threadid(pkt, thr);
1133 } /* remote_upk_currthread_response */
1136 /* -------- REMOTE_UPK-SIMPLE_ACK --------------------------------- */
1137 /* Decode a response which is eother "OK" or "Enn"
1138 fillin error code, fillin pkfag-1== undef, 0==nak, 1 == ack;
1139 return advanced packet pointer */
1142 char *remote_upk_simple_ack(
1149 int retval = -1; /* Undefined ACK, a protocol error */
1150 if (ch == 'E') /* NAK */
1152 buf = unpack_byte(buf, &lclerr);
1153 retval = 0; /* transaction failed, explicitly */
1156 if ((ch == 'O') && (*buf++ == 'K')) /* ACK */
1157 retval = 1; /* transaction succeeded */
1161 } /* remote-upk_simple_ack */
1164 /* -------- PACK_THREADALIVE_REQUEST ------------------------------- */
1166 char *pack_threadalive_request(
1168 threadref *threadid)
1171 buf = pack_threadid(buf, threadid);
1174 } /* pack_threadalive_request */
1176 #endif /* GDB_MOCKUP */
1178 /* ---------------------------------------------------------------------- */
1179 /* UNIT_TESTS SUBSECTION */
1180 /* ---------------------------------------------------------------------- */
1184 extern void output_string(char *message);
1185 static char test_req[400];
1186 static char t_response[400];
1190 /* ----- DISPLAY_THREAD_INFO ---------------------------------------------- */
1191 /* Use local cygmon string output utiities */
1193 void display_thread_info(struct gdb_ext_thread_info *info)
1196 output_threadid("Threadid: ", &info->threadid);
1198 output_string("Name: "); output_string(info->shortname); output_string("\n");
1199 /* format display state */
1200 output_string("State: "); output_string(info->display); output_string("\n");
1201 /* additional data */
1202 output_string("other: ");output_string(info->more_display);
1203 output_string("\n\n");
1204 } /* display_thread_info */
1207 /* --- CURRTHREAD-TEST -------------------------------------------- */
1208 static int currthread_test(threadref *thread)
1212 output_string("TEST: currthread\n");
1213 remote_pack_currthread_request(test_req);
1214 stub_pkt_currthread(test_req+2, t_response, STUB_BUF_MAX);
1215 result = remote_upk_currthread_response(t_response+2, &threadid);
1218 output_string("PASS getcurthread\n");
1219 /* FIXME: print the thread */
1222 output_string("FAIL getcurrthread\n");
1224 } /* currthread_test */
1226 /* ------ SETTHREAD_TEST ------------------------------------------- */
1227 /* use a known thread from previous test */
1229 static int setthread_test(threadref *thread)
1231 int result, errcode;
1232 output_string("TEST: setthread\n");
1234 pack_setthread_request(test_req, 'p', 1, thread);
1235 stub_pkt_changethread(test_req, t_response, STUB_BUF_MAX);
1236 remote_upk_simple_ack(t_response, &result, &errcode);
1240 output_string("FAIL setthread\n");
1243 output_string("PASS setthread\n");
1246 output_string("FAIL setthread -unrecognized response\n");
1250 } /* setthread_test */
1253 /* ------ THREADACTIVE_TEST ---------------------- */
1254 /* use known thread */
1255 /* pack threadactive packet */
1256 /* process threadactive packet */
1257 /* parse threadactive response */
1261 int threadactive_test(threadref *thread)
1265 output_string("TEST: threadactive\n");
1266 pack_threadalive_request(test_req, thread);
1267 stub_pkt_thread_alive(test_req+1, t_response, STUB_BUF_MAX);
1268 remote_upk_simple_ack(t_response, &result, &errcode);
1272 output_string("FAIL threadalive\n");
1275 output_string("PASS threadalive\n");
1278 output_string("FAIL threadalive -unrecognized response\n");
1282 } /* threadactive_test */
1284 /* ------ REMOTE_GET_THREADINFO -------------------------------------- */
1285 int remote_get_threadinfo(
1286 threadref *threadid,
1287 int fieldset, /* TAG mask */
1288 struct gdb_ext_thread_info *info
1292 pack_threadinfo_request(test_req, fieldset, threadid);
1293 stub_pkt_getthreadinfo(test_req+2, t_response, STUB_BUF_MAX);
1294 result = remote_upk_thread_info_response(t_response+2, threadid, info);
1296 } /* remote_get-thrreadinfo */
1299 static struct gdb_ext_thread_info test_info;
1301 static int get_and_display_threadinfo(threadref *thread)
1305 /* output_string("TEST: get and display threadinfo\n"); */
1307 mode = TAG_THREADID | TAG_EXISTS | TAG_THREADNAME
1308 | TAG_MOREDISPLAY | TAG_DISPLAY;
1309 result = remote_get_threadinfo(thread, mode, &test_info);
1310 if (result) display_thread_info(&test_info);
1311 #if 0 /* silent subtest */
1313 output_string("PASS: get_and_display threadinfo\n");
1315 output_string("FAIL: get_and_display threadinfo\n");
1318 } /* get-and-display-threadinfo */
1322 /* ----- THREADLIST_TEST ------------------------------------------ */
1323 #define TESTLISTSIZE 16
1325 static threadref test_threadlist[TESTLISTSIZE];
1327 static int threadlist_test(void)
1329 int done, i, result_count;
1333 static threadref nextthread;
1334 static threadref echo_nextthread;
1336 output_string("TEST: threadlist\n");
1340 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)) {
1352 output_string("FAIL: threadlist did not echo arg thread\n");
1356 if (result_count <= 0) {
1358 { output_string("FAIL threadlist_test, failed to get list");
1363 if (result_count > TLRSIZ) {
1364 output_string("FAIL: threadlist response longer than requested\n");
1368 /* Setup to resume next batch of thread references, set nestthread */
1369 copy_threadref(&nextthread, &test_threadlist[result_count-1]);
1370 /* output_threadid("last-of-batch", &nextthread); */
1372 while (result_count--) {
1373 if (0) /* two display alternatives */
1374 output_threadid("truncatedisplay", &test_threadlist[i++]);
1376 get_and_display_threadinfo(&test_threadlist[i++]);
1381 output_string("FAIL: threadlist test\n");
1382 else output_string("PASS: Threadlist test\n");
1384 } /* threadlist_test */
1387 static threadref testthread;
1390 int test_thread_support(void)
1393 output_string("TESTING Thread support infrastructure\n");
1394 stub_pack_Tpkt_threadid(test_req);
1395 PKT_TRACE("packing the threadid -> ", test_req);
1396 result &= currthread_test(&testthread);
1397 result &= get_and_display_threadinfo(&testthread);
1398 result &= threadlist_test();
1399 result &= setthread_test(&testthread);
1401 output_string("PASS: UNITTEST Thread support\n");
1403 output_string("FAIL: UNITTEST Thread support\n");
1405 } /* test-thread_support */
1406 #endif /* UNIT_TEST */
1409 #endif // ifdef CYGDBG_HAL_DEBUG_GDB_THREAD_SUPPORT...
1410 // #endif // __ECOS__