unsigned char valgrind_wait (char *ourstatus) { int pid; unsigned long wptid; ThreadState *tst; enum target_signal sig; int code; pid = VG_(getpid) (); dlog(1, "enter valgrind_wait pid %d\n", pid); regcache_invalidate(); valgrind_update_threads(pid); /* First see if we are done with this process. */ if (exit_status_to_report != 0) { *ourstatus = exit_status_to_report; exit_status_to_report = 0; if (*ourstatus == 'W') { code = exit_code_to_report; exit_code_to_report = 0; dlog(1, "exit valgrind_wait status W exit code %d\n", code); return code; } if (*ourstatus == 'X') { sig = target_signal_from_host(exit_code_to_report); exit_code_to_report = 0; dlog(1, "exit valgrind_wait status X signal %u\n", sig); return sig; } } /* in valgrind, we consider that a wait always succeeds with STOPPED 'T' and with a signal TRAP (i.e. a breakpoint), unless there is a signal to report. */ *ourstatus = 'T'; if (vki_signal_to_report.si_signo == 0) sig = TARGET_SIGNAL_TRAP; else sig = target_signal_from_host(vki_signal_to_report.si_signo); if (vgdb_interrupted_tid != 0) tst = VG_(get_ThreadState) (vgdb_interrupted_tid); else tst = VG_(get_ThreadState) (VG_(running_tid)); wptid = tst->os_state.lwpid; /* we can only change the current_inferior when the wptid references an existing thread. Otherwise, we are still in the init phase. (hack similar to main thread hack in valgrind_update_threads) */ if (tst->os_state.lwpid) current_inferior = gdb_id_to_thread (wptid); stop_pc = (*the_low_target.get_pc) (); dlog(1, "exit valgrind_wait status T ptid %s stop_pc %s signal %u\n", image_ptid (wptid), sym (stop_pc), sig); return sig; }
int valgrind_thread_alive (unsigned long tid) { struct thread_info *ti = gdb_id_to_thread(tid); ThreadState *tst; if (ti != NULL) { tst = (ThreadState *) inferior_target_data (ti); return tst->status != VgTs_Zombie; } else { return 0; } }
/* synchronize threads known by valgrind and threads known by gdbserver */ static void valgrind_update_threads (int pid) { ThreadId tid; ThreadState *ts; unsigned long ptid; struct thread_info *ti; /* call remove_thread for all gdb threads not in valgrind threads */ for_each_inferior (&all_threads, remove_thread_if_not_in_vg_threads); /* call add_thread for all valgrind threads not known in gdb all_threads */ for (tid = 1; tid < VG_N_THREADS; tid++) { #define LOCAL_THREAD_TRACE " ti* %p vgtid %d status %s as gdb ptid %s lwpid %d\n", \ ti, tid, VG_(name_of_ThreadStatus) (ts->status), \ image_ptid (ptid), ts->os_state.lwpid if (VG_(is_valid_tid) (tid)) { ts = VG_(get_ThreadState) (tid); ptid = ts->os_state.lwpid; ti = gdb_id_to_thread (ptid); if (!ti) { /* we do not report the threads which are not yet fully initialized otherwise this creates duplicated threads in gdb: once with pid xxx lwpid 0, then after that with pid xxx lwpid yyy. */ if (ts->status != VgTs_Init) { dlog(1, "adding_thread" LOCAL_THREAD_TRACE); add_thread (ptid, ts, ptid); } } else { dlog(2, "(known thread)" LOCAL_THREAD_TRACE); } } #undef LOCAL_THREAD_TRACE } }
/* Handle all of the extended 'q' packets. */ static void handle_query (char *arg_own_buf, int *new_packet_len_p) { static struct inferior_list_entry *thread_ptr; /* qRcmd, monitor command handling. */ if (strncmp ("qRcmd,", arg_own_buf, 6) == 0) { char *p = arg_own_buf + 6; int cmdlen = strlen(p)/2; char cmd[cmdlen+1]; if (unhexify (cmd, p, cmdlen) != cmdlen) { write_enn (arg_own_buf); return; } cmd[cmdlen] = '\0'; if (handle_gdb_monitor_command (cmd)) { /* In case the command is from a standalone vgdb, connection will be closed soon => flush the output. */ VG_(message_flush) (); write_ok (arg_own_buf); return; } else { /* cmd not recognised */ VG_(gdb_printf) ("command '%s' not recognised\n" "In gdb, try 'monitor help'\n" "In a shell, try 'vgdb help'\n", cmd); write_ok (arg_own_buf); return; } } /* provide some valgrind specific info in return to qThreadExtraInfo. */ if (strncmp ("qThreadExtraInfo,", arg_own_buf, 17) == 0) { unsigned long gdb_id; struct thread_info *ti; ThreadState *tst; char status[100]; gdb_id = strtoul (&arg_own_buf[17], NULL, 16); ti = gdb_id_to_thread (gdb_id); if (ti != NULL) { tst = (ThreadState *) inferior_target_data (ti); /* Additional info is the tid and the thread status. */ VG_(snprintf) (status, sizeof(status), "tid %d %s", tst->tid, VG_(name_of_ThreadStatus)(tst->status)); hexify (arg_own_buf, status, strlen(status)); return; } else { write_enn (arg_own_buf); return; } } if (strcmp ("qAttached", arg_own_buf) == 0) { /* tell gdb to always detach, never kill the process */ arg_own_buf[0] = '1'; arg_own_buf[1] = 0; return; } if (strcmp ("qSymbol::", arg_own_buf) == 0) { /* We have no symbol to read. */ write_ok (arg_own_buf); return; } if (strcmp ("qfThreadInfo", arg_own_buf) == 0) { thread_ptr = all_threads.head; VG_(sprintf) (arg_own_buf, "m%x", thread_to_gdb_id ((struct thread_info *)thread_ptr)); thread_ptr = thread_ptr->next; return; } if (strcmp ("qsThreadInfo", arg_own_buf) == 0) { if (thread_ptr != NULL) { VG_(sprintf) (arg_own_buf, "m%x", thread_to_gdb_id ((struct thread_info *)thread_ptr)); thread_ptr = thread_ptr->next; return; } else { VG_(sprintf) (arg_own_buf, "l"); return; } } if (valgrind_target_xml(VG_(clo_vgdb_shadow_registers)) != NULL && strncmp ("qXfer:features:read:", arg_own_buf, 20) == 0) { CORE_ADDR ofs; unsigned int len, doc_len; const char *annex = NULL; // First, the annex is extracted from the packet received. // Then, it is replaced by the corresponding file name. int fd; /* Grab the annex, offset, and length. */ if (decode_xfer_read (arg_own_buf + 20, &annex, &ofs, &len) < 0) { strcpy (arg_own_buf, "E00"); return; } if (strcmp (annex, "target.xml") == 0) { annex = valgrind_target_xml(VG_(clo_vgdb_shadow_registers)); if (annex != NULL && VG_(clo_vgdb_shadow_registers)) { /* Ensure the shadow registers are initialized. */ initialize_shadow_low(True); } if (annex == NULL) { strcpy (arg_own_buf, "E00"); return; } } { char doc[VG_(strlen)(VG_(libdir)) + 1 + VG_(strlen)(annex) + 1]; struct vg_stat stat_doc; char toread[len]; int len_read; VG_(sprintf)(doc, "%s/%s", VG_(libdir), annex); fd = VG_(fd_open) (doc, VKI_O_RDONLY, 0); if (fd == -1) { strcpy (arg_own_buf, "E00"); return; } if (VG_(fstat) (fd, &stat_doc) != 0) { VG_(close) (fd); strcpy (arg_own_buf, "E00"); return; } doc_len = stat_doc.size; if (len > PBUFSIZ - POVERHSIZ) len = PBUFSIZ - POVERHSIZ; if (ofs > doc_len) { write_enn (arg_own_buf); VG_(close) (fd); return; } VG_(lseek) (fd, ofs, VKI_SEEK_SET); len_read = VG_(read) (fd, toread, len); *new_packet_len_p = write_qxfer_response (arg_own_buf, (unsigned char *)toread, len_read, ofs + len_read < doc_len); VG_(close) (fd); return; } } if (strncmp ("qXfer:auxv:read:", arg_own_buf, 16) == 0) { unsigned char *data; int n; CORE_ADDR ofs; unsigned int len; const char *annex; /* Reject any annex; grab the offset and length. */ if (decode_xfer_read (arg_own_buf + 16, &annex, &ofs, &len) < 0 || annex[0] != '\0') { strcpy (arg_own_buf, "E00"); return; } if (len > PBUFSIZ - 2) len = PBUFSIZ - 2; data = malloc (len); { UWord *client_auxv = VG_(client_auxv); unsigned int client_auxv_len = 0; while (*client_auxv != 0) { dlog(4, "auxv %lld %llx\n", (ULong)*client_auxv, (ULong)*(client_auxv+1)); client_auxv++; client_auxv++; client_auxv_len += 2 * sizeof(UWord); } client_auxv_len += 2 * sizeof(UWord); dlog(4, "auxv len %d\n", client_auxv_len); if (ofs >= client_auxv_len) n = -1; else { n = client_auxv_len - ofs; VG_(memcpy) (data, (unsigned char *) VG_(client_auxv), n); } } if (n < 0) write_enn (arg_own_buf); else if (n > len) *new_packet_len_p = write_qxfer_response (arg_own_buf, data, len, 1); else *new_packet_len_p = write_qxfer_response (arg_own_buf, data, n, 0); free (data); return; } /* Protocol features query. */ if (strncmp ("qSupported", arg_own_buf, 10) == 0 && (arg_own_buf[10] == ':' || arg_own_buf[10] == '\0')) { VG_(sprintf) (arg_own_buf, "PacketSize=%x", PBUFSIZ - 1); /* Note: max packet size including frame and checksum, but without trailing null byte, which is not sent/received. */ strcat (arg_own_buf, ";QStartNoAckMode+"); strcat (arg_own_buf, ";QPassSignals+"); if (VG_(client_auxv)) strcat (arg_own_buf, ";qXfer:auxv:read+"); if (valgrind_target_xml(VG_(clo_vgdb_shadow_registers)) != NULL) { strcat (arg_own_buf, ";qXfer:features:read+"); /* if a new gdb connects to us, we have to reset the register set to the normal register sets to allow this new gdb to decide to use or not the shadow registers. Note that the reset is only done for gdb that are sending qSupported packets. If a user first connected with a recent gdb using shadow registers and then with a very old gdb that does not use qSupported packet, then the old gdb will not properly connect. */ initialize_shadow_low(False); } return; } /* Otherwise we didn't know what packet it was. Say we didn't understand it. */ arg_own_buf[0] = 0; }
/* Handle all of the extended 'q' packets. */ void handle_query (char *own_buf, int packet_len, int *new_packet_len_p) { static struct inferior_list_entry *thread_ptr; /* Reply the current thread id. */ if (strcmp ("qC", own_buf) == 0) { thread_ptr = all_threads.head; if (thread_ptr == NULL) strcpy (own_buf, "unset"); else sprintf (own_buf, "QC%x", thread_to_gdb_id ((struct thread_info *)thread_ptr)); return; } if (strcmp ("qSymbol::", own_buf) == 0) { if (the_target->look_up_symbols != NULL) (*the_target->look_up_symbols) (); strcpy (own_buf, "OK"); return; } if (strcmp ("qfThreadInfo", own_buf) == 0) { thread_ptr = all_threads.head; sprintf (own_buf, "m%x", thread_to_gdb_id ((struct thread_info *)thread_ptr)); thread_ptr = thread_ptr->next; return; } if (strcmp ("qsThreadInfo", own_buf) == 0) { if (thread_ptr != NULL) { sprintf (own_buf, "m%x", thread_to_gdb_id ((struct thread_info *)thread_ptr)); thread_ptr = thread_ptr->next; return; } else { sprintf (own_buf, "l"); return; } } if (the_target->read_offsets != NULL && strcmp ("qOffsets", own_buf) == 0) { CORE_ADDR text, data; if (the_target->read_offsets (&text, &data)) sprintf (own_buf, "Text=%lX;Data=%lX;Bss=%lX", (long)text, (long)data, (long)data); else write_enn (own_buf); return; } if (the_target->qxfer_spu != NULL && strncmp ("qXfer:spu:read:", own_buf, 15) == 0) { char *annex; int n; unsigned int len; CORE_ADDR ofs; unsigned char *spu_buf; strcpy (own_buf, "E00"); if (decode_xfer_read (own_buf + 15, &annex, &ofs, &len) < 0) return; if (len > PBUFSIZ - 2) len = PBUFSIZ - 2; spu_buf = malloc (len + 1); if (!spu_buf) return; n = (*the_target->qxfer_spu) (annex, spu_buf, NULL, ofs, len + 1); if (n < 0) write_enn (own_buf); else if (n > len) *new_packet_len_p = write_qxfer_response (own_buf, spu_buf, len, 1); else *new_packet_len_p = write_qxfer_response (own_buf, spu_buf, n, 0); free (spu_buf); return; } if (the_target->qxfer_spu != NULL && strncmp ("qXfer:spu:write:", own_buf, 16) == 0) { char *annex; int n; unsigned int len; CORE_ADDR ofs; unsigned char *spu_buf; strcpy (own_buf, "E00"); spu_buf = malloc (packet_len - 15); if (!spu_buf) return; if (decode_xfer_write (own_buf + 16, packet_len - 16, &annex, &ofs, &len, spu_buf) < 0) { free (spu_buf); return; } n = (*the_target->qxfer_spu) (annex, NULL, (unsigned const char *)spu_buf, ofs, len); if (n < 0) write_enn (own_buf); else sprintf (own_buf, "%x", n); free (spu_buf); return; } if (the_target->read_auxv != NULL && strncmp ("qXfer:auxv:read:", own_buf, 16) == 0) { unsigned char *data; int n; CORE_ADDR ofs; unsigned int len; char *annex; /* Reject any annex; grab the offset and length. */ if (decode_xfer_read (own_buf + 16, &annex, &ofs, &len) < 0 || annex[0] != '\0') { strcpy (own_buf, "E00"); return; } /* Read one extra byte, as an indicator of whether there is more. */ if (len > PBUFSIZ - 2) len = PBUFSIZ - 2; data = malloc (len + 1); n = (*the_target->read_auxv) (ofs, data, len + 1); if (n < 0) write_enn (own_buf); else if (n > len) *new_packet_len_p = write_qxfer_response (own_buf, data, len, 1); else *new_packet_len_p = write_qxfer_response (own_buf, data, n, 0); free (data); return; } if (strncmp ("qXfer:features:read:", own_buf, 20) == 0) { CORE_ADDR ofs; unsigned int len, total_len; const char *document; char *annex; /* Check for support. */ document = get_features_xml ("target.xml"); if (document == NULL) { own_buf[0] = '\0'; return; } /* Grab the annex, offset, and length. */ if (decode_xfer_read (own_buf + 20, &annex, &ofs, &len) < 0) { strcpy (own_buf, "E00"); return; } /* Now grab the correct annex. */ document = get_features_xml (annex); if (document == NULL) { strcpy (own_buf, "E00"); return; } total_len = strlen (document); if (len > PBUFSIZ - 2) len = PBUFSIZ - 2; if (ofs > total_len) write_enn (own_buf); else if (len < total_len - ofs) *new_packet_len_p = write_qxfer_response (own_buf, document + ofs, len, 1); else *new_packet_len_p = write_qxfer_response (own_buf, document + ofs, total_len - ofs, 0); return; } if (strncmp ("qXfer:libraries:read:", own_buf, 21) == 0) { CORE_ADDR ofs; unsigned int len, total_len; char *document, *p; struct inferior_list_entry *dll_ptr; char *annex; /* Reject any annex; grab the offset and length. */ if (decode_xfer_read (own_buf + 21, &annex, &ofs, &len) < 0 || annex[0] != '\0') { strcpy (own_buf, "E00"); return; } /* Over-estimate the necessary memory. Assume that every character in the library name must be escaped. */ total_len = 64; for (dll_ptr = all_dlls.head; dll_ptr != NULL; dll_ptr = dll_ptr->next) total_len += 128 + 6 * strlen (((struct dll_info *) dll_ptr)->name); document = malloc (total_len); strcpy (document, "<library-list>\n"); p = document + strlen (document); for (dll_ptr = all_dlls.head; dll_ptr != NULL; dll_ptr = dll_ptr->next) { struct dll_info *dll = (struct dll_info *) dll_ptr; char *name; strcpy (p, " <library name=\""); p = p + strlen (p); name = xml_escape_text (dll->name); strcpy (p, name); free (name); p = p + strlen (p); strcpy (p, "\"><segment address=\""); p = p + strlen (p); sprintf (p, "0x%lx", (long) dll->base_addr); p = p + strlen (p); strcpy (p, "\"/></library>\n"); p = p + strlen (p); } strcpy (p, "</library-list>\n"); total_len = strlen (document); if (len > PBUFSIZ - 2) len = PBUFSIZ - 2; if (ofs > total_len) write_enn (own_buf); else if (len < total_len - ofs) *new_packet_len_p = write_qxfer_response (own_buf, document + ofs, len, 1); else *new_packet_len_p = write_qxfer_response (own_buf, document + ofs, total_len - ofs, 0); free (document); return; } /* Protocol features query. */ if (strncmp ("qSupported", own_buf, 10) == 0 && (own_buf[10] == ':' || own_buf[10] == '\0')) { sprintf (own_buf, "PacketSize=%x", PBUFSIZ - 1); #if !defined (NO_PASS_SIGNALS) strcat (own_buf, ";QPassSignals+", PBUFSIZ - 1); #endif #if !defined (NO_LIBRARIES) /* We do not have any hook to indicate whether the target backend supports qXfer:libraries:read, so always report it. */ strcat (own_buf, ";qXfer:libraries:read+"); #endif strcat (own_buf, ";qXfer:memory map:read+"); if (the_target->read_auxv != NULL) strcat (own_buf, ";qXfer:auxv:read+"); if (the_target->qxfer_spu != NULL) strcat (own_buf, ";qXfer:spu:read+;qXfer:spu:write+"); if (get_features_xml ("target.xml") != NULL) strcat (own_buf, ";qXfer:features:read+"); return; } /* Thread-local storage support. */ if (the_target->get_tls_address != NULL && strncmp ("qGetTLSAddr:", own_buf, 12) == 0) { char *p = own_buf + 12; CORE_ADDR parts[3], address = 0; int i, err; for (i = 0; i < 3; i++) { char *p2; int len; if (p == NULL) break; p2 = strchr (p, ','); if (p2) { len = p2 - p; p2++; } else { len = strlen (p); p2 = NULL; } decode_address (&parts[i], p, len); p = p2; } if (p != NULL || i < 3) err = 1; else { struct thread_info *thread = gdb_id_to_thread (parts[0]); if (thread == NULL) err = 2; else err = the_target->get_tls_address (thread, parts[1], parts[2], &address); } if (err == 0) { sprintf (own_buf, "%llx", address); return; } else if (err > 0) { write_enn (own_buf); return; } /* Otherwise, pretend we do not understand this packet. */ } /* Handle "monitor" commands. */ if (strncmp ("qRcmd,", own_buf, 6) == 0) { char *mon = malloc (PBUFSIZ); int len = strlen (own_buf + 6); if ((len % 1) != 0 || unhexify (mon, own_buf + 6, len / 2) != len / 2) { write_enn (own_buf); free (mon); return; } mon[len / 2] = '\0'; write_ok (own_buf); if (strcmp (mon, "set debug 1") == 0) { debug_threads = 1; monitor_output ("Debug output enabled.\n"); } else if (strcmp (mon, "set debug 0") == 0) { debug_threads = 0; monitor_output ("Debug output disabled.\n"); } else if (strcmp (mon, "set remote-debug 1") == 0) { remote_debug = 1; monitor_output ("Protocol debug output enabled.\n"); } else if (strcmp (mon, "set remote-debug 0") == 0) { remote_debug = 0; monitor_output ("Protocol debug output disabled.\n"); } else if (strcmp (mon, "help") == 0) monitor_show_help (); else { int ok = 0; if (the_target->commands) ok = (*the_target->commands) (mon, len); else monitor_output ("Unknown monitor command.\n\n"); if (!ok) { monitor_show_help (); write_enn (own_buf); } } free (mon); return; } /* Otherwise we didn't know what packet it was. Say we didn't understand it. */ own_buf[0] = 0; }
/* Handle all of the extended 'q' packets. */ void handle_query (char *own_buf, int *new_packet_len_p) { static struct inferior_list_entry *thread_ptr; if (strcmp ("qSymbol::", own_buf) == 0) { if (the_target->look_up_symbols != NULL) (*the_target->look_up_symbols) (); strcpy (own_buf, "OK"); return; } if (strcmp ("qfThreadInfo", own_buf) == 0) { thread_ptr = all_threads.head; sprintf (own_buf, "m%x", thread_to_gdb_id ((struct thread_info *)thread_ptr)); thread_ptr = thread_ptr->next; return; } if (strcmp ("qsThreadInfo", own_buf) == 0) { if (thread_ptr != NULL) { sprintf (own_buf, "m%x", thread_to_gdb_id ((struct thread_info *)thread_ptr)); thread_ptr = thread_ptr->next; return; } else { sprintf (own_buf, "l"); return; } } if (the_target->read_offsets != NULL && strcmp ("qOffsets", own_buf) == 0) { CORE_ADDR text, data; if (the_target->read_offsets (&text, &data)) sprintf (own_buf, "Text=%lX;Data=%lX;Bss=%lX", (long)text, (long)data, (long)data); else write_enn (own_buf); return; } if (the_target->read_auxv != NULL && strncmp ("qXfer:auxv:read:", own_buf, 16) == 0) { unsigned char *data; int n; CORE_ADDR ofs; unsigned int len; char *annex; /* Reject any annex; grab the offset and length. */ if (decode_xfer_read (own_buf + 16, &annex, &ofs, &len) < 0 || annex[0] != '\0') { strcpy (own_buf, "E00"); return; } /* Read one extra byte, as an indicator of whether there is more. */ if (len > PBUFSIZ - 2) len = PBUFSIZ - 2; data = malloc (len + 1); n = (*the_target->read_auxv) (ofs, data, len + 1); if (n < 0) write_enn (own_buf); else if (n > len) *new_packet_len_p = write_qxfer_response (own_buf, data, len, 1); else *new_packet_len_p = write_qxfer_response (own_buf, data, n, 0); free (data); return; } /* Protocol features query. */ if (strncmp ("qSupported", own_buf, 10) == 0 && (own_buf[10] == ':' || own_buf[10] == '\0')) { sprintf (own_buf, "PacketSize=%x", PBUFSIZ - 1); if (the_target->read_auxv != NULL) strcat (own_buf, ";qXfer:auxv:read+"); return; } /* Thread-local storage support. */ if (the_target->get_tls_address != NULL && strncmp ("qGetTLSAddr:", own_buf, 12) == 0) { char *p = own_buf + 12; CORE_ADDR parts[3], address = 0; int i, err; for (i = 0; i < 3; i++) { char *p2; int len; if (p == NULL) break; p2 = strchr (p, ','); if (p2) { len = p2 - p; p2++; } else { len = strlen (p); p2 = NULL; } decode_address (&parts[i], p, len); p = p2; } if (p != NULL || i < 3) err = 1; else { struct thread_info *thread = gdb_id_to_thread (parts[0]); if (thread == NULL) err = 2; else err = the_target->get_tls_address (thread, parts[1], parts[2], &address); } if (err == 0) { sprintf (own_buf, "%llx", address); return; } else if (err > 0) { write_enn (own_buf); return; } /* Otherwise, pretend we do not understand this packet. */ } /* Otherwise we didn't know what packet it was. Say we didn't understand it. */ own_buf[0] = 0; }
/* Handle all of the extended 'q' packets. */ static void handle_query (char *arg_own_buf, int *new_packet_len_p) { static struct inferior_list_entry *thread_ptr; /* thread local storage query */ if (strncmp ("qGetTLSAddr:", arg_own_buf, 12) == 0) { char *from, *to; char *end = arg_own_buf + strlen(arg_own_buf); unsigned long gdb_id; CORE_ADDR lm; CORE_ADDR offset; struct thread_info *ti; from = arg_own_buf + 12; to = strchr(from, ','); *to = 0; gdb_id = strtoul (from, NULL, 16); from = to + 1; to = strchr(from, ','); decode_address (&offset, from, to - from); from = to + 1; to = end; decode_address (&lm, from, to - from); dlog(2, "qGetTLSAddr thread %lu offset %p lm %p\n", gdb_id, (void*)offset, (void*)lm); ti = gdb_id_to_thread (gdb_id); if (ti != NULL) { ThreadState *tst; Addr tls_addr; tst = (ThreadState *) inferior_target_data (ti); if (valgrind_get_tls_addr(tst, offset, lm, &tls_addr)) { VG_(sprintf) (arg_own_buf, "%lx", tls_addr); return; } // else we will report we do not support qGetTLSAddr } else { write_enn (arg_own_buf); return; } } /* qRcmd, monitor command handling. */ if (strncmp ("qRcmd,", arg_own_buf, 6) == 0) { char *p = arg_own_buf + 6; int cmdlen = strlen(p)/2; char cmd[cmdlen+1]; if (unhexify (cmd, p, cmdlen) != cmdlen) { write_enn (arg_own_buf); return; } cmd[cmdlen] = '\0'; if (handle_gdb_monitor_command (cmd)) { write_ok (arg_own_buf); return; } else { /* cmd not recognised */ VG_(gdb_printf) ("command '%s' not recognised\n" "In gdb, try 'monitor help'\n" "In a shell, try 'vgdb help'\n", cmd); write_ok (arg_own_buf); return; } } /* provide some valgrind specific info in return to qThreadExtraInfo. */ if (strncmp ("qThreadExtraInfo,", arg_own_buf, 17) == 0) { unsigned long gdb_id; struct thread_info *ti; ThreadState *tst; gdb_id = strtoul (&arg_own_buf[17], NULL, 16); ti = gdb_id_to_thread (gdb_id); if (ti != NULL) { tst = (ThreadState *) inferior_target_data (ti); /* Additional info is the tid, the thread status and the thread's name, if any. */ SizeT len = strlen(VG_(name_of_ThreadStatus)(tst->status)) + 20; if (tst->thread_name) len += strlen(tst->thread_name); /* As the string will be hexified and copied into own_buf we need to limit the length to avoid buffer overflow. */ if (len * 2 > (PBUFSIZ + POVERHSIZ)) len = (PBUFSIZ + POVERHSIZ) / 2; char status[len]; if (tst->thread_name) { VG_(snprintf) (status, sizeof(status), "tid %d %s %s", tst->tid, VG_(name_of_ThreadStatus)(tst->status), tst->thread_name); } else { VG_(snprintf) (status, sizeof(status), "tid %d %s", tst->tid, VG_(name_of_ThreadStatus)(tst->status)); } hexify (arg_own_buf, status, strlen(status)); return; } else { write_enn (arg_own_buf); return; } } if (strcmp ("qAttached", arg_own_buf) == 0) { /* tell gdb to always detach, never kill the process */ arg_own_buf[0] = '1'; arg_own_buf[1] = 0; return; } if (strcmp ("qSymbol::", arg_own_buf) == 0) { /* We have no symbol to read. */ write_ok (arg_own_buf); return; } if (strcmp ("qfThreadInfo", arg_own_buf) == 0) { thread_ptr = all_threads.head; VG_(sprintf) (arg_own_buf, "m%x", thread_to_gdb_id ((struct thread_info *)thread_ptr)); thread_ptr = thread_ptr->next; return; } if (strcmp ("qsThreadInfo", arg_own_buf) == 0) { if (thread_ptr != NULL) { VG_(sprintf) (arg_own_buf, "m%x", thread_to_gdb_id ((struct thread_info *)thread_ptr)); thread_ptr = thread_ptr->next; return; } else { VG_(sprintf) (arg_own_buf, "l"); return; } } if (valgrind_target_xml(VG_(clo_vgdb_shadow_registers)) != NULL && strncmp ("qXfer:features:read:", arg_own_buf, 20) == 0) { CORE_ADDR ofs; unsigned int len, doc_len; const char *annex = NULL; // First, the annex is extracted from the packet received. // Then, it is replaced by the corresponding file name. int fd; /* Grab the annex, offset, and length. */ if (decode_xfer_read (arg_own_buf + 20, &annex, &ofs, &len) < 0) { strcpy (arg_own_buf, "E00"); return; } if (strcmp (annex, "target.xml") == 0) { annex = valgrind_target_xml(VG_(clo_vgdb_shadow_registers)); if (annex != NULL && VG_(clo_vgdb_shadow_registers)) { /* Ensure the shadow registers are initialized. */ initialize_shadow_low(True); } if (annex == NULL) { strcpy (arg_own_buf, "E00"); return; } } { char doc[VG_(strlen)(VG_(libdir)) + 1 + VG_(strlen)(annex) + 1]; struct vg_stat stat_doc; char toread[len]; int len_read; VG_(sprintf)(doc, "%s/%s", VG_(libdir), annex); fd = VG_(fd_open) (doc, VKI_O_RDONLY, 0); if (fd == -1) { strcpy (arg_own_buf, "E00"); return; } if (VG_(fstat) (fd, &stat_doc) != 0) { VG_(close) (fd); strcpy (arg_own_buf, "E00"); return; } doc_len = stat_doc.size; if (len > PBUFSIZ - POVERHSIZ) len = PBUFSIZ - POVERHSIZ; if (ofs > doc_len) { write_enn (arg_own_buf); VG_(close) (fd); return; } VG_(lseek) (fd, ofs, VKI_SEEK_SET); len_read = VG_(read) (fd, toread, len); *new_packet_len_p = write_qxfer_response (arg_own_buf, (unsigned char *)toread, len_read, ofs + len_read < doc_len); VG_(close) (fd); return; } } if (strncmp ("qXfer:auxv:read:", arg_own_buf, 16) == 0) { unsigned char *data; int n; CORE_ADDR ofs; unsigned int len; const char *annex; /* Reject any annex; grab the offset and length. */ if (decode_xfer_read (arg_own_buf + 16, &annex, &ofs, &len) < 0 || annex[0] != '\0') { strcpy (arg_own_buf, "E00"); return; } if (len > PBUFSIZ - POVERHSIZ) len = PBUFSIZ - POVERHSIZ; data = malloc (len); { UWord *client_auxv = VG_(client_auxv); unsigned int client_auxv_len = 0; while (*client_auxv != 0) { dlog(4, "auxv %lld %llx\n", (ULong)*client_auxv, (ULong)*(client_auxv+1)); client_auxv++; client_auxv++; client_auxv_len += 2 * sizeof(UWord); } client_auxv_len += 2 * sizeof(UWord); dlog(4, "auxv len %d\n", client_auxv_len); if (ofs >= client_auxv_len) n = -1; else { n = client_auxv_len - ofs; VG_(memcpy) (data, (unsigned char *) VG_(client_auxv), n); } } if (n < 0) write_enn (arg_own_buf); else if (n > len) *new_packet_len_p = write_qxfer_response (arg_own_buf, data, len, 1); else *new_packet_len_p = write_qxfer_response (arg_own_buf, data, n, 0); free (data); return; } if (strncmp ("qXfer:exec-file:read:", arg_own_buf, 21) == 0) { unsigned char *data; int n; CORE_ADDR ofs; unsigned int len; const char *annex; unsigned long pid; const HChar *name; /* grab the annex, offset and length. */ if (decode_xfer_read (arg_own_buf + 21, &annex, &ofs, &len) < 0) { strcpy (arg_own_buf, "E00"); return; } /* Reject any annex with invalid/unexpected pid */ if (strlen(annex) > 0) pid = strtoul (annex, NULL, 16); else pid = 0; if ((int)pid != VG_(getpid)() && pid != 0) { VG_(sprintf) (arg_own_buf, "E.Valgrind gdbserver pid is %d." " Cannot give info for pid %d", VG_(getpid)(), (int) pid); return; } if (len > PBUFSIZ - 2) len = PBUFSIZ - 2; data = malloc (len); if (!VG_(resolve_filename)(VG_(cl_exec_fd), &name)) { VG_(sprintf) (arg_own_buf, "E.Valgrind gdbserver could not" " resolve pid %d exec filename.", VG_(getpid)()); return; } if (ofs >= strlen(name)) n = -1; else { n = strlen(name) - ofs; VG_(memcpy) (data, name, n); } if (n < 0) write_enn (arg_own_buf); else if (n > len) *new_packet_len_p = write_qxfer_response (arg_own_buf, data, len, 1); else *new_packet_len_p = write_qxfer_response (arg_own_buf, data, n, 0); free (data); return; } if (strncmp ("qXfer:siginfo:read:", arg_own_buf, 19) == 0) { vki_siginfo_t info; int n; CORE_ADDR ofs; unsigned int len; const char *annex; /* Reject any annex; grab the offset and length. */ if (decode_xfer_read (arg_own_buf + 19, &annex, &ofs, &len) < 0 || annex[0] != '\0') { strcpy (arg_own_buf, "E00"); return; } if (len > PBUFSIZ - POVERHSIZ) len = PBUFSIZ - POVERHSIZ; gdbserver_pending_signal_to_report(&info); if (ofs >= sizeof(info)) n = -1; else n = sizeof(info) - ofs; if (n < 0) write_enn (arg_own_buf); else if (n > len) *new_packet_len_p = write_qxfer_response (arg_own_buf, (unsigned char *)&info, len, 1); else *new_packet_len_p = write_qxfer_response (arg_own_buf, (unsigned char *)&info, n, 0); return; } /* Protocol features query. */ if (strncmp ("qSupported", arg_own_buf, 10) == 0 && (arg_own_buf[10] == ':' || arg_own_buf[10] == '\0')) { VG_(sprintf) (arg_own_buf, "PacketSize=%x", PBUFSIZ - 1); /* Note: max packet size including frame and checksum, but without trailing null byte, which is not sent/received. */ strcat (arg_own_buf, ";QStartNoAckMode+"); strcat (arg_own_buf, ";QPassSignals+"); if (VG_(client_auxv)) strcat (arg_own_buf, ";qXfer:auxv:read+"); if (valgrind_target_xml(VG_(clo_vgdb_shadow_registers)) != NULL) { strcat (arg_own_buf, ";qXfer:features:read+"); /* if a new gdb connects to us, we have to reset the register set to the normal register sets to allow this new gdb to decide to use or not the shadow registers. Note that the reset is only done for gdb that are sending qSupported packets. If a user first connected with a recent gdb using shadow registers and then with a very old gdb that does not use qSupported packet, then the old gdb will not properly connect. */ initialize_shadow_low(False); } strcat (arg_own_buf, ";qXfer:exec-file:read+"); strcat (arg_own_buf, ";qXfer:siginfo:read+"); return; } /* Otherwise we didn't know what packet it was. Say we didn't understand it. */ arg_own_buf[0] = 0; }