|
0
|
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 = ®isters[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... |