diff options
Diffstat (limited to 'gdb/remote.c')
-rw-r--r-- | gdb/remote.c | 1080 |
1 files changed, 1060 insertions, 20 deletions
diff --git a/gdb/remote.c b/gdb/remote.c index d51c08a..ab0f470 100644 --- a/gdb/remote.c +++ b/gdb/remote.c @@ -209,11 +209,11 @@ static int remote_write_bytes PARAMS ((CORE_ADDR memaddr, static int remote_read_bytes PARAMS ((CORE_ADDR memaddr, char *myaddr, int len)); -static void remote_files_info PARAMS ((struct target_ops *ignore)); +static void remote_files_info PARAMS ((struct target_ops * ignore)); -static int remote_xfer_memory PARAMS ((CORE_ADDR memaddr, char *myaddr, +static int remote_xfer_memory PARAMS ((CORE_ADDR memaddr, char * myaddr, int len, int should_write, - struct target_ops *target)); + struct target_ops * target)); static void remote_prepare_to_store PARAMS ((void)); @@ -248,7 +248,7 @@ static void remote_send PARAMS ((char *buf)); static int readchar PARAMS ((int timeout)); -static int remote_wait PARAMS ((int pid, struct target_waitstatus *status)); +static int remote_wait PARAMS ((int pid, struct target_waitstatus * status)); static void remote_kill PARAMS ((void)); @@ -302,6 +302,8 @@ extern int putpkt PARAMS ((char *buf)); void remote_console_output PARAMS ((char *)); +/* Define the target subroutine names */ + void open_remote_target PARAMS ((char *, int, struct target_ops *, int)); void _initialize_remote PARAMS ((void)); @@ -358,6 +360,7 @@ static serial_t remote_desc = NULL; #define PBUFSIZ (REGISTER_BYTES * 2 + 32) #endif + /* This variable sets the number of bytes to be written to the target in a single packet. Normally PBUFSIZ is satisfactory, but some targets need smaller values (perhaps because the receiving end @@ -396,11 +399,174 @@ void (*target_resume_hook) PARAMS ((void)); void (*target_wait_loop_hook) PARAMS ((void)); +/* ------- REMOTE Thread (or) Process support ----------------------- */ + + + +static int +stub_unpack_int PARAMS ((char *buff, int fieldlength)); + +char * + unpack_varlen_hex PARAMS ((char *buff, int *result)); + + +static char * + unpack_nibble PARAMS ((char *buf, int *val)); + +static char * + unpack_nibble PARAMS ((char *buf, int *val)); + +static char * + pack_hex_byte PARAMS ((char *pkt, unsigned char byte)); + +static char * + unpack_byte PARAMS ((char *buf, int *value)); + +static char * + pack_int PARAMS ((char *buf, int value)); + +static char * + unpack_int PARAMS ((char *buf, int *value)); + +static char * + pack_string PARAMS ((char *pkt, char *string)); + +static char * + unpack_string PARAMS ((char *src, char *dest, int length)); + +static char * + pack_threadid PARAMS ((char *pkt, threadref * id)); + +static char * + unpack_threadid PARAMS ((char *inbuf, threadref * id)); + +void +int_to_threadref PARAMS ((threadref * id, int value)); + + +int +threadref_to_int PARAMS ((threadref * ref)); + +static void +copy_threadref PARAMS ((threadref * dest, threadref * src)); + +static int +threadmatch PARAMS ((threadref * dest, threadref * src)); + + +static char * + pack_threadinfo_request PARAMS ((char *pkt, + int mode, + threadref * id)); + +static int +remote_unpack_thread_info_response PARAMS (( + char *pkt, + threadref * expectedref, + struct gdb_ext_thread_info * info)); + + +int +remote_get_threadinfo PARAMS (( + threadref * threadid, + int fieldset, /* TAG mask */ + struct gdb_ext_thread_info * info)); + +int +adapt_remote_get_threadinfo PARAMS (( + gdb_threadref * ref, + int selection, + struct gdb_ext_thread_info * info)); +static char * + pack_threadlist_request PARAMS (( + char *pkt, + int startflag, + int threadcount, + threadref * nextthread)); + +static int +parse_threadlist_response PARAMS (( + char *pkt, + int result_limit, + threadref * original_echo, + threadref * resultlist, + int *doneflag)); +static int +remote_get_threadlist PARAMS (( + int startflag, + threadref * nextthread, + int result_limit, + int *done, + int *result_count, + threadref * threadlist)); + + + +static int +remote_newthread_step PARAMS (( + threadref * ref, + void *context)); + +int +remote_find_new_threads PARAMS ((void)) ; + +static void +threadalive_test PARAMS ((char *cmd, int tty)); + + +static void +threadset_test_cmd PARAMS ((char *cmd, int tty)); + +static void +threadlist_test_cmd PARAMS ((char *cmd, + int tty)); + +void +display_thread_info PARAMS ((struct gdb_ext_thread_info * info)); + + +int +get_and_display_threadinfo PARAMS ((threadref * ref)); + + +static void +threadinfo_test_cmd PARAMS ((char *cmd, + int tty)); + +static int +thread_display_step PARAMS (( + threadref * ref, + void *context)); + + +static void +threadlist_update_test_cmd PARAMS ((char *cmd, + int tty)); + + +static void +init_remote_threadtests PARAMS ((void)); + /* These are the threads which we last sent to the remote system. -1 for all or -2 for not sent yet. */ int general_thread; int cont_thread; +/* Call this function as a result of + 1) A halt indication (T packet) containing a thread id + 2) A direct query of currthread + 3) Successful execution of set thread + */ + +static void +record_currthread (currthread) + int currthread; +{ + inferior_pid = currthread; + general_thread = currthread; + cont_thread = currthread; +} + static void set_thread (th, gen) int th; @@ -439,14 +605,870 @@ remote_thread_alive (th) buf[0] = 'T'; if (th < 0) - sprintf (&buf[1], "-%x", -th); + sprintf (&buf[1], "-%08x", -th); else - sprintf (&buf[1], "%x", th); + sprintf (&buf[1], "%08x", th); putpkt (buf); getpkt (buf, 0); return (buf[0] == 'O' && buf[1] == 'K'); } +/* + About these extended threadlist and threadinfo packets. + They are variable length packets but, the fields within them + are often fixed length. + They are redundent enough to send over UDP as is the remote protocol + in general. + There is a matching unit test module in libstub. + */ + + +#define BUF_THREAD_ID_SIZE (OPAQUETHREADBYTES*2) +/* encode 64 bits in 16 chars of hex */ + + +static const char hexchars[] = "0123456789abcdef"; + +static int +ishex (ch, val) + char ch; + int *val; +{ + if ((ch >= 'a') && (ch <= 'f')) + { + *val = ch - 'a' + 10; + return 1; + } + if ((ch >= 'A') && (ch <= 'F')) + { + *val = ch - 'A' + 10; + return 1; + } + if ((ch >= '0') && (ch <= '9')) + { + *val = ch - '0'; + return 1; + } + return 0; +} + +static int +stubhex (ch) + unsigned char ch; +{ + if (ch >= 'a' && ch <= 'f') + return ch - 'a' + 10; + if (ch >= '0' && ch <= '9') + return ch - '0'; + if (ch >= 'A' && ch <= 'F') + return ch - 'A' + 10; + return -1; +} + +static int +stub_unpack_int (buff, fieldlength) + char *buff; + int fieldlength; +{ + int retval = 0; + int nibble; + while (fieldlength) + { + nibble = stubhex (*buff++); + retval |= nibble; + fieldlength--; + if (fieldlength) + retval = retval << 4; + } + return retval; +} + +char * +unpack_varlen_hex (buff, result) + char *buff; /* packet to parse */ + int *result; +{ + int nibble; + int retval; + retval = 0; + + while (ishex (*buff, &nibble)) + { + buff++; + retval = retval << 4; + retval |= nibble & 0x0f; + } + *result = retval; + return buff; +} + +static char * +unpack_nibble (buf, val) + char *buf; + int *val; + +{ + ishex (*buf++, val); + return buf; +} + +static char * +pack_nibble (buf, nibble) + char *buf; + int nibble; + +{ + *buf++ = hexchars[(nibble & 0x0f)]; + return buf; +} + +static char * +pack_hex_byte (pkt, byte) + char *pkt; + unsigned char byte; +{ + *pkt++ = hexchars[(byte >> 4) & 0xf]; + *pkt++ = hexchars[(byte & 0xf)]; + return pkt; +} + +static char * +unpack_byte (buf, value) + char *buf; + int *value; +{ + *value = stub_unpack_int (buf, 2); + return buf + 2; +} + + +static char * +pack_int (buf, value) + char *buf; + int value; +{ + buf = pack_hex_byte (buf, (value >> 24) & 0xff); + buf = pack_hex_byte (buf, (value >> 16) & 0xff); + buf = pack_hex_byte (buf, (value >> 8) & 0x0ff); + buf = pack_hex_byte (buf, (value & 0xff)); + return buf; +} + + +static char * +unpack_int (buf, value) + char *buf; + int *value; +{ + *value = stub_unpack_int (buf, 8); + return buf + 8; +} + + +static char * +pack_string (pkt, string) + char *pkt; + char *string; +{ + char ch; + int len; + len = strlen (string); + if (len > 200) + len = 200; /* Bigger than most GDB packets, junk??? */ + pkt = pack_hex_byte (pkt, len); + while (len-- > 0) + { + ch = *string++; + if ((ch == '\0') || (ch == '#')) + ch = '*'; /* Protect encapsulation */ + *pkt++ = ch; + } + return pkt; +} + +static char * +unpack_string (src, dest, length) + char *src; + char *dest; + int length; +{ + while (length--) + *dest++ = *src++; + *dest = '\0'; + return src; +} + +static char * +pack_threadid (pkt, id) + char *pkt; + threadref *id; +{ + char *limit; + unsigned char *altid; + altid = (unsigned char *) id; + limit = pkt + BUF_THREAD_ID_SIZE; + while (pkt < limit) + pkt = pack_hex_byte (pkt, *altid++); + return pkt; +} + + +static char * +unpack_threadid (inbuf, id) + char *inbuf; + threadref *id; +{ + char *altref; + char *limit = inbuf + BUF_THREAD_ID_SIZE; + int x, y; + altref = (char *) id; + + while (inbuf < limit) + { + x = stubhex (*inbuf++); + y = stubhex (*inbuf++); + *altref++ = (x << 4) | y; + } + return inbuf; +} + +/* Externally, threadrefs are 64 bits but internally, they are still + ints. This is due to a mismatch of specifications. + We would like to use 64bit thread references internally. + This is an adapter function. + */ + +void +int_to_threadref (id, value) + threadref *id; + int value; +{ + unsigned char *scan; + scan = (unsigned char *) id; + { + int i = 4; + while (i--) + *scan++ = 0; + } + *scan++ = (value >> 24) & 0xff; + *scan++ = (value >> 16) & 0xff; + *scan++ = (value >> 8) & 0xff; + *scan++ = (value & 0xff); +} + +int +threadref_to_int (ref) + threadref *ref; +{ + int value = 0; + unsigned char *scan; + int i; + + scan = (char *) ref; + scan += 4; + i = 4; + while (i-- > 0) + value = (value << 8) | ((*scan++) & 0xff); + return value; +} + +static void +copy_threadref (dest, src) + threadref *dest; + threadref *src; +{ + int i; + unsigned char *csrc, *cdest; + csrc = (unsigned char *) src; + cdest = (unsigned char *) dest; + i = 8; + while (i--) + *cdest++ = *csrc++; +} + + + +static int +threadmatch (dest, src) + threadref *dest; + threadref *src; +{ + /* things are broken right now, so just assume we got a match */ +#if 0 + unsigned char *srcp, *destp; + int i, result; + srcp = (char *) src; + destp = (char *) dest; + + result = 1; + while (i-- > 0) + result &= (*srcp++ == *destp++) ? 1 : 0; + return result; +#endif + return 1; +} + +#if THREAD_PKT_TRACE +#define PKT_TRACE(title,packet) { printf_filtered("%s %s\n", title, packet);} +#else +#define PKT_TRACE(a,b) {} +#endif + + +/* ----- PACK_THREAD_INFO_REQUEST -------------------------------- */ + +/* + threadid:1, # always request threadid + context_exists:2, + display:4, + unique_name:8, + more_display:16 +*/ + +/* Encoding: 'Q':8,'P':8,mask:32,threadid:64 */ + +static char * + pack_threadinfo_request PARAMS ((char *pkt, + int mode, + threadref * id)); + +static char * +pack_threadinfo_request (pkt, mode, id) + char *pkt; + int mode; + threadref *id; +{ + char *base = pkt; + *pkt++ = 'q'; /* Info Query */ + *pkt++ = 'P'; /* process or thread info */ + pkt = pack_int (pkt, mode); /* mode */ + pkt = pack_threadid (pkt, id); /* threadid */ + *pkt = '\0'; /* terminate */ + PKT_TRACE ("threadinfo-req ", base); + return pkt; +} + + +/* These values tag the fields in a thread info response packet */ +/* Tagging the fields allows us to request specific fields and to + add more fields as time goes by */ +#define TAG_THREADID 1 /* Echo the thread identifier */ +#define TAG_EXISTS 2 /* It this process defined enough to + fetch registers and its stack */ +#define TAG_DISPLAY 4 /* A short thing maybe to put on a window */ +#define TAG_THREADNAME 8 /* string, maps 1-to-1 with a thread is */ +#define TAG_MOREDISPLAY 16 /* Whatever the kernel wants to say about the process*/ + + +static int +remote_unpack_thread_info_response (pkt, expectedref, info) + char *pkt; + threadref *expectedref; + struct gdb_ext_thread_info *info; +{ + int mask, length; + unsigned int tag; + threadref ref; + char *limit = pkt + PBUFSIZ; /* plausable parsing limit */ + int retval = 1; + + PKT_TRACE ("unpack-threadinfo ", pkt); + + /* info->threadid = 0; FIXME: implement zero_threadref */ + info->active = 0; + info->display[0] = '\0'; + info->shortname[0] = '\0'; + info->more_display[0] = '\0'; + + /* Assume the characters indicating the packet type have been stripped */ + pkt = unpack_int (pkt, &mask); /* arg mask */ + pkt = unpack_threadid (pkt, &ref); + + if (mask == 0) + warning("Incomplete response to threadinfo request\n"); + if (!threadmatch (&ref, expectedref)) + { /* This is an answer to a different request */ + warning("ERROR RMT Thread info mismatch\n"); + return 0; + } + copy_threadref (&info->threadid, &ref); + + /* Loop on tagged fields , try to bail if somthing goes wrong */ + + while ((pkt < limit) && mask && *pkt) /* packets are terminated with nulls */ + { + pkt = unpack_int (pkt, &tag); /* tag */ + pkt = unpack_byte (pkt, &length); /* length */ + if (!(tag & mask)) /* tags out of synch with mask */ + { + warning ("ERROR RMT: threadinfo tag mismatch\n"); + retval = 0; + break; + } + if (tag == TAG_THREADID) + { + if (length != 16) + { + warning ("ERROR RMT: length of threadid is not 16\n"); + retval = 0; + break; + } + pkt = unpack_threadid (pkt, &ref); + mask = mask & ~TAG_THREADID; + continue; + } + if (tag == TAG_EXISTS) + { + info->active = stub_unpack_int (pkt, length); + pkt += length; + mask = mask & ~(TAG_EXISTS); + if (length > 8) + { + warning ("ERROR RMT: 'exists' length too long\n"); + retval = 0; + break; + } + continue; + } + if (tag == TAG_THREADNAME) + { + pkt = unpack_string (pkt, &info->shortname[0], length); + mask = mask & ~TAG_THREADNAME; + continue; + } + if (tag == TAG_DISPLAY) + { + pkt = unpack_string (pkt, &info->display[0], length); + mask = mask & ~TAG_DISPLAY; + continue; + } + if (tag == TAG_MOREDISPLAY) + { + pkt = unpack_string (pkt, &info->more_display[0], length); + mask = mask & ~TAG_MOREDISPLAY; + continue; + } + warning ("ERROR RMT: unknown thread info tag\n"); + break; /* Not a tag we know about */ + } + return retval; +} + + +/* ------ REMOTE_GET_THREADINFO -------------------------------------- */ + +int +remote_get_threadinfo (threadid, fieldset, info) + threadref *threadid; + int fieldset; /* TAG mask */ + struct gdb_ext_thread_info *info; +{ + int result; + char threadinfo_pkt[PBUFSIZ]; + pack_threadinfo_request (threadinfo_pkt, fieldset, threadid); + putpkt (threadinfo_pkt); + getpkt (threadinfo_pkt, 0); + result = remote_unpack_thread_info_response (threadinfo_pkt + 2, threadid, info); + return result; +} + +/* ------- ADAPT_remote_GET_THREADINFO - */ +/* Unfortunatly, 61 but thread-ids are bugger than the internal + representation of a threadid. */ + + +int +adapt_remote_get_threadinfo (ref, selection, info) + gdb_threadref *ref; + int selection; + struct gdb_ext_thread_info *info; +{ + threadref lclref; + int_to_threadref (&lclref, *ref); + return remote_get_threadinfo (&lclref, selection, info); +} + + +/* -------- PACK_THREADLIST-REQUEST --------------------------------- */ +/* Format: i'Q':8,i"L":8,initflag:8,batchsize:16,lastthreadid:32 */ + +static char * +pack_threadlist_request (pkt, startflag, threadcount, nextthread) + char *pkt; + int startflag; + int threadcount; + threadref *nextthread; +{ + *pkt++ = 'q'; /* info query packet */ + *pkt++ = 'L'; /* Process LIST or threadLIST request */ + pkt = pack_nibble (pkt, startflag); /* initflag 1 bytes */ + pkt = pack_hex_byte (pkt, threadcount); /* threadcount 2 bytes */ + pkt = pack_threadid (pkt, nextthread); /* 64 bit thread identifier */ + *pkt = '\0'; + return pkt; +} + + +/* ---------- PARSE_THREADLIST_RESPONSE ------------------------------------ */ +/* Encoding: 'q':8,'M':8,count:16,done:8,argthreadid:64,(threadid:64)* */ + + +static int +parse_threadlist_response (pkt, result_limit, original_echo, + resultlist, doneflag) + char *pkt; + int result_limit; + threadref *original_echo; + threadref *resultlist; + int *doneflag; +{ + char *limit; + int count, resultcount, done; + resultcount = 0; + + /* assume the 'q' and 'M chars have been stripped */ + PKT_TRACE ("parse-threadlist-response ", pkt); + limit = pkt + (PBUFSIZ - BUF_THREAD_ID_SIZE); /* done parse past here */ + pkt = unpack_byte (pkt, &count); /* count field */ + pkt = unpack_nibble (pkt, &done); + /* The first threadid is the argument threadid */ + pkt = unpack_threadid (pkt, original_echo); /* should match query packet */ + while ((count-- > 0) && (pkt < limit)) + { + pkt = unpack_threadid (pkt, resultlist++); + if (resultcount++ >= result_limit) + break; + } + if (doneflag) + *doneflag = done; + return resultcount; /* successvalue */ +} + + + +static int +remote_get_threadlist (startflag, nextthread, result_limit, + done, result_count, threadlist) + int startflag; + threadref *nextthread; + int result_limit; + int *done; + int *result_count; + threadref *threadlist; + +{ + static threadref echo_nextthread; + char threadlist_packet[PBUFSIZ]; + char t_response[PBUFSIZ]; + int result = 1; + + /* Trancate result limit to be smaller than the packet size */ + if ((((result_limit + 1) * BUF_THREAD_ID_SIZE) + 10) >= PBUFSIZ) + result_limit = (PBUFSIZ / BUF_THREAD_ID_SIZE) - 2; + + pack_threadlist_request (threadlist_packet, + startflag, result_limit, nextthread); + putpkt (threadlist_packet); + getpkt (t_response, 0); + *result_count = parse_threadlist_response ( + t_response + 2, /* strip header */ + result_limit, + &echo_nextthread, + threadlist, + done); + if (!threadmatch (&echo_nextthread, nextthread)) + { + /* FIXME: This is a good reason to drop the packet */ + /* Possably, there is a duplicate response */ + /* Possabilities : + retransmit immediatly - race conditions + retransmit after timeout - yes + exit + wait for packet, then exit + */ + warning ("HMM: threadlist did not echo arg thread, dropping it\n"); + return 0; /* I choose simply exiting */ + } + if (*result_count <= 0) + { + if (*done != 1) + { + warning ("RMT ERROR : failed to get remote thread list\n"); + result = 0; + } + return result; /* break; */ + } + if (*result_count > result_limit) + { + *result_count = 0; + warning ("RMT ERROR: threadlist response longer than requested\n"); + return 0; + } + return result; +} + + + +/* This is the interface between remote and threads, remotes upper interface */ +/* remote_find_new_threads retreives the thread list and for each + thread in the list, looks up the thread in GDB's internal list, + ading the thread if it does not already exist. + This involves getting partial thread lists from the remote target so, + polling the quit_flag is required. +*/ + +typedef int (*rmt_thread_action) ( + threadref * ref, + void *context +); + +#define MAXTHREADLISTRESULTS 32 /* About this many threadisds fit in a packet */ + +static int +remote_threadlist_iterator PARAMS (( + rmt_thread_action stepfunction, + void *context, + int looplimit)); + +static int +remote_threadlist_iterator (stepfunction, context, looplimit) + rmt_thread_action stepfunction; + void *context; + int looplimit; +{ + int done, i, result_count; + int startflag = 1; + int result = 1; + int loopcount = 0; + static threadref nextthread; + static threadref echo_nextthread; + static threadref resultthreadlist[MAXTHREADLISTRESULTS]; + + done = 0; + while (!done) + { + if (loopcount++ > looplimit) + { + result = 0; + warning ("Remote fetch threadlist -infinite loop-\n"); + break; + } + if (!remote_get_threadlist (startflag, + &nextthread, + MAXTHREADLISTRESULTS, + &done, + &result_count, + resultthreadlist)) + { + result = 0; + break; + } + startflag = 0; /* clear for later iterations */ + /* Setup to resume next batch of thread references , set nestthread */ + if (result_count >= 1) + copy_threadref (&nextthread, &resultthreadlist[result_count - 1]); + /* output_threadid("last-of-batch",&nextthread); */ + i = 0; + while (result_count--) + if (!(result = (*stepfunction) (&resultthreadlist[i++], context))) + break; + } + return result; +} + + +static int +remote_newthread_step (ref, context) + threadref *ref; + void *context + ; + +{ + int pid; + pid = threadref_to_int (ref); + if (!in_thread_list (pid)) + add_thread (pid); + return 1; /* continue iterator */ +} + +#define CRAZY_MAX_THREADS 1000 + + +int +remote_find_new_threads (void) +{ + return remote_threadlist_iterator (remote_newthread_step, 0, CRAZY_MAX_THREADS); +} /* remote_find_new_threads */ + +int +remote_update_threads () +{ + /* Right now, this is empty. But it is one of the functions + defined for the thread target vector so it gets called. + If we were to allow the modification of the registers of + a suspended process, this would be implemented. */ + return 0; +} + +static struct target_thread_vector remote_thread_vec; + +/* Initialize the thread vector which is used by threads.c */ +/* The thread stubb is a package, it has an initializer */ +void init_remote_threads () +{ + remote_thread_vec.find_new_threads = remote_find_new_threads; + remote_thread_vec.get_thread_info = adapt_remote_get_threadinfo; +} + +/* --------- UNIT_TEST for THREAD oriented PACKETS -------------------------- */ + +#define SAMPLE_THREAD 0x05060708 /* Truncated 64 bit threadid */ + + +static void +threadset_test_cmd (cmd, tty) + char *cmd; + int tty; +{ + int sample_thread = SAMPLE_THREAD; + printf_filtered ("Remote threadset test\n"); + set_thread (sample_thread, 1); +} + + +static void +threadalive_test (cmd, tty) + char *cmd; + int tty; +{ + int sample_thread = SAMPLE_THREAD; + if (remote_thread_alive (sample_thread)) + printf_filtered ("PASS: Thread alive test\n"); + else + printf_filtered ("FAIL: Thread alive test\n"); +} + +void +output_threadid PARAMS ((char *title, threadref * ref)); + +void +output_threadid (title, ref) + char *title; + threadref *ref; +{ + char hexid[20]; + pack_threadid (&hexid[0], ref); /* Convert threead id into hex */ + hexid[16] = 0; + printf_filtered ("%s %s\n", title, (&hexid[0])); +} + + +static void +threadlist_test_cmd (cmd, tty) + char *cmd; + int tty; +{ + int startflag = 1; + threadref nextthread; + int done, result_count; + threadref threadlist[3]; + + printf_filtered ("Remote Threadlist test\n"); + if (!remote_get_threadlist (startflag, &nextthread, 3, &done, + &result_count, &threadlist[0])) + printf_filtered ("FAIL: threadlist test\n"); + else + { + threadref *scan = threadlist; + threadref *limit = scan + result_count; + while (scan < limit) + output_threadid (" thread ", scan++); + } +} + +void +display_thread_info (info) + struct gdb_ext_thread_info *info; +{ + + output_threadid ("Threadid: ", &info->threadid); + /* short name */ + printf_filtered ("Name: %s\n ", info->shortname); + /* format display state */ + printf_filtered ("State: %s\n", info->display); + /* additional data */ + printf_filtered ("other: %s\n\n", info->more_display); +} + +int +get_and_display_threadinfo (ref) + threadref *ref; +{ + int result; + int set; + struct gdb_ext_thread_info threadinfo; + + set = TAG_THREADID | TAG_EXISTS | TAG_THREADNAME + | TAG_MOREDISPLAY | TAG_DISPLAY; + if (0 != (result = remote_get_threadinfo (ref, set, &threadinfo))) + display_thread_info (&threadinfo); + return result; +} + +static void +threadinfo_test_cmd (cmd, tty) + char *cmd; + int tty; +{ + int athread = SAMPLE_THREAD; + threadref thread; + int set; + + int_to_threadref (&thread, athread); + printf_filtered ("Remote Threadinfo test\n"); + if (!get_and_display_threadinfo (&thread)) + printf_filtered ("FAIL cannot get thread info\n"); +} + + +static int +thread_display_step (ref, context) + threadref *ref; + void *context; +{ + /* output_threadid(" threadstep ",ref); *//* simple test */ + return get_and_display_threadinfo (ref); +} + + +static void +threadlist_update_test_cmd (cmd, tty) + char *cmd; + int tty; +{ + printf_filtered ("Remote Threadlist update test\n"); + remote_threadlist_iterator (thread_display_step, 0, CRAZY_MAX_THREADS); +} + +static void +init_remote_threadtests (void) +{ + add_com ("tlist", class_obscure, threadlist_test_cmd, + "Fetch and print the remote list of thread identifiers, one pkt only"); + add_com ("tinfo", class_obscure, threadinfo_test_cmd, + "Fetch and display info about one thread"); + add_com ("tset", class_obscure, threadset_test_cmd, + "Test setting to a different thread"); + add_com ("tupd", class_obscure, threadlist_update_test_cmd, + "Iterate through updating all remote thread info"); + add_com ("talive", class_obscure, threadalive_test, + " Remote thread alive test "); +} + +#define INIT_REMOTE_THREADTESTS { init_remote_threadtests();} +/* END OF REMOTE THREAD UNIT TESTS */ + + /* Restart the remote side; this is an extended protocol operation. */ static void @@ -655,7 +1677,10 @@ device is attached to the remote system (e.g. /dev/ttya)."); puts_filtered ("\n"); } push_target (target); /* Switch to using remote target now */ - + /* The target vector does not have the thread functions in it yet, + so we use this function to call back into the thread module and + register the thread vector and its contained functions. */ + bind_target_thread_vector(&remote_thread_vec); /* Start out by trying the 'P' request to set registers. We set this each time that we open a new target so that if the user switches from one stub to another, we can (if the target is closed and reopened) cope. */ @@ -916,16 +1941,17 @@ remote_wait (pid, status) regno = strtol ((const char *) p, &p_temp, 16); /* Read the register number */ p1 = (unsigned char *)p_temp; - if (p1 == p) + if (p1 == p) /* No register number present here */ { p1 = (unsigned char *) strchr ((const char *) p, ':'); if (p1 == NULL) - warning ("Malformed packet (missing colon): %s\n\ + warning ("Malformed packet(a) (missing colon): %s\n\ Packet: '%s'\n", p, buf); if (strncmp ((const char *) p, "thread", p1 - p) == 0) { - thread_num = strtol ((const char *) ++p1, &p_temp, 16); + p_temp = unpack_varlen_hex(++p1,&thread_num); + record_currthread(thread_num); p = (unsigned char *)p_temp; } } @@ -934,7 +1960,7 @@ Packet: '%s'\n", p = p1; if (*p++ != ':') - warning ("Malformed packet (missing colon): %s\n\ + warning ("Malformed packet(b) (missing colon): %s\n\ Packet: '%s'\n", p, buf); @@ -954,7 +1980,10 @@ Packet: '%s'\n", } if (*p++ != ';') - warning ("Remote register badly formatted: %s", buf); + { + warning ("Remote register badly formatted: %s", buf); + warning (" here: %s",p); + } } } /* fall through */ @@ -1778,6 +2807,8 @@ read_frame (buf) } } + + /* Read a packet from the remote machine, with error checking, and store it in BUF. BUF is expected to be of size PBUFSIZ. If FOREVER, wait forever rather than timing out; this is used @@ -2197,9 +3228,9 @@ init_remote_ops () Specify the serial device it is connected to (e.g. /dev/ttya)."; remote_ops.to_open = remote_open; remote_ops.to_close = remote_close; - remote_ops.to_detach = remote_detach; + remote_ops.to_detach = remote_detach; remote_ops.to_resume = remote_resume; - remote_ops.to_wait = remote_wait; + remote_ops.to_wait = remote_wait; remote_ops.to_fetch_registers = remote_fetch_registers; remote_ops.to_store_registers = remote_store_registers; remote_ops.to_prepare_to_store = remote_prepare_to_store; @@ -2222,7 +3253,7 @@ Specify the serial device it is connected to (e.g. /dev/ttya)."; } static void -init_extended_remote_ops () +init_extended_remote_ops () { extended_remote_ops = remote_ops; @@ -2243,6 +3274,8 @@ _initialize_remote () init_extended_remote_ops (); add_target (&extended_remote_ops); + init_remote_threads(); + INIT_REMOTE_THREADTESTS /* conditional thread packet unit test */ add_cmd ("compare-sections", class_obscure, compare_sections_command, "Compare section data on target to the exec file.\n\ @@ -2260,22 +3293,29 @@ terminating `#' character and checksum.", add_show_from_set (add_set_cmd ("remotetimeout", no_class, var_integer, (char *)&remote_timeout, - "Set timeout value for remote read.\n", &setlist), + "Set timeout value for remote read.\n", + &setlist), &showlist); add_show_from_set (add_set_cmd ("remotebreak", no_class, var_integer, (char *)&remote_break, - "Set whether to send break if interrupted.\n", &setlist), + "Set whether to send break if interrupted.\n", + &setlist), &showlist); add_show_from_set (add_set_cmd ("remotewritesize", no_class, var_integer, (char *)&remote_write_size, - "Set the maximum number of bytes in each memory write packet.\n", &setlist), + "Set the maximum number of bytes in each memory write packet.\n", + &setlist), &showlist); + + remote_address_size = TARGET_PTR_BIT; add_show_from_set (add_set_cmd ("remoteaddresssize", class_obscure, var_integer, (char *)&remote_address_size, - "Set the maximum size of the address (in bits) in a memory packet.\n", &setlist), - &showlist); + "Set the maximum size of the address (in bits) in a memory packet.\n", + &setlist), + &showlist); } + |