static void uninsert_raw_breakpoint (struct raw_breakpoint *bp) { if (bp->inserted) { int err; unsigned char buf[MAX_BREAKPOINT_LEN]; bp->inserted = 0; /* Since there can be fast tracepoint jumps inserted in the same address range, we use `write_inferior_memory', which takes care of layering breakpoints on top of fast tracepoints, and on top of the buffer we pass it. This works because we've already unlinked the fast tracepoint jump above. Also note that we need to pass the current shadow contents, because write_inferior_memory updates any shadow memory with what we pass here, and we want that to be a nop. */ memcpy (buf, bp->old_data, breakpoint_len); err = write_inferior_memory (bp->pc, buf, breakpoint_len); if (err != 0) { bp->inserted = 1; if (debug_threads) fprintf (stderr, "Failed to uninsert raw breakpoint at 0x%s (%s).\n", paddress (bp->pc), strerror (err)); } } }
int remove_memory_breakpoint (struct raw_breakpoint *bp) { unsigned char buf[MAX_BREAKPOINT_LEN]; int err; /* Since there can be trap breakpoints inserted in the same address range, we use `write_inferior_memory', which takes care of layering breakpoints on top of fast tracepoints, and on top of the buffer we pass it. This works because the caller has already either unlinked the breakpoint or marked it uninserted. Also note that we need to pass the current shadow contents, because write_inferior_memory updates any shadow memory with what we pass here, and we want that to be a nop. */ memcpy (buf, bp->old_data, breakpoint_len); err = write_inferior_memory (bp->pc, buf, breakpoint_len); if (err != 0) { if (debug_threads) debug_printf ("Failed to uninsert raw breakpoint " "at 0x%s (%s) while deleting it.\n", paddress (bp->pc), strerror (err)); } return err != 0 ? -1 : 0; }
void store_inferior_registers (int ignored) { struct regs inferior_registers; struct fp_status inferior_fp_registers; CORE_ADDR sp = *(CORE_ADDR *) & registers[REGISTER_BYTE (SP_REGNUM)]; write_inferior_memory (sp, ®isters[REGISTER_BYTE (L0_REGNUM)], 16 * REGISTER_RAW_SIZE (L0_REGNUM)); memcpy (&inferior_registers.r_g1, ®isters[REGISTER_BYTE (G1_REGNUM)], 15 * REGISTER_RAW_SIZE (G1_REGNUM)); inferior_registers.r_ps = *(int *) ®isters[REGISTER_BYTE (PS_REGNUM)]; inferior_registers.r_pc = *(int *) ®isters[REGISTER_BYTE (PC_REGNUM)]; inferior_registers.r_npc = *(int *) ®isters[REGISTER_BYTE (NPC_REGNUM)]; inferior_registers.r_y = *(int *) ®isters[REGISTER_BYTE (Y_REGNUM)]; if (ptrace (PTRACE_SETREGS, inferior_pid, (PTRACE_ARG3_TYPE) & inferior_registers, 0)) perror ("ptrace_setregs"); memcpy (&inferior_fp_registers, ®isters[REGISTER_BYTE (FP0_REGNUM)], sizeof inferior_fp_registers.fpu_fr); if (ptrace (PTRACE_SETFPREGS, inferior_pid, (PTRACE_ARG3_TYPE) & inferior_fp_registers, 0)) perror ("ptrace_setfpregs"); }
void uninsert_fast_tracepoint_jumps_at (CORE_ADDR pc) { struct fast_tracepoint_jump *jp; int err; jp = find_fast_tracepoint_jump_at (pc); if (jp == NULL) { /* This can happen when we remove all breakpoints while handling a step-over. */ if (debug_threads) fprintf (stderr, "Could not find fast tracepoint jump at 0x%s " "in list (uninserting).\n", paddress (pc)); return; } if (jp->inserted) { unsigned char *buf; jp->inserted = 0; /* Since there can be trap breakpoints inserted in the same address range, we use use `write_inferior_memory', which takes care of layering breakpoints on top of fast tracepoints, and on top of the buffer we pass it. This works because we've already marked the fast tracepoint fast tracepoint jump uninserted above. Also note that we need to pass the current shadow contents, because write_inferior_memory updates any shadow memory with what we pass here, and we want that to be a nop. */ buf = alloca (jp->length); memcpy (buf, fast_tracepoint_jump_shadow (jp), jp->length); err = write_inferior_memory (jp->pc, buf, jp->length); if (err != 0) { jp->inserted = 1; if (debug_threads) fprintf (stderr, "Failed to uninsert fast tracepoint jump at 0x%s (%s).\n", paddress (pc), strerror (err)); } } }
static void mygeneric_load (bfd *loadfile_bfd) { asection *s; for (s = loadfile_bfd->sections; s; s = s->next) { if (s->flags & SEC_LOAD) { bfd_size_type size; size = bfd_get_section_size_before_reloc (s); if (size > 0) { char *buffer; bfd_vma lma; /* use load address, not virtual address */ buffer = xmalloc (size); lma = s->lma; /* Is this really necessary? I guess it gives the user something * to look at during a long download. */ printf ("Loading section %s, size 0x%lx lma 0x%lx\n", bfd_get_section_name (loadfile_bfd, s), (unsigned long) size, (unsigned long) lma); /* chops high 32 bits. FIXME!! */ bfd_get_section_contents (loadfile_bfd, s, buffer, 0, size); write_inferior_memory (lma, buffer, size); free (buffer); } } } printf ("Start address 0x%lx\n", (unsigned long) loadfile_bfd->start_address); /* We were doing this in remote-mips.c, I suspect it is right * for other targets too. */ /* write_pc (loadfile_bfd->start_address); *//* FIXME!! */ }
int main (int argc, char *argv[]) { char ch, status, own_buf[PBUFSIZ], mem_buf[2000]; int i = 0; unsigned char signal; unsigned int len; CORE_ADDR mem_addr; if (setjmp (toplevel)) { fprintf (stderr, "Exiting\n"); exit (1); } if (argc < 3) error ("Usage: gdbserver tty prog [args ...]"); initialize_low (); /* Wait till we are at first instruction in program. */ signal = start_inferior (&argv[2], &status); /* We are now stopped at the first instruction of the target process */ while (1) { remote_open (argv[1]); restart: setjmp (toplevel); while (getpkt (own_buf) > 0) { unsigned char sig; i = 0; ch = own_buf[i++]; switch (ch) { case 'd': remote_debug = !remote_debug; break; case '!': extended_protocol = 1; prepare_resume_reply (own_buf, status, signal); break; case '?': prepare_resume_reply (own_buf, status, signal); break; case 'H': switch (own_buf[1]) { case 'g': general_thread = strtol (&own_buf[2], NULL, 16); write_ok (own_buf); fetch_inferior_registers (0); break; case 'c': cont_thread = strtol (&own_buf[2], NULL, 16); write_ok (own_buf); break; default: /* Silently ignore it so that gdb can extend the protocol without compatibility headaches. */ own_buf[0] = '\0'; break; } break; case 'g': convert_int_to_ascii (registers, own_buf, REGISTER_BYTES); break; case 'G': convert_ascii_to_int (&own_buf[1], registers, REGISTER_BYTES); store_inferior_registers (-1); write_ok (own_buf); break; case 'm': decode_m_packet (&own_buf[1], &mem_addr, &len); read_inferior_memory (mem_addr, mem_buf, len); convert_int_to_ascii (mem_buf, own_buf, len); break; case 'M': decode_M_packet (&own_buf[1], &mem_addr, &len, mem_buf); if (write_inferior_memory (mem_addr, mem_buf, len) == 0) write_ok (own_buf); else write_enn (own_buf); break; case 'C': convert_ascii_to_int (own_buf + 1, &sig, 1); myresume (0, sig); signal = mywait (&status); prepare_resume_reply (own_buf, status, signal); break; case 'S': convert_ascii_to_int (own_buf + 1, &sig, 1); myresume (1, sig); signal = mywait (&status); prepare_resume_reply (own_buf, status, signal); break; case 'c': myresume (0, 0); signal = mywait (&status); prepare_resume_reply (own_buf, status, signal); break; case 's': myresume (1, 0); signal = mywait (&status); prepare_resume_reply (own_buf, status, signal); break; case 'k': fprintf (stderr, "Killing inferior\n"); kill_inferior (); /* When using the extended protocol, we start up a new debugging session. The traditional protocol will exit instead. */ if (extended_protocol) { write_ok (own_buf); fprintf (stderr, "GDBserver restarting\n"); /* Wait till we are at 1st instruction in prog. */ signal = start_inferior (&argv[2], &status); goto restart; break; } else { exit (0); break; } case 'T': if (mythread_alive (strtol (&own_buf[1], NULL, 16))) write_ok (own_buf); else write_enn (own_buf); break; case 'R': /* Restarting the inferior is only supported in the extended protocol. */ if (extended_protocol) { kill_inferior (); write_ok (own_buf); fprintf (stderr, "GDBserver restarting\n"); /* Wait till we are at 1st instruction in prog. */ signal = start_inferior (&argv[2], &status); goto restart; break; } else { /* It is a request we don't understand. Respond with an empty packet so that gdb knows that we don't support this request. */ own_buf[0] = '\0'; break; } default: /* It is a request we don't understand. Respond with an empty packet so that gdb knows that we don't support this request. */ own_buf[0] = '\0'; break; } putpkt (own_buf); if (status == 'W') fprintf (stderr, "\nChild exited with status %d\n", sig); if (status == 'X') fprintf (stderr, "\nChild terminated with signal = 0x%x\n", sig); if (status == 'W' || status == 'X') { if (extended_protocol) { fprintf (stderr, "Killing inferior\n"); kill_inferior (); write_ok (own_buf); fprintf (stderr, "GDBserver restarting\n"); /* Wait till we are at 1st instruction in prog. */ signal = start_inferior (&argv[2], &status); goto restart; break; } else { fprintf (stderr, "GDBserver exiting\n"); exit (0); } } } /* We come here when getpkt fails. For the extended remote protocol we exit (and this is the only way we gracefully exit!). For the traditional remote protocol close the connection, and re-open it at the top of the loop. */ if (extended_protocol) { remote_close (); exit (0); } else { fprintf (stderr, "Remote side has terminated connection. GDBserver will reopen the connection.\n"); remote_close (); } } }
static int delete_raw_breakpoint (struct process_info *proc, struct raw_breakpoint *todel) { struct raw_breakpoint *bp, **bp_link; int ret; bp = proc->raw_breakpoints; bp_link = &proc->raw_breakpoints; while (bp) { if (bp == todel) { if (bp->inserted) { struct raw_breakpoint *prev_bp_link = *bp_link; unsigned char buf[MAX_BREAKPOINT_LEN]; *bp_link = bp->next; /* Since there can be trap breakpoints inserted in the same address range, we use `write_inferior_memory', which takes care of layering breakpoints on top of fast tracepoints, and on top of the buffer we pass it. This works because we've already unlinked the fast tracepoint jump above. Also note that we need to pass the current shadow contents, because write_inferior_memory updates any shadow memory with what we pass here, and we want that to be a nop. */ memcpy (buf, bp->old_data, breakpoint_len); ret = write_inferior_memory (bp->pc, buf, breakpoint_len); if (ret != 0) { /* Something went wrong, relink the breakpoint. */ *bp_link = prev_bp_link; if (debug_threads) fprintf (stderr, "Failed to uninsert raw breakpoint " "at 0x%s (%s) while deleting it.\n", paddress (bp->pc), strerror (ret)); return ret; } } else *bp_link = bp->next; free (bp); return 0; } else { bp_link = &bp->next; bp = *bp_link; } } warning ("Could not find raw breakpoint in list."); return ENOENT; }
int main (int argc, char *argv[]) { char ch, status, *own_buf, mem_buf[2000]; int i = 0; unsigned char signal; unsigned int len; CORE_ADDR mem_addr; int bad_attach; int pid; char *arg_end; if (setjmp (toplevel)) { fprintf (stderr, "Exiting\n"); exit (1); } bad_attach = 0; pid = 0; attached = 0; if (argc >= 3 && strcmp (argv[2], "--attach") == 0) { if (argc == 4 && argv[3] != '\0' && (pid = strtoul (argv[3], &arg_end, 10)) != 0 && *arg_end == '\0') { ; } else bad_attach = 1; } if (argc < 3 || bad_attach) gdbserver_usage(); initialize_low (); own_buf = malloc (PBUFSIZ); if (pid == 0) { /* Wait till we are at first instruction in program. */ signal = start_inferior (&argv[2], &status); /* We are now stopped at the first instruction of the target process */ } else { switch (attach_inferior (pid, &status, &signal)) { case -1: error ("Attaching not supported on this target"); break; default: attached = 1; break; } } while (1) { remote_open (argv[1]); restart: setjmp (toplevel); while (getpkt (own_buf) > 0) { unsigned char sig; i = 0; ch = own_buf[i++]; switch (ch) { case 'q': handle_query (own_buf); break; case 'd': remote_debug = !remote_debug; break; case 'D': fprintf (stderr, "Detaching from inferior\n"); detach_inferior (); write_ok (own_buf); putpkt (own_buf); remote_close (); /* If we are attached, then we can exit. Otherwise, we need to hang around doing nothing, until the child is gone. */ if (!attached) { int status, ret; do { ret = waitpid (signal_pid, &status, 0); if (WIFEXITED (status) || WIFSIGNALED (status)) break; } while (ret != -1 || errno != ECHILD); } exit (0); case '!': if (attached == 0) { extended_protocol = 1; prepare_resume_reply (own_buf, status, signal); } else { /* We can not use the extended protocol if we are attached, because we can not restart the running program. So return unrecognized. */ own_buf[0] = '\0'; } break; case '?': prepare_resume_reply (own_buf, status, signal); break; case 'H': switch (own_buf[1]) { case 'g': general_thread = strtol (&own_buf[2], NULL, 16); write_ok (own_buf); set_desired_inferior (1); break; case 'c': cont_thread = strtol (&own_buf[2], NULL, 16); write_ok (own_buf); break; case 's': step_thread = strtol (&own_buf[2], NULL, 16); write_ok (own_buf); break; default: /* Silently ignore it so that gdb can extend the protocol without compatibility headaches. */ own_buf[0] = '\0'; break; } break; case 'g': set_desired_inferior (1); registers_to_string (own_buf); break; case 'G': set_desired_inferior (1); registers_from_string (&own_buf[1]); write_ok (own_buf); break; case 'm': decode_m_packet (&own_buf[1], &mem_addr, &len); if (read_inferior_memory (mem_addr, mem_buf, len) == 0) convert_int_to_ascii (mem_buf, own_buf, len); else write_enn (own_buf); break; case 'M': decode_M_packet (&own_buf[1], &mem_addr, &len, mem_buf); if (write_inferior_memory (mem_addr, mem_buf, len) == 0) write_ok (own_buf); else write_enn (own_buf); break; case 'C': convert_ascii_to_int (own_buf + 1, &sig, 1); if (target_signal_to_host_p (sig)) signal = target_signal_to_host (sig); else signal = 0; set_desired_inferior (0); myresume (0, signal); signal = mywait (&status, 1); prepare_resume_reply (own_buf, status, signal); break; case 'S': convert_ascii_to_int (own_buf + 1, &sig, 1); if (target_signal_to_host_p (sig)) signal = target_signal_to_host (sig); else signal = 0; set_desired_inferior (0); myresume (1, signal); signal = mywait (&status, 1); prepare_resume_reply (own_buf, status, signal); break; case 'c': set_desired_inferior (0); myresume (0, 0); signal = mywait (&status, 1); prepare_resume_reply (own_buf, status, signal); break; case 's': set_desired_inferior (0); myresume (1, 0); signal = mywait (&status, 1); prepare_resume_reply (own_buf, status, signal); break; case 'k': fprintf (stderr, "Killing inferior\n"); kill_inferior (); /* When using the extended protocol, we start up a new debugging session. The traditional protocol will exit instead. */ if (extended_protocol) { write_ok (own_buf); fprintf (stderr, "GDBserver restarting\n"); /* Wait till we are at 1st instruction in prog. */ signal = start_inferior (&argv[2], &status); goto restart; break; } else { exit (0); break; } case 'T': if (mythread_alive (strtol (&own_buf[1], NULL, 16))) write_ok (own_buf); else write_enn (own_buf); break; case 'R': /* Restarting the inferior is only supported in the extended protocol. */ if (extended_protocol) { kill_inferior (); write_ok (own_buf); fprintf (stderr, "GDBserver restarting\n"); /* Wait till we are at 1st instruction in prog. */ signal = start_inferior (&argv[2], &status); goto restart; break; } else { /* It is a request we don't understand. Respond with an empty packet so that gdb knows that we don't support this request. */ own_buf[0] = '\0'; break; } case 'v': /* Extended (long) request. */ handle_v_requests (own_buf, &status, &signal); break; default: /* It is a request we don't understand. Respond with an empty packet so that gdb knows that we don't support this request. */ own_buf[0] = '\0'; break; } putpkt (own_buf); if (status == 'W') fprintf (stderr, "\nChild exited with status %d\n", signal); if (status == 'X') fprintf (stderr, "\nChild terminated with signal = 0x%x\n", signal); if (status == 'W' || status == 'X') { if (extended_protocol) { fprintf (stderr, "Killing inferior\n"); kill_inferior (); write_ok (own_buf); fprintf (stderr, "GDBserver restarting\n"); /* Wait till we are at 1st instruction in prog. */ signal = start_inferior (&argv[2], &status); goto restart; break; } else { fprintf (stderr, "GDBserver exiting\n"); exit (0); } } } /* We come here when getpkt fails. For the extended remote protocol we exit (and this is the only way we gracefully exit!). For the traditional remote protocol close the connection, and re-open it at the top of the loop. */ if (extended_protocol) { remote_close (); exit (0); } else { fprintf (stderr, "Remote side has terminated connection. " "GDBserver will reopen the connection.\n"); remote_close (); } } }
struct fast_tracepoint_jump * set_fast_tracepoint_jump (CORE_ADDR where, unsigned char *insn, ULONGEST length) { struct process_info *proc = current_process (); struct fast_tracepoint_jump *jp; int err; unsigned char *buf; /* We refcount fast tracepoint jumps. Check if we already know about a jump at this address. */ jp = find_fast_tracepoint_jump_at (where); if (jp != NULL) { jp->refcount++; return jp; } /* We don't, so create a new object. Double the length, because the flexible array member holds both the jump insn, and the shadow. */ jp = xcalloc (1, sizeof (*jp) + (length * 2)); jp->pc = where; jp->length = length; memcpy (fast_tracepoint_jump_insn (jp), insn, length); jp->refcount = 1; buf = alloca (length); /* Note that there can be trap breakpoints inserted in the same address range. To access the original memory contents, we use `read_inferior_memory', which masks out breakpoints. */ err = read_inferior_memory (where, buf, length); if (err != 0) { if (debug_threads) fprintf (stderr, "Failed to read shadow memory of" " fast tracepoint at 0x%s (%s).\n", paddress (where), strerror (err)); free (jp); return NULL; } memcpy (fast_tracepoint_jump_shadow (jp), buf, length); /* Link the jump in. */ jp->inserted = 1; jp->next = proc->fast_tracepoint_jumps; proc->fast_tracepoint_jumps = jp; /* Since there can be trap breakpoints inserted in the same address range, we use use `write_inferior_memory', which takes care of layering breakpoints on top of fast tracepoints, on top of the buffer we pass it. This works because we've already linked in the fast tracepoint jump above. Also note that we need to pass the current shadow contents, because write_inferior_memory updates any shadow memory with what we pass here, and we want that to be a nop. */ err = write_inferior_memory (where, buf, length); if (err != 0) { if (debug_threads) fprintf (stderr, "Failed to insert fast tracepoint jump at 0x%s (%s).\n", paddress (where), strerror (err)); /* Unlink it. */ proc->fast_tracepoint_jumps = jp->next; free (jp); return NULL; } return jp; }
ps_err_e ps_pdwrite (gdb_ps_prochandle_t ph, psaddr_t addr, gdb_ps_write_buf_t buf, gdb_ps_size_t size) { return write_inferior_memory ((unsigned long) addr, buf, size); }
int main (int argc, char *argv[]) { char ch, status, *own_buf; unsigned char *mem_buf; int i = 0; int signal; unsigned int len; CORE_ADDR mem_addr; int bad_attach; int pid; char *arg_end; if (argc >= 2 && strcmp (argv[1], "--version") == 0) { gdbserver_version (); exit (0); } if (argc >= 2 && strcmp (argv[1], "--help") == 0) { gdbserver_usage (); exit (0); } if (setjmp (toplevel)) { fprintf (stderr, "Exiting\n"); exit (1); } bad_attach = 0; pid = 0; attached = 0; if (argc >= 3 && strcmp (argv[2], "--attach") == 0) { if (argc == 4 && argv[3] != '\0' && (pid = strtoul (argv[3], &arg_end, 10)) != 0 && *arg_end == '\0') { ; } else bad_attach = 1; } if (argc < 3 || bad_attach) { gdbserver_usage (); exit (1); } initialize_low (); own_buf = malloc (PBUFSIZ); mem_buf = malloc (PBUFSIZ); if (pid == 0) { /* Wait till we are at first instruction in program. */ signal = start_inferior (&argv[2], &status); /* start_inferior() returns an integer, but the wait * function returns an unsigned char. in the case of * of an error, the wait returns -1 which means 255. */ if (status == 'W' || status == 'X') { fprintf (stderr, "Aborting server; child exited with %i\n", signal); exit (signal); } /* We are now stopped at the first instruction of the target process */ } else { switch (attach_inferior (pid, &status, &signal)) { case -1: error ("Attaching not supported on this target"); break; default: attached = 1; break; } } while (1) { remote_open (argv[1]); restart: setjmp (toplevel); while (1) { unsigned char sig; int packet_len; int new_packet_len = -1; packet_len = getpkt (own_buf); if (packet_len <= 0) break; i = 0; ch = own_buf[i++]; switch (ch) { case 'q': handle_query (own_buf, &new_packet_len); break; case 'd': remote_debug = !remote_debug; break; #ifndef USE_WIN32API /* Skip "detach" support on mingw32, since we don't have waitpid. */ case 'D': fprintf (stderr, "Detaching from inferior\n"); detach_inferior (); write_ok (own_buf); putpkt (own_buf); remote_close (); /* If we are attached, then we can exit. Otherwise, we need to hang around doing nothing, until the child is gone. */ if (!attached) { int status, ret; do { ret = waitpid (signal_pid, &status, 0); if (WIFEXITED (status) || WIFSIGNALED (status)) break; } while (ret != -1 || errno != ECHILD); } exit (0); #endif case '!': if (attached == 0) { extended_protocol = 1; prepare_resume_reply (own_buf, status, signal); } else { /* We can not use the extended protocol if we are attached, because we can not restart the running program. So return unrecognized. */ own_buf[0] = '\0'; } break; case '?': prepare_resume_reply (own_buf, status, signal); break; case 'H': if (own_buf[1] == 'c' || own_buf[1] == 'g' || own_buf[1] == 's') { unsigned long gdb_id, thread_id; gdb_id = strtoul (&own_buf[2], NULL, 16); thread_id = gdb_id_to_thread_id (gdb_id); if (thread_id == 0) { write_enn (own_buf); break; } if (own_buf[1] == 'g') { general_thread = thread_id; set_desired_inferior (1); } else if (own_buf[1] == 'c') cont_thread = thread_id; else if (own_buf[1] == 's') step_thread = thread_id; write_ok (own_buf); } else { /* Silently ignore it so that gdb can extend the protocol without compatibility headaches. */ own_buf[0] = '\0'; } break; case 'g': set_desired_inferior (1); registers_to_string (own_buf); break; case 'G': set_desired_inferior (1); registers_from_string (&own_buf[1]); write_ok (own_buf); break; case 'm': decode_m_packet (&own_buf[1], &mem_addr, &len); if (read_inferior_memory (mem_addr, mem_buf, len) == 0) convert_int_to_ascii (mem_buf, own_buf, len); else write_enn (own_buf); break; case 'M': decode_M_packet (&own_buf[1], &mem_addr, &len, mem_buf); if (write_inferior_memory (mem_addr, mem_buf, len) == 0) write_ok (own_buf); else write_enn (own_buf); break; case 'X': if (decode_X_packet (&own_buf[1], packet_len - 1, &mem_addr, &len, mem_buf) < 0 || write_inferior_memory (mem_addr, mem_buf, len) != 0) write_enn (own_buf); else write_ok (own_buf); break; case 'C': convert_ascii_to_int (own_buf + 1, &sig, 1); if (target_signal_to_host_p (sig)) signal = target_signal_to_host (sig); else signal = 0; set_desired_inferior (0); myresume (0, signal); signal = mywait (&status, 1); prepare_resume_reply (own_buf, status, signal); break; case 'S': convert_ascii_to_int (own_buf + 1, &sig, 1); if (target_signal_to_host_p (sig)) signal = target_signal_to_host (sig); else signal = 0; set_desired_inferior (0); myresume (1, signal); signal = mywait (&status, 1); prepare_resume_reply (own_buf, status, signal); break; case 'c': set_desired_inferior (0); myresume (0, 0); signal = mywait (&status, 1); prepare_resume_reply (own_buf, status, signal); break; case 's': set_desired_inferior (0); myresume (1, 0); signal = mywait (&status, 1); prepare_resume_reply (own_buf, status, signal); break; case 'Z': { char *lenptr; char *dataptr; CORE_ADDR addr = strtoul (&own_buf[3], &lenptr, 16); int len = strtol (lenptr + 1, &dataptr, 16); char type = own_buf[1]; if (the_target->insert_watchpoint == NULL || (type < '2' || type > '4')) { /* No watchpoint support or not a watchpoint command; unrecognized either way. */ own_buf[0] = '\0'; } else { int res; res = (*the_target->insert_watchpoint) (type, addr, len); if (res == 0) write_ok (own_buf); else if (res == 1) /* Unsupported. */ own_buf[0] = '\0'; else write_enn (own_buf); } break; } case 'z': { char *lenptr; char *dataptr; CORE_ADDR addr = strtoul (&own_buf[3], &lenptr, 16); int len = strtol (lenptr + 1, &dataptr, 16); char type = own_buf[1]; if (the_target->remove_watchpoint == NULL || (type < '2' || type > '4')) { /* No watchpoint support or not a watchpoint command; unrecognized either way. */ own_buf[0] = '\0'; } else { int res; res = (*the_target->remove_watchpoint) (type, addr, len); if (res == 0) write_ok (own_buf); else if (res == 1) /* Unsupported. */ own_buf[0] = '\0'; else write_enn (own_buf); } break; } case 'k': fprintf (stderr, "Killing inferior\n"); kill_inferior (); /* When using the extended protocol, we start up a new debugging session. The traditional protocol will exit instead. */ if (extended_protocol) { write_ok (own_buf); fprintf (stderr, "GDBserver restarting\n"); /* Wait till we are at 1st instruction in prog. */ signal = start_inferior (&argv[2], &status); goto restart; break; } else { exit (0); break; } case 'T': { unsigned long gdb_id, thread_id; gdb_id = strtoul (&own_buf[1], NULL, 16); thread_id = gdb_id_to_thread_id (gdb_id); if (thread_id == 0) { write_enn (own_buf); break; } if (mythread_alive (thread_id)) write_ok (own_buf); else write_enn (own_buf); } break; case 'R': /* Restarting the inferior is only supported in the extended protocol. */ if (extended_protocol) { kill_inferior (); write_ok (own_buf); fprintf (stderr, "GDBserver restarting\n"); /* Wait till we are at 1st instruction in prog. */ signal = start_inferior (&argv[2], &status); goto restart; break; } else { /* It is a request we don't understand. Respond with an empty packet so that gdb knows that we don't support this request. */ own_buf[0] = '\0'; break; } case 'v': /* Extended (long) request. */ handle_v_requests (own_buf, &status, &signal); break; default: /* It is a request we don't understand. Respond with an empty packet so that gdb knows that we don't support this request. */ own_buf[0] = '\0'; break; } if (new_packet_len != -1) putpkt_binary (own_buf, new_packet_len); else putpkt (own_buf); if (status == 'W') fprintf (stderr, "\nChild exited with status %d\n", signal); if (status == 'X') fprintf (stderr, "\nChild terminated with signal = 0x%x (%s)\n", target_signal_to_host (signal), target_signal_to_name (signal)); if (status == 'W' || status == 'X') { if (extended_protocol) { fprintf (stderr, "Killing inferior\n"); kill_inferior (); write_ok (own_buf); fprintf (stderr, "GDBserver restarting\n"); /* Wait till we are at 1st instruction in prog. */ signal = start_inferior (&argv[2], &status); goto restart; break; } else { fprintf (stderr, "GDBserver exiting\n"); exit (0); } } } /* We come here when getpkt fails. For the extended remote protocol we exit (and this is the only way we gracefully exit!). For the traditional remote protocol close the connection, and re-open it at the top of the loop. */ if (extended_protocol) { remote_close (); exit (0); } else { fprintf (stderr, "Remote side has terminated connection. " "GDBserver will reopen the connection.\n"); remote_close (); } } }
int delete_fast_tracepoint_jump (struct fast_tracepoint_jump *todel) { struct fast_tracepoint_jump *bp, **bp_link; int ret; struct process_info *proc = current_process (); bp = proc->fast_tracepoint_jumps; bp_link = &proc->fast_tracepoint_jumps; while (bp) { if (bp == todel) { if (--bp->refcount == 0) { struct fast_tracepoint_jump *prev_bp_link = *bp_link; unsigned char *buf; /* Unlink it. */ *bp_link = bp->next; /* Since there can be breakpoints inserted in the same address range, we use `write_inferior_memory', which takes care of layering breakpoints on top of fast tracepoints, and on top of the buffer we pass it. This works because we've already unlinked the fast tracepoint jump above. Also note that we need to pass the current shadow contents, because write_inferior_memory updates any shadow memory with what we pass here, and we want that to be a nop. */ buf = alloca (bp->length); memcpy (buf, fast_tracepoint_jump_shadow (bp), bp->length); ret = write_inferior_memory (bp->pc, buf, bp->length); if (ret != 0) { /* Something went wrong, relink the jump. */ *bp_link = prev_bp_link; if (debug_threads) fprintf (stderr, "Failed to uninsert fast tracepoint jump " "at 0x%s (%s) while deleting it.\n", paddress (bp->pc), strerror (ret)); return ret; } free (bp); } return 0; } else { bp_link = &bp->next; bp = *bp_link; } } warning ("Could not find fast tracepoint jump in list."); return ENOENT; }
int target_write_memory (CORE_ADDR memaddr, const gdb_byte *myaddr, ssize_t len) { return write_inferior_memory (memaddr, myaddr, len); }
void gdbserver_main (void) { CORE_ADDR mem_addr; char *own_buf; unsigned char *mem_buf; int i = 0; unsigned int len; own_buf = malloc (PBUFSIZ + 1); mem_buf = malloc (PBUFSIZ); while (1) { remote_open (port); restart: #if 0 if (setjmp (toplevel) != 0) { /* An error occurred. */ if (response_needed) { write_enn (own_buf); putpkt (own_buf); } } #endif disable_async_io (); while (!exit_requested) { unsigned char sig; int packet_len; int new_packet_len = -1; response_needed = 0; packet_len = getpkt (own_buf); if (packet_len <= 0) break; response_needed = 1; i = 0; ch = own_buf[i++]; switch (ch) { case 'q': handle_query (own_buf, packet_len, &new_packet_len); break; case 'Q': handle_general_set (own_buf); break; case 'D': require_running (own_buf); fprintf (stderr, "Detaching from inferior\n"); if (detach_inferior () != 0) write_enn (own_buf); else { write_ok (own_buf); if (extended_protocol) { /* Treat this like a normal program exit. */ signal = 0; status = 'W'; } else { putpkt (own_buf); remote_close (); /* If we are attached, then we can exit. Otherwise, we need to hang around doing nothing, until the child is gone. */ if (!attached) join_inferior (); exit (0); } } break; case '!': extended_protocol = 1; write_ok (own_buf); break; case '?': prepare_resume_reply (own_buf, status, signal); break; case 'H': if (own_buf[1] == 'c' || own_buf[1] == 'g' || own_buf[1] == 's') { unsigned long gdb_id, thread_id; require_running (own_buf); gdb_id = strtoul (&own_buf[2], NULL, 16); if (gdb_id == 0 || gdb_id == -1) thread_id = gdb_id; else { thread_id = gdb_id_to_thread_id (gdb_id); if (thread_id == 0) { write_enn (own_buf); break; } } if (own_buf[1] == 'g') { general_thread = thread_id; set_desired_inferior (1); } else if (own_buf[1] == 'c') cont_thread = thread_id; else if (own_buf[1] == 's') step_thread = thread_id; write_ok (own_buf); } else { /* Silently ignore it so that gdb can extend the protocol without compatibility headaches. */ own_buf[0] = '\0'; } break; case 'g': require_running (own_buf); set_desired_inferior (1); registers_to_string (own_buf); break; case 'G': require_running (own_buf); set_desired_inferior (1); registers_from_string (&own_buf[1]); write_ok (own_buf); break; case 'm': require_running (own_buf); decode_m_packet (&own_buf[1], &mem_addr, &len); if (read_inferior_memory (mem_addr, mem_buf, len) == 0) convert_int_to_ascii (mem_buf, own_buf, len); else write_enn (own_buf); break; case 'M': require_running (own_buf); decode_M_packet (&own_buf[1], &mem_addr, &len, mem_buf); if (write_inferior_memory (mem_addr, mem_buf, len) == 0) write_ok (own_buf); else write_enn (own_buf); break; case 'X': require_running (own_buf); if (decode_X_packet (&own_buf[1], packet_len - 1, &mem_addr, &len, mem_buf) < 0 || write_inferior_memory (mem_addr, mem_buf, len) != 0) write_enn (own_buf); else write_ok (own_buf); break; case 'C': require_running (own_buf); convert_ascii_to_int (own_buf + 1, &sig, 1); if (target_signal_to_host_p (sig)) signal = target_signal_to_host (sig); else signal = 0; myresume (own_buf, 0, &signal, &status); break; case 'S': require_running (own_buf); convert_ascii_to_int (own_buf + 1, &sig, 1); if (target_signal_to_host_p (sig)) signal = target_signal_to_host (sig); else signal = 0; myresume (own_buf, 1, &signal, &status); break; case 'c': require_running (own_buf); signal = 0; myresume (own_buf, 0, &signal, &status); break; case 's': require_running (own_buf); signal = 0; myresume (own_buf, 1, &signal, &status); break; case 'Z': { char *lenptr; char *dataptr; CORE_ADDR addr = strtoul (&own_buf[3], &lenptr, 16); int len = strtol (lenptr + 1, &dataptr, 16); char type = own_buf[1]; if (the_target->insert_watchpoint == NULL || (type < '2' || type > '4')) { /* No watchpoint support or not a watchpoint command; unrecognized either way. */ own_buf[0] = '\0'; } else { int res; require_running (own_buf); res = (*the_target->insert_watchpoint) (type, addr, len); if (res == 0) write_ok (own_buf); else if (res == 1) /* Unsupported. */ own_buf[0] = '\0'; else write_enn (own_buf); } break; } case 'z': { char *lenptr; char *dataptr; CORE_ADDR addr = strtoul (&own_buf[3], &lenptr, 16); int len = strtol (lenptr + 1, &dataptr, 16); char type = own_buf[1]; if (the_target->remove_watchpoint == NULL || (type < '2' || type > '4')) { /* No watchpoint support or not a watchpoint command; unrecognized either way. */ own_buf[0] = '\0'; } else { int res; require_running (own_buf); res = (*the_target->remove_watchpoint) (type, addr, len); if (res == 0) write_ok (own_buf); else if (res == 1) /* Unsupported. */ own_buf[0] = '\0'; else write_enn (own_buf); } break; } case 'k': response_needed = 0; if (!target_running ()) /* The packet we received doesn't make sense - but we can't reply to it, either. */ goto restart; fprintf (stderr, "Killing inferior\n"); kill_inferior (); /* When using the extended protocol, we wait with no program running. The traditional protocol will exit instead. */ if (extended_protocol) { status = 'X'; signal = TARGET_SIGNAL_KILL; was_running = 0; goto restart; } else { exit (0); break; } case 'T': { unsigned long gdb_id, thread_id; require_running (own_buf); gdb_id = strtoul (&own_buf[1], NULL, 16); thread_id = gdb_id_to_thread_id (gdb_id); if (thread_id == 0) { write_enn (own_buf); break; } if (mythread_alive (thread_id)) write_ok (own_buf); else write_enn (own_buf); } break; case 'R': response_needed = 0; /* Restarting the inferior is only supported in the extended protocol. */ if (extended_protocol) { if (target_running ()) kill_inferior (); fprintf (stderr, "GDBserver restarting\n"); /* Wait till we are at 1st instruction in prog. */ if (program_argv != NULL) signal = start_inferior (program_argv, &status); else { status = 'X'; signal = TARGET_SIGNAL_KILL; } goto restart; } else { /* It is a request we don't understand. Respond with an empty packet so that gdb knows that we don't support this request. */ own_buf[0] = '\0'; break; } case 'v': /* Extended (long) request. */ handle_v_requests (own_buf, &status, &signal, packet_len, &new_packet_len); break; default: /* It is a request we don't understand. Respond with an empty packet so that gdb knows that we don't support this request. */ own_buf[0] = '\0'; break; } if (new_packet_len != -1) putpkt_binary (own_buf, new_packet_len); else putpkt (own_buf); response_needed = 0; if (was_running && (status == 'W' || status == 'X')) { was_running = 0; if (status == 'W') fprintf (stderr, "\nChild exited with status %d\n", signal); if (status == 'X') fprintf (stderr, "\nChild terminated with signal = 0x%x (%s)\n", target_signal_to_host (signal), target_signal_to_name (signal)); if (extended_protocol) goto restart; else { fprintf (stderr, "GDBserver exiting\n"); exit (0); } } if (status != 'W' && status != 'X') was_running = 1; } /* If an exit was requested (using the "monitor exit" command), terminate now. The only other way to get here is for getpkt to fail; close the connection and reopen it at the top of the loop. */ if (exit_requested) { remote_close (); if (attached && target_running ()) detach_inferior (); else if (target_running ()) kill_inferior (); exit (0); } else { fprintf (stderr, "Remote side has terminated connection. " "GDBserver will reopen the connection.\n"); remote_close (); } } }
int main (int argc, char *argv[]) { char ch, status, *own_buf; unsigned char *mem_buf; int i = 0; int signal; unsigned int len; CORE_ADDR mem_addr; int bad_attach; int pid; char *arg_end; my_stdout = stdout; my_stderr = stderr; myname = argv[0]; if (argc >= 2 && strcmp (argv[1], "--version") == 0) { gdbserver_version (); exit (0); } if (argc >= 2 && strcmp (argv[1], "--help") == 0) { gdbserver_usage (); exit (0); } if (setjmp (toplevel)) { warning ("Exiting"); exit (1); } bad_attach = 0; pid = 0; attached = 0; if (argc >= 3 && strcmp (argv[2], "--attach") == 0) { if (argc == 4 && argv[3][0] != '\0' && (pid = strtoul (argv[3], &arg_end, 10)) != 0 && *arg_end == '\0') { ; } else bad_attach = 1; } if (argc < 3 || bad_attach) { gdbserver_usage (); exit (1); } if (strcmp (argv[1], "pipe") == 0) { my_stdout = my_stderr = stderr; } initialize_low (); own_buf = malloc (PBUFSIZ + 1); mem_buf = malloc (PBUFSIZ); if (pid == 0) { /* Wait till we are at first instruction in program. */ signal = start_inferior (&argv[2], &status); /* We are now (hopefully) stopped at the first instruction of the target process. This assumes that the target process was successfully created. */ /* Don't report shared library events on the initial connection, even if some libraries are preloaded. */ dlls_changed = 0; } else { switch (attach_inferior (pid, &status, &signal)) { case -1: error ("Attaching not supported on this target"); break; default: attached = 1; break; } } if (setjmp (toplevel)) { warning ("Killing inferior"); kill_inferior (); exit (1); } if (status == 'W' || status == 'X') { warning ("No inferior, GDBserver exiting."); exit (1); } while (1) { remote_open (argv[1]); restart: if (setjmp (toplevel)) { if (remote_debug) printf_filtered ("gdbserver: error returned to main loop\n"); write_enn (own_buf); putpkt (own_buf); } while (1) { unsigned char sig; int packet_len; int new_packet_len = -1; packet_len = getpkt (own_buf, PBUFSIZ); if (packet_len <= 0) break; i = 0; ch = own_buf[i++]; switch (ch) { case 'q': handle_query (own_buf, packet_len, &new_packet_len); break; case 'Q': handle_general_set (own_buf); break; case 'D': warning ("Detaching from inferior"); if (detach_inferior () != 0) { write_enn (own_buf); putpkt (own_buf); } else { write_ok (own_buf); putpkt (own_buf); remote_close (); /* If we are attached, then we can exit. Otherwise, we need to hang around doing nothing, until the child is gone. */ if (!attached) join_inferior (); exit (0); } case '!': if (attached == 0) { extended_protocol = 1; prepare_resume_reply (own_buf, status, signal); } else { /* We can not use the extended protocol if we are attached, because we can not restart the running program. So return unrecognized. */ own_buf[0] = '\0'; } break; case '?': prepare_resume_reply (own_buf, status, signal); break; case 'H': if (own_buf[1] == 'c' || own_buf[1] == 'g' || own_buf[1] == 's') { unsigned long gdb_id, thread_id; gdb_id = strtoul (&own_buf[2], NULL, 16); thread_id = gdb_id_to_thread_id (gdb_id); if (thread_id == 0) { write_enn (own_buf); break; } if (own_buf[1] == 'g') { general_thread = thread_id; set_desired_inferior (1); } else if (own_buf[1] == 'c') cont_thread = thread_id; else if (own_buf[1] == 's') step_thread = thread_id; write_ok (own_buf); } else { /* Silently ignore it so that gdb can extend the protocol without compatibility headaches. */ own_buf[0] = '\0'; } break; case 'g': set_desired_inferior (1); registers_to_string (own_buf); break; case 'G': set_desired_inferior (1); registers_from_string (&own_buf[1]); write_ok (own_buf); break; case 'm': decode_m_packet (&own_buf[1], &mem_addr, &len); if (read_inferior_memory (mem_addr, mem_buf, len) == 0) convert_int_to_ascii (mem_buf, own_buf, len); else write_enn (own_buf); break; case 'M': decode_M_packet (&own_buf[1], &mem_addr, &len, mem_buf); if (write_inferior_memory (mem_addr, mem_buf, len) == 0) write_ok (own_buf); else write_enn (own_buf); break; case 'X': if (decode_X_packet (&own_buf[1], packet_len - 1, &mem_addr, &len, mem_buf) < 0 || write_inferior_memory (mem_addr, mem_buf, len) != 0) write_enn (own_buf); else write_ok (own_buf); break; case 'C': convert_ascii_to_int (own_buf + 1, &sig, 1); if (target_signal_to_host_p (sig)) signal = target_signal_to_host (sig); else signal = 0; set_desired_inferior (0); myresume (0, signal); signal = mywait (&status, 1); prepare_resume_reply (own_buf, status, signal); break; case 'S': convert_ascii_to_int (own_buf + 1, &sig, 1); if (target_signal_to_host_p (sig)) signal = target_signal_to_host (sig); else signal = 0; set_desired_inferior (0); myresume (1, signal); signal = mywait (&status, 1); prepare_resume_reply (own_buf, status, signal); break; case 'c': set_desired_inferior (0); myresume (0, 0); signal = mywait (&status, 1); prepare_resume_reply (own_buf, status, signal); break; case 's': set_desired_inferior (0); myresume (1, 0); signal = mywait (&status, 1); prepare_resume_reply (own_buf, status, signal); break; case 'z': case 'Z': { char *lenptr; char *dataptr; CORE_ADDR addr = strtoul (&own_buf[3], &lenptr, 16); int len = strtol (lenptr + 1, &dataptr, 16); char type = own_buf[1]; if (the_target->insert_watchpoint == NULL || the_target->remove_watchpoint == NULL || (type < '0' || type > '4')) { /* No watchpoint support or not a watchpoint command; unrecognized either way. */ own_buf[0] = '\0'; } else { int res; if (ch == 'z') res = (*the_target->remove_watchpoint) (type, addr, len); else res = (*the_target->insert_watchpoint) (type, addr, len); if (res == 0) write_ok (own_buf); else if (res == 1) /* Unsupported. */ own_buf[0] = '\0'; else write_enn (own_buf); } break; } case 'k': warning ("Killing inferior"); kill_inferior (); /* When using the extended protocol, we start up a new debugging session. The traditional protocol will exit instead. */ if (extended_protocol) { write_ok (own_buf); warning ("GDBserver restarting"); /* Wait till we are at 1st instruction in prog. */ signal = start_inferior (&argv[2], &status); goto restart; break; } else { exit (0); break; } case 'T': { unsigned long gdb_id, thread_id; gdb_id = strtoul (&own_buf[1], NULL, 16); thread_id = gdb_id_to_thread_id (gdb_id); if (thread_id == 0) { write_enn (own_buf); break; } if (mythread_alive (thread_id)) write_ok (own_buf); else write_enn (own_buf); } break; case 'R': /* Restarting the inferior is only supported in the extended protocol. */ if (extended_protocol) { kill_inferior (); write_ok (own_buf); warning ("GDBserver restarting"); /* Wait till we are at 1st instruction in prog. */ signal = start_inferior (&argv[2], &status); goto restart; break; } else { /* It is a request we don't understand. Respond with an empty packet so that gdb knows that we don't support this request. */ own_buf[0] = '\0'; break; } case 'v': /* Extended (long) request. */ handle_v_requests (own_buf, &status, &signal); break; default: /* It is a request we don't understand. Respond with an empty packet so that gdb knows that we don't support this request. */ own_buf[0] = '\0'; break; } if (new_packet_len != -1) putpkt_binary (own_buf, new_packet_len); else putpkt (own_buf); if (status == 'W') warning ("\nChild exited with status %d", signal); if (status == 'X') warning ("\nChild terminated with signal = 0x%x (%s)", target_signal_to_host (signal), target_signal_to_name (signal)); if (status == 'W' || status == 'X') { if (extended_protocol) { warning ("Killing inferior"); kill_inferior (); write_ok (own_buf); warning ("GDBserver restarting"); /* Wait till we are at 1st instruction in prog. */ signal = start_inferior (&argv[2], &status); goto restart; break; } else { warning ("GDBserver exiting"); exit (0); } } } /* We come here when getpkt fails. For the extended remote protocol we exit (and this is the only way we gracefully exit!). For the traditional remote protocol close the connection, and re-open it at the top of the loop. */ if (extended_protocol) { remote_close (); exit (0); } else { warning ("Remote side has terminated connection. " "GDBserver will reopen the connection."); remote_close (); } } }
int main (int argc, char *argv[]) { char ch, status, *own_buf; unsigned char *mem_buf; int i = 0; int signal; unsigned int len; CORE_ADDR mem_addr; int bad_attach; int pid; char *arg_end, *port; char **next_arg = &argv[1]; int multi_mode = 0; int attach = 0; int was_running; while (*next_arg != NULL && **next_arg == '-') { if (strcmp (*next_arg, "--version") == 0) { gdbserver_version (); exit (0); } else if (strcmp (*next_arg, "--help") == 0) { gdbserver_usage (stdout); exit (0); } else if (strcmp (*next_arg, "--attach") == 0) attach = 1; else if (strcmp (*next_arg, "--multi") == 0) multi_mode = 1; else if (strcmp (*next_arg, "--wrapper") == 0) { next_arg++; wrapper_argv = next_arg; while (*next_arg != NULL && strcmp (*next_arg, "--") != 0) next_arg++; if (next_arg == wrapper_argv || *next_arg == NULL) { gdbserver_usage (stderr); exit (1); } /* Consume the "--". */ *next_arg = NULL; } else if (strcmp (*next_arg, "--debug") == 0) debug_threads = 1; else if (strcmp (*next_arg, "--disable-packet") == 0) { gdbserver_show_disableable (stdout); exit (0); } else if (strncmp (*next_arg, "--disable-packet=", sizeof ("--disable-packet=") - 1) == 0) { char *packets, *tok; packets = *next_arg += sizeof ("--disable-packet=") - 1; for (tok = strtok (packets, ","); tok != NULL; tok = strtok (NULL, ",")) { if (strcmp ("vCont", tok) == 0) disable_packet_vCont = 1; else if (strcmp ("Tthread", tok) == 0) disable_packet_Tthread = 1; else if (strcmp ("qC", tok) == 0) disable_packet_qC = 1; else if (strcmp ("qfThreadInfo", tok) == 0) disable_packet_qfThreadInfo = 1; else if (strcmp ("threads", tok) == 0) { disable_packet_vCont = 1; disable_packet_Tthread = 1; disable_packet_qC = 1; disable_packet_qfThreadInfo = 1; } else { fprintf (stderr, "Don't know how to disable \"%s\".\n\n", tok); gdbserver_show_disableable (stderr); exit (1); } } } else { fprintf (stderr, "Unknown argument: %s\n", *next_arg); exit (1); } next_arg++; continue; } if (setjmp (toplevel)) { fprintf (stderr, "Exiting\n"); exit (1); } port = *next_arg; next_arg++; if (port == NULL || (!attach && !multi_mode && *next_arg == NULL)) { gdbserver_usage (stderr); exit (1); } bad_attach = 0; pid = 0; /* --attach used to come after PORT, so allow it there for compatibility. */ if (*next_arg != NULL && strcmp (*next_arg, "--attach") == 0) { attach = 1; next_arg++; } if (attach && (*next_arg == NULL || (*next_arg)[0] == '\0' || (pid = strtoul (*next_arg, &arg_end, 0)) == 0 || *arg_end != '\0' || next_arg[1] != NULL)) bad_attach = 1; if (bad_attach) { gdbserver_usage (stderr); exit (1); } initialize_async_io (); initialize_low (); own_buf = malloc (PBUFSIZ + 1); mem_buf = malloc (PBUFSIZ); if (pid == 0 && *next_arg != NULL) { int i, n; n = argc - (next_arg - argv); program_argv = malloc (sizeof (char *) * (n + 1)); for (i = 0; i < n; i++) program_argv[i] = strdup (next_arg[i]); program_argv[i] = NULL; /* Wait till we are at first instruction in program. */ signal = start_inferior (program_argv, &status); /* We are now (hopefully) stopped at the first instruction of the target process. This assumes that the target process was successfully created. */ } else if (pid != 0) { if (attach_inferior (pid, &status, &signal) == -1) error ("Attaching not supported on this target"); /* Otherwise succeeded. */ } else { status = 'W'; signal = 0; } /* Don't report shared library events on the initial connection, even if some libraries are preloaded. Avoids the "stopped by shared library event" notice on gdb side. */ dlls_changed = 0; if (setjmp (toplevel)) { fprintf (stderr, "Killing inferior\n"); kill_inferior (); exit (1); } if (status == 'W' || status == 'X') was_running = 0; else was_running = 1; if (!was_running && !multi_mode) { fprintf (stderr, "No program to debug. GDBserver exiting.\n"); exit (1); } while (1) { noack_mode = 0; remote_open (port); restart: if (setjmp (toplevel) != 0) { /* An error occurred. */ if (response_needed) { write_enn (own_buf); putpkt (own_buf); } } disable_async_io (); while (!exit_requested) { unsigned char sig; int packet_len; int new_packet_len = -1; response_needed = 0; packet_len = getpkt (own_buf); if (packet_len <= 0) break; response_needed = 1; i = 0; ch = own_buf[i++]; switch (ch) { case 'q': handle_query (own_buf, packet_len, &new_packet_len); break; case 'Q': handle_general_set (own_buf); break; case 'D': require_running (own_buf); fprintf (stderr, "Detaching from inferior\n"); if (detach_inferior () != 0) write_enn (own_buf); else { write_ok (own_buf); if (extended_protocol) { /* Treat this like a normal program exit. */ signal = 0; status = 'W'; } else { putpkt (own_buf); remote_close (); /* If we are attached, then we can exit. Otherwise, we need to hang around doing nothing, until the child is gone. */ if (!attached) join_inferior (); exit (0); } } break; case '!': extended_protocol = 1; write_ok (own_buf); break; case '?': prepare_resume_reply (own_buf, status, signal); break; case 'H': if (own_buf[1] == 'c' || own_buf[1] == 'g' || own_buf[1] == 's') { unsigned long gdb_id, thread_id; require_running (own_buf); gdb_id = strtoul (&own_buf[2], NULL, 16); if (gdb_id == 0 || gdb_id == -1) thread_id = gdb_id; else { thread_id = gdb_id_to_thread_id (gdb_id); if (thread_id == 0) { write_enn (own_buf); break; } } if (own_buf[1] == 'g') { general_thread = thread_id; set_desired_inferior (1); } else if (own_buf[1] == 'c') cont_thread = thread_id; else if (own_buf[1] == 's') step_thread = thread_id; write_ok (own_buf); } else { /* Silently ignore it so that gdb can extend the protocol without compatibility headaches. */ own_buf[0] = '\0'; } break; case 'g': require_running (own_buf); set_desired_inferior (1); registers_to_string (own_buf); break; case 'G': require_running (own_buf); set_desired_inferior (1); registers_from_string (&own_buf[1]); write_ok (own_buf); break; case 'm': require_running (own_buf); decode_m_packet (&own_buf[1], &mem_addr, &len); if (read_inferior_memory (mem_addr, mem_buf, len) == 0) convert_int_to_ascii (mem_buf, own_buf, len); else write_enn (own_buf); break; case 'M': require_running (own_buf); decode_M_packet (&own_buf[1], &mem_addr, &len, mem_buf); if (write_inferior_memory (mem_addr, mem_buf, len) == 0) write_ok (own_buf); else write_enn (own_buf); break; case 'X': require_running (own_buf); if (decode_X_packet (&own_buf[1], packet_len - 1, &mem_addr, &len, mem_buf) < 0 || write_inferior_memory (mem_addr, mem_buf, len) != 0) write_enn (own_buf); else write_ok (own_buf); break; case 'C': require_running (own_buf); convert_ascii_to_int (own_buf + 1, &sig, 1); if (target_signal_to_host_p (sig)) signal = target_signal_to_host (sig); else signal = 0; myresume (own_buf, 0, &signal, &status); break; case 'S': require_running (own_buf); convert_ascii_to_int (own_buf + 1, &sig, 1); if (target_signal_to_host_p (sig)) signal = target_signal_to_host (sig); else signal = 0; myresume (own_buf, 1, &signal, &status); break; case 'c': require_running (own_buf); signal = 0; myresume (own_buf, 0, &signal, &status); break; case 's': require_running (own_buf); signal = 0; myresume (own_buf, 1, &signal, &status); break; case 'Z': { char *lenptr; char *dataptr; CORE_ADDR addr = strtoul (&own_buf[3], &lenptr, 16); int len = strtol (lenptr + 1, &dataptr, 16); char type = own_buf[1]; if (the_target->insert_watchpoint == NULL || (type < '2' || type > '4')) { /* No watchpoint support or not a watchpoint command; unrecognized either way. */ own_buf[0] = '\0'; } else { int res; require_running (own_buf); res = (*the_target->insert_watchpoint) (type, addr, len); if (res == 0) write_ok (own_buf); else if (res == 1) /* Unsupported. */ own_buf[0] = '\0'; else write_enn (own_buf); } break; } case 'z': { char *lenptr; char *dataptr; CORE_ADDR addr = strtoul (&own_buf[3], &lenptr, 16); int len = strtol (lenptr + 1, &dataptr, 16); char type = own_buf[1]; if (the_target->remove_watchpoint == NULL || (type < '2' || type > '4')) { /* No watchpoint support or not a watchpoint command; unrecognized either way. */ own_buf[0] = '\0'; } else { int res; require_running (own_buf); res = (*the_target->remove_watchpoint) (type, addr, len); if (res == 0) write_ok (own_buf); else if (res == 1) /* Unsupported. */ own_buf[0] = '\0'; else write_enn (own_buf); } break; } case 'k': response_needed = 0; if (!target_running ()) /* The packet we received doesn't make sense - but we can't reply to it, either. */ goto restart; fprintf (stderr, "Killing inferior\n"); kill_inferior (); /* When using the extended protocol, we wait with no program running. The traditional protocol will exit instead. */ if (extended_protocol) { status = 'X'; signal = TARGET_SIGNAL_KILL; was_running = 0; goto restart; } else { exit (0); break; } case 'T': { unsigned long gdb_id, thread_id; require_running (own_buf); gdb_id = strtoul (&own_buf[1], NULL, 16); thread_id = gdb_id_to_thread_id (gdb_id); if (thread_id == 0) { write_enn (own_buf); break; } if (mythread_alive (thread_id)) write_ok (own_buf); else write_enn (own_buf); } break; case 'R': response_needed = 0; /* Restarting the inferior is only supported in the extended protocol. */ if (extended_protocol) { if (target_running ()) kill_inferior (); fprintf (stderr, "GDBserver restarting\n"); /* Wait till we are at 1st instruction in prog. */ if (program_argv != NULL) signal = start_inferior (program_argv, &status); else { status = 'X'; signal = TARGET_SIGNAL_KILL; } goto restart; } else { /* It is a request we don't understand. Respond with an empty packet so that gdb knows that we don't support this request. */ own_buf[0] = '\0'; break; } case 'v': /* Extended (long) request. */ handle_v_requests (own_buf, &status, &signal, packet_len, &new_packet_len); break; default: /* It is a request we don't understand. Respond with an empty packet so that gdb knows that we don't support this request. */ own_buf[0] = '\0'; break; } if (new_packet_len != -1) putpkt_binary (own_buf, new_packet_len); else putpkt (own_buf); response_needed = 0; if (was_running && (status == 'W' || status == 'X')) { was_running = 0; if (status == 'W') fprintf (stderr, "\nChild exited with status %d\n", signal); if (status == 'X') fprintf (stderr, "\nChild terminated with signal = 0x%x (%s)\n", target_signal_to_host (signal), target_signal_to_name (signal)); if (extended_protocol) goto restart; else { fprintf (stderr, "GDBserver exiting\n"); exit (0); } } if (status != 'W' && status != 'X') was_running = 1; } /* If an exit was requested (using the "monitor exit" command), terminate now. The only other way to get here is for getpkt to fail; close the connection and reopen it at the top of the loop. */ if (exit_requested) { remote_close (); if (attached && target_running ()) detach_inferior (); else if (target_running ()) kill_inferior (); exit (0); } else { fprintf (stderr, "Remote side has terminated connection. " "GDBserver will reopen the connection.\n"); remote_close (); } } }
int agent_run_command (int pid, const char *cmd, int len) { int fd; int tid = agent_get_helper_thread_id (); ptid_t ptid = ptid_build (pid, tid, 0); #ifdef GDBSERVER int ret = write_inferior_memory (ipa_sym_addrs.addr_cmd_buf, (const unsigned char *) cmd, len); #else int ret = target_write_memory (ipa_sym_addrs.addr_cmd_buf, cmd, len); #endif if (ret != 0) { warning (_("unable to write")); return -1; } DEBUG_AGENT ("agent: resumed helper thread\n"); /* Resume helper thread. */ #ifdef GDBSERVER { struct thread_resume resume_info; resume_info.thread = ptid; resume_info.kind = resume_continue; resume_info.sig = GDB_SIGNAL_0; (*the_target->resume) (&resume_info, 1); } #else target_resume (ptid, 0, GDB_SIGNAL_0); #endif fd = gdb_connect_sync_socket (pid); if (fd >= 0) { char buf[1] = ""; int ret; DEBUG_AGENT ("agent: signalling helper thread\n"); do { ret = write (fd, buf, 1); } while (ret == -1 && errno == EINTR); DEBUG_AGENT ("agent: waiting for helper thread's response\n"); do { ret = read (fd, buf, 1); } while (ret == -1 && errno == EINTR); close (fd); DEBUG_AGENT ("agent: helper thread's response received\n"); } else return -1; /* Need to read response with the inferior stopped. */ if (!ptid_equal (ptid, null_ptid)) { struct target_waitstatus status; int was_non_stop = non_stop; /* Stop thread PTID. */ DEBUG_AGENT ("agent: stop helper thread\n"); #ifdef GDBSERVER { struct thread_resume resume_info; resume_info.thread = ptid; resume_info.kind = resume_stop; resume_info.sig = GDB_SIGNAL_0; (*the_target->resume) (&resume_info, 1); } non_stop = 1; mywait (ptid, &status, 0, 0); #else non_stop = 1; target_stop (ptid); memset (&status, 0, sizeof (status)); target_wait (ptid, &status, 0); #endif non_stop = was_non_stop; } if (fd >= 0) { #ifdef GDBSERVER if (read_inferior_memory (ipa_sym_addrs.addr_cmd_buf, (unsigned char *) cmd, IPA_CMD_BUF_SIZE)) #else if (target_read_memory (ipa_sym_addrs.addr_cmd_buf, (gdb_byte *) cmd, IPA_CMD_BUF_SIZE)) #endif { warning (_("Error reading command response")); return -1; } } return 0; }