| /* Target operations for the remote server for GDB. |
| Copyright (C) 2002, 2004, 2005, 2007, 2008, 2009, 2010, 2011 |
| Free Software Foundation, Inc. |
| |
| Contributed by MontaVista Software. |
| |
| This file is part of GDB. |
| |
| This program is free software; you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation; either version 3 of the License, or |
| (at your option) any later version. |
| |
| This program is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with this program. If not, see <http://www.gnu.org/licenses/>. */ |
| |
| #include "server.h" |
| |
| struct target_ops *the_target; |
| |
| void |
| set_desired_inferior (int use_general) |
| { |
| struct thread_info *found; |
| |
| if (use_general == 1) |
| found = find_thread_ptid (general_thread); |
| 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 ((!ptid_equal (step_thread, null_ptid) |
| && !ptid_equal (step_thread, minus_one_ptid)) |
| && (ptid_equal (cont_thread, null_ptid) |
| || ptid_equal (cont_thread, minus_one_ptid))) |
| found = find_thread_ptid (step_thread); |
| |
| if (found == NULL) |
| found = find_thread_ptid (cont_thread); |
| } |
| |
| if (found == NULL) |
| current_inferior = (struct thread_info *) all_threads.head; |
| else |
| current_inferior = found; |
| } |
| |
| int |
| read_inferior_memory (CORE_ADDR memaddr, unsigned char *myaddr, int len) |
| { |
| int res; |
| res = (*the_target->read_memory) (memaddr, myaddr, len); |
| check_mem_read (memaddr, myaddr, len); |
| return res; |
| } |
| |
| int |
| write_inferior_memory (CORE_ADDR memaddr, const unsigned char *myaddr, |
| int len) |
| { |
| /* Lacking cleanups, there is some potential for a memory leak if the |
| write fails and we go through error(). Make sure that no more than |
| one buffer is ever pending by making BUFFER static. */ |
| static unsigned char *buffer = 0; |
| int res; |
| |
| if (buffer != NULL) |
| free (buffer); |
| |
| buffer = xmalloc (len); |
| memcpy (buffer, myaddr, len); |
| check_mem_write (memaddr, buffer, len); |
| res = (*the_target->write_memory) (memaddr, buffer, len); |
| free (buffer); |
| buffer = NULL; |
| |
| return res; |
| } |
| |
| 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) (ptid, ourstatus, options); |
| |
| 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", |
| target_signal_to_host (ourstatus->value.sig), |
| target_signal_to_name (ourstatus->value.sig)); |
| |
| if (connected_wait) |
| server_waiting = 0; |
| |
| return ret; |
| } |
| |
| 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)); |
| 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_equal (ptid, minus_one_ptid)) |
| xsnprintf (buf, sizeof (buf), "<all threads>"); |
| else if (ptid_equal (ptid, null_ptid)) |
| xsnprintf (buf, sizeof (buf), "<null thread>"); |
| else if (ptid_get_tid (ptid) != 0) |
| xsnprintf (buf, sizeof (buf), "Thread %d.0x%lx", |
| ptid_get_pid (ptid), ptid_get_tid (ptid)); |
| else if (ptid_get_lwp (ptid) != 0) |
| xsnprintf (buf, sizeof (buf), "LWP %d.%ld", |
| ptid_get_pid (ptid), ptid_get_lwp (ptid)); |
| else |
| xsnprintf (buf, sizeof (buf), "Process %d", |
| ptid_get_pid (ptid)); |
| |
| return buf; |
| } |
| |
| /* Return a pretty printed form of target_waitstatus. */ |
| |
| const char * |
| target_waitstatus_to_string (const struct target_waitstatus *ws) |
| { |
| static char buf[200]; |
| const char *kind_str = "status->kind = "; |
| |
| switch (ws->kind) |
| { |
| case TARGET_WAITKIND_EXITED: |
| sprintf (buf, "%sexited, status = %d", |
| kind_str, ws->value.integer); |
| break; |
| case TARGET_WAITKIND_STOPPED: |
| sprintf (buf, "%sstopped, signal = %s", |
| kind_str, target_signal_to_name (ws->value.sig)); |
| break; |
| case TARGET_WAITKIND_SIGNALLED: |
| sprintf (buf, "%ssignalled, signal = %s", |
| kind_str, target_signal_to_name (ws->value.sig)); |
| break; |
| case TARGET_WAITKIND_LOADED: |
| sprintf (buf, "%sloaded", kind_str); |
| break; |
| case TARGET_WAITKIND_EXECD: |
| sprintf (buf, "%sexecd", kind_str); |
| break; |
| case TARGET_WAITKIND_SPURIOUS: |
| sprintf (buf, "%sspurious", kind_str); |
| break; |
| case TARGET_WAITKIND_IGNORE: |
| sprintf (buf, "%signore", kind_str); |
| break; |
| default: |
| sprintf (buf, "%sunknown???", kind_str); |
| break; |
| } |
| |
| return buf; |
| } |