diff options
Diffstat (limited to 'gdb/gdbserver/target.c')
-rw-r--r-- | gdb/gdbserver/target.c | 107 |
1 files changed, 107 insertions, 0 deletions
diff --git a/gdb/gdbserver/target.c b/gdb/gdbserver/target.c index 80512d86..b376ce8 100644 --- a/gdb/gdbserver/target.c +++ b/gdb/gdbserver/target.c @@ -37,6 +37,113 @@ set_desired_thread (int use_general) return (current_thread != NULL); } +/* Structure used to look up a thread to use as current when accessing + memory. */ + +struct thread_search +{ + /* The PTID of the current general thread. This is an input + parameter. */ + ptid_t current_gen_ptid; + + /* The first thread found. */ + struct thread_info *first; + + /* The first stopped thread found. */ + struct thread_info *stopped; + + /* The current general thread, if found. */ + struct thread_info *current; +}; + +/* Callback for find_inferior. Search for a thread to use as current + when accessing memory. */ + +static int +thread_search_callback (struct inferior_list_entry *entry, void *args) +{ + struct thread_info *thread = (struct thread_info *) entry; + struct thread_search *s = (struct thread_search *) args; + + if (ptid_get_pid (entry->id) == ptid_get_pid (s->current_gen_ptid) + && mythread_alive (ptid_of (thread))) + { + if (s->stopped == NULL && thread_stopped (thread)) + s->stopped = thread; + + if (s->first == NULL) + s->first = thread; + + if (s->current == NULL && ptid_equal (s->current_gen_ptid, entry->id)) + s->current = thread; + } + + return 0; +} + +/* 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_search search; + struct thread_info *thread; + + memset (&search, 0, sizeof (search)); + search.current_gen_ptid = general_thread; + prev_general_thread = general_thread; + + if (the_target->prepare_to_access_memory != NULL) + { + int res; + + res = the_target->prepare_to_access_memory (); + if (res != 0) + return res; + } + + find_inferior (&all_threads, thread_search_callback, &search); + + /* 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 (search.stopped != NULL) + thread = search.stopped; + else if (search.current != NULL) + thread = search.current; + else if (search.first != NULL) + thread = search.first; + else + { + done_accessing_memory (); + return 1; + } + + current_thread = thread; + general_thread = ptid_of (thread); + + return 0; +} + +/* See target.h. */ + +void +done_accessing_memory (void) +{ + if (the_target->done_accessing_memory != NULL) + the_target->done_accessing_memory (); + + /* Restore the previous selected thread. */ + general_thread = prev_general_thread; + current_thread = find_thread_ptid (general_thread); +} + int read_inferior_memory (CORE_ADDR memaddr, unsigned char *myaddr, int len) { |