X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gdb%2Fgdbserver%2Ftarget.c;h=25f91eeba739ce0a4cce3bd8300e4fba97811b87;hb=353ea2d106a51cfd1680f7d351f35eb8f69c9248;hp=3bdc469e7895dbc5c7f2d2012f0ec7b4f950eea9;hpb=5b1c542ea1c4ff247db390bd24a9e0665d0c2e48;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/gdbserver/target.c b/gdb/gdbserver/target.c index 3bdc469e78..25f91eeba7 100644 --- a/gdb/gdbserver/target.c +++ b/gdb/gdbserver/target.c @@ -1,6 +1,5 @@ /* Target operations for the remote server for GDB. - Copyright (C) 2002, 2004, 2005, 2007, 2008, 2009 - Free Software Foundation, Inc. + Copyright (C) 2002-2019 Free Software Foundation, Inc. Contributed by MontaVista Software. @@ -20,40 +19,106 @@ along with this program. If not, see . */ #include "server.h" +#include "tracepoint.h" struct target_ops *the_target; -void -set_desired_inferior (int use_general) +int +set_desired_thread () +{ + client_state &cs = get_client_state (); + thread_info *found = find_thread_ptid (cs.general_thread); + + current_thread = found; + return (current_thread != NULL); +} + +/* The thread that was current before prepare_to_access_memory was + called. done_accessing_memory uses this to restore the previous + selected thread. */ +static ptid_t prev_general_thread; + +/* See target.h. */ + +int +prepare_to_access_memory (void) { - struct thread_info *found; + client_state &cs = get_client_state (); - if (use_general == 1) + /* The first thread found. */ + struct thread_info *first = NULL; + /* The first stopped thread found. */ + struct thread_info *stopped = NULL; + /* The current general thread, if found. */ + struct thread_info *current = NULL; + + /* Save the general thread value, since prepare_to_access_memory could change + it. */ + prev_general_thread = cs.general_thread; + + if (the_target->prepare_to_access_memory != NULL) { - found = (struct thread_info *) find_inferior_id (&all_threads, - general_thread); + int res; + + res = the_target->prepare_to_access_memory (); + if (res != 0) + return res; } + + for_each_thread (prev_general_thread.pid (), [&] (thread_info *thread) + { + if (mythread_alive (thread->id)) + { + if (stopped == NULL && the_target->thread_stopped != NULL + && thread_stopped (thread)) + stopped = thread; + + if (first == NULL) + first = thread; + + if (current == NULL && prev_general_thread == thread->id) + current = thread; + } + }); + + /* The thread we end up choosing. */ + struct thread_info *thread; + + /* Prefer a stopped thread. If none is found, try the current + thread. Otherwise, take the first thread in the process. If + none is found, undo the effects of + target->prepare_to_access_memory() and return error. */ + if (stopped != NULL) + thread = stopped; + else if (current != NULL) + thread = current; + else if (first != NULL) + thread = first; else { - found = NULL; - - /* If we are continuing any (all) thread(s), use step_thread - to decide which thread to step and/or send the specified - signal to. */ - if ((step_thread != 0 && step_thread != -1) - && (cont_thread == 0 || cont_thread == -1)) - found = (struct thread_info *) find_inferior_id (&all_threads, - step_thread); - - if (found == NULL) - found = (struct thread_info *) find_inferior_id (&all_threads, - cont_thread); + done_accessing_memory (); + return 1; } - if (found == NULL) - current_inferior = (struct thread_info *) all_threads.head; - else - current_inferior = found; + current_thread = thread; + cs.general_thread = ptid_of (thread); + + return 0; +} + +/* See target.h. */ + +void +done_accessing_memory (void) +{ + client_state &cs = get_client_state (); + + if (the_target->done_accessing_memory != NULL) + the_target->done_accessing_memory (); + + /* Restore the previous selected thread. */ + cs.general_thread = prev_general_thread; + switch_to_thread (cs.general_thread); } int @@ -65,6 +130,22 @@ read_inferior_memory (CORE_ADDR memaddr, unsigned char *myaddr, int len) return res; } +/* See target/target.h. */ + +int +target_read_memory (CORE_ADDR memaddr, gdb_byte *myaddr, ssize_t len) +{ + return read_inferior_memory (memaddr, myaddr, len); +} + +/* See target/target.h. */ + +int +target_read_uint32 (CORE_ADDR memaddr, uint32_t *result) +{ + return read_inferior_memory (memaddr, (gdb_byte *) result, sizeof (*result)); +} + int write_inferior_memory (CORE_ADDR memaddr, const unsigned char *myaddr, int len) @@ -78,9 +159,9 @@ write_inferior_memory (CORE_ADDR memaddr, const unsigned char *myaddr, if (buffer != NULL) free (buffer); - buffer = xmalloc (len); + buffer = (unsigned char *) xmalloc (len); memcpy (buffer, myaddr, len); - check_mem_write (memaddr, buffer, len); + check_mem_write (memaddr, buffer, myaddr, len); res = (*the_target->write_memory) (memaddr, buffer, len); free (buffer); buffer = NULL; @@ -88,15 +169,46 @@ write_inferior_memory (CORE_ADDR memaddr, const unsigned char *myaddr, return res; } -unsigned long -mywait (struct target_waitstatus *ourstatus, int connected_wait) +/* See target/target.h. */ + +int +target_write_memory (CORE_ADDR memaddr, const gdb_byte *myaddr, ssize_t len) { - unsigned long ret; + return write_inferior_memory (memaddr, myaddr, len); +} + +ptid_t +mywait (ptid_t ptid, struct target_waitstatus *ourstatus, int options, + int connected_wait) +{ + ptid_t ret; if (connected_wait) server_waiting = 1; - ret = (*the_target->wait) (ourstatus); + ret = target_wait (ptid, ourstatus, options); + + /* We don't expose _LOADED events to gdbserver core. See the + `dlls_changed' global. */ + if (ourstatus->kind == TARGET_WAITKIND_LOADED) + ourstatus->kind = TARGET_WAITKIND_STOPPED; + + /* If GDB is connected through TCP/serial, then GDBserver will most + probably be running on its own terminal/console, so it's nice to + print there why is GDBserver exiting. If however, GDB is + connected through stdio, then there's no need to spam the GDB + console with this -- the user will already see the exit through + regular GDB output, in that same terminal. */ + if (!remote_connection_is_stdio ()) + { + if (ourstatus->kind == TARGET_WAITKIND_EXITED) + fprintf (stderr, + "\nChild exited with status %d\n", ourstatus->value.integer); + else if (ourstatus->kind == TARGET_WAITKIND_SIGNALLED) + fprintf (stderr, "\nChild terminated with signal = 0x%x (%s)\n", + gdb_signal_to_host (ourstatus->value.sig), + gdb_signal_to_name (ourstatus->value.sig)); + } if (connected_wait) server_waiting = 0; @@ -104,9 +216,197 @@ mywait (struct target_waitstatus *ourstatus, int connected_wait) return ret; } +/* See target/target.h. */ + +void +target_stop_and_wait (ptid_t ptid) +{ + struct target_waitstatus status; + int was_non_stop = non_stop; + 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); + non_stop = was_non_stop; +} + +/* See target/target.h. */ + +ptid_t +target_wait (ptid_t ptid, struct target_waitstatus *status, int options) +{ + return (*the_target->wait) (ptid, status, options); +} + +/* See target/target.h. */ + +void +target_mourn_inferior (ptid_t ptid) +{ + (*the_target->mourn) (find_process_pid (ptid.pid ())); +} + +/* See target/target.h. */ + +void +target_continue_no_signal (ptid_t ptid) +{ + 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); +} + +/* See target/target.h. */ + +void +target_continue (ptid_t ptid, enum gdb_signal signal) +{ + struct thread_resume resume_info; + + resume_info.thread = ptid; + resume_info.kind = resume_continue; + resume_info.sig = gdb_signal_to_host (signal); + (*the_target->resume) (&resume_info, 1); +} + +/* See target/target.h. */ + +int +target_supports_multi_process (void) +{ + return (the_target->supports_multi_process != NULL ? + (*the_target->supports_multi_process) () : 0); +} + +int +start_non_stop (int nonstop) +{ + if (the_target->start_non_stop == NULL) + { + if (nonstop) + return -1; + else + return 0; + } + + return (*the_target->start_non_stop) (nonstop); +} + void set_target_ops (struct target_ops *target) { - the_target = (struct target_ops *) xmalloc (sizeof (*the_target)); + the_target = XNEW (struct target_ops); memcpy (the_target, target, sizeof (*the_target)); } + +/* Convert pid to printable format. */ + +const char * +target_pid_to_str (ptid_t ptid) +{ + static char buf[80]; + + if (ptid == minus_one_ptid) + xsnprintf (buf, sizeof (buf), ""); + else if (ptid == null_ptid) + xsnprintf (buf, sizeof (buf), ""); + else if (ptid.tid () != 0) + xsnprintf (buf, sizeof (buf), "Thread %d.0x%lx", + ptid.pid (), ptid.tid ()); + else if (ptid.lwp () != 0) + xsnprintf (buf, sizeof (buf), "LWP %d.%ld", + ptid.pid (), ptid.lwp ()); + else + xsnprintf (buf, sizeof (buf), "Process %d", + ptid.pid ()); + + return buf; +} + +int +kill_inferior (process_info *proc) +{ + gdb_agent_about_to_close (proc->pid); + + return (*the_target->kill) (proc); +} + +/* Target can do hardware single step. */ + +int +target_can_do_hardware_single_step (void) +{ + return 1; +} + +/* Default implementation for breakpoint_kind_for_pc. + + The default behavior for targets that don't implement breakpoint_kind_for_pc + is to use the size of a breakpoint as the kind. */ + +int +default_breakpoint_kind_from_pc (CORE_ADDR *pcptr) +{ + int size = 0; + + gdb_assert (the_target->sw_breakpoint_from_kind != NULL); + + (*the_target->sw_breakpoint_from_kind) (0, &size); + return size; +} + +/* Define it. */ + +target_terminal_state target_terminal::m_terminal_state + = target_terminal_state::is_ours; + +/* See target/target.h. */ + +void +target_terminal::init () +{ + /* Placeholder needed because of fork_inferior. Not necessary on + GDBserver. */ +} + +/* See target/target.h. */ + +void +target_terminal::inferior () +{ + /* Placeholder needed because of fork_inferior. Not necessary on + GDBserver. */ +} + +/* See target/target.h. */ + +void +target_terminal::ours () +{ + /* Placeholder needed because of fork_inferior. Not necessary on + GDBserver. */ +} + +/* See target/target.h. */ + +void +target_terminal::ours_for_output (void) +{ + /* Placeholder. */ +} + +/* See target/target.h. */ + +void +target_terminal::info (const char *arg, int from_tty) +{ + /* Placeholder. */ +}