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