1 /* Inferior process information for the remote server for GDB.
2    Copyright (C) 2002, 2005, 2011
3    Free Software Foundation, Inc.
4 
5    Contributed by MontaVista Software.
6 
7    This file is part of GDB.
8    It has been modified to integrate it in valgrind
9 
10    This program is free software; you can redistribute it and/or modify
11    it under the terms of the GNU General Public License as published by
12    the Free Software Foundation; either version 2 of the License, or
13    (at your option) any later version.
14 
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License for more details.
19 
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 51 Franklin Street, Fifth Floor,
23    Boston, MA 02110-1301, USA.  */
24 
25 #include "server.h"
26 
27 struct thread_info
28 {
29    struct inferior_list_entry entry;
30    void *target_data;
31    void *regcache_data;
32    unsigned int gdb_id;
33 };
34 
35 struct inferior_list all_threads;
36 
37 struct thread_info *current_inferior;
38 
39 #define get_thread(inf) ((struct thread_info *)(inf))
40 
add_inferior_to_list(struct inferior_list * list,struct inferior_list_entry * new_inferior)41 void add_inferior_to_list (struct inferior_list *list,
42 		      struct inferior_list_entry *new_inferior)
43 {
44    new_inferior->next = NULL;
45    if (list->tail != NULL)
46       list->tail->next = new_inferior;
47    else
48       list->head = new_inferior;
49    list->tail = new_inferior;
50 }
51 
for_each_inferior(struct inferior_list * list,void (* action)(struct inferior_list_entry *))52 void for_each_inferior (struct inferior_list *list,
53 		   void (*action) (struct inferior_list_entry *))
54 {
55    struct inferior_list_entry *cur = list->head, *next;
56 
57    while (cur != NULL) {
58       next = cur->next;
59       (*action) (cur);
60       cur = next;
61    }
62 }
63 
change_inferior_id(struct inferior_list * list,unsigned long new_id)64 void change_inferior_id (struct inferior_list *list,
65 		    unsigned long new_id)
66 {
67    if (list->head != list->tail)
68       error ("tried to change thread ID after multiple threads are created\n");
69 
70    list->head->id = new_id;
71 }
72 
remove_inferior(struct inferior_list * list,struct inferior_list_entry * entry)73 void remove_inferior (struct inferior_list *list,
74 		 struct inferior_list_entry *entry)
75 {
76    struct inferior_list_entry **cur;
77 
78    if (list->head == entry) {
79       list->head = entry->next;
80       if (list->tail == entry)
81          list->tail = list->head;
82       return;
83    }
84 
85    cur = &list->head;
86    while (*cur && (*cur)->next != entry)
87       cur = &(*cur)->next;
88 
89    if (*cur == NULL)
90       return;
91 
92    (*cur)->next = entry->next;
93 
94    if (list->tail == entry)
95       list->tail = *cur;
96 }
97 
add_thread(unsigned long thread_id,void * target_data,unsigned int gdb_id)98 void add_thread (unsigned long thread_id, void *target_data, unsigned int gdb_id)
99 {
100    struct thread_info *new_thread
101       = (struct thread_info *) malloc (sizeof (*new_thread));
102 
103    VG_(memset) (new_thread, 0, sizeof (*new_thread));
104 
105    new_thread->entry.id = thread_id;
106 
107    add_inferior_to_list (&all_threads, & new_thread->entry);
108 
109    if (current_inferior == NULL)
110       current_inferior = new_thread;
111 
112    new_thread->target_data = target_data;
113    set_inferior_regcache_data (new_thread, new_register_cache ());
114    new_thread->gdb_id = gdb_id;
115 }
116 
thread_id_to_gdb_id(unsigned long thread_id)117 unsigned int thread_id_to_gdb_id (unsigned long thread_id)
118 {
119    struct inferior_list_entry *inf = all_threads.head;
120 
121    while (inf != NULL) {
122       struct thread_info *thread = get_thread (inf);
123       if (inf->id == thread_id)
124          return thread->gdb_id;
125       inf = inf->next;
126    }
127 
128    return 0;
129 }
130 
thread_to_gdb_id(struct thread_info * thread)131 unsigned int thread_to_gdb_id (struct thread_info *thread)
132 {
133    return thread->gdb_id;
134 }
135 
gdb_id_to_thread(unsigned int gdb_id)136 struct thread_info * gdb_id_to_thread (unsigned int gdb_id)
137 {
138    struct inferior_list_entry *inf = all_threads.head;
139 
140    while (inf != NULL) {
141       struct thread_info *thread = get_thread (inf);
142       if (thread->gdb_id == gdb_id)
143          return thread;
144       inf = inf->next;
145    }
146 
147    return NULL;
148 }
149 
gdb_id_to_thread_id(unsigned int gdb_id)150 unsigned long gdb_id_to_thread_id (unsigned int gdb_id)
151 {
152    struct thread_info *thread = gdb_id_to_thread (gdb_id);
153 
154    return thread ? thread->entry.id : 0;
155 }
156 
157 static
free_one_thread(struct inferior_list_entry * inf)158 void free_one_thread (struct inferior_list_entry *inf)
159 {
160    struct thread_info *thread = get_thread (inf);
161    free_register_cache (inferior_regcache_data (thread));
162    free (thread);
163 }
164 
remove_thread(struct thread_info * thread)165 void remove_thread (struct thread_info *thread)
166 {
167    remove_inferior (&all_threads, (struct inferior_list_entry *) thread);
168    free_one_thread (&thread->entry);
169 }
170 
clear_inferiors(void)171 void clear_inferiors (void)
172 {
173    for_each_inferior (&all_threads, free_one_thread);
174 
175    all_threads.head = all_threads.tail = NULL;
176 }
177 
find_inferior(struct inferior_list * list,int (* func)(struct inferior_list_entry *,void *),void * arg)178 struct inferior_list_entry * find_inferior (struct inferior_list *list,
179                                             int (*func)
180                                               (struct inferior_list_entry *,
181                                                void *),
182                                             void *arg)
183 {
184    struct inferior_list_entry *inf = list->head;
185 
186    while (inf != NULL) {
187       if ((*func) (inf, arg))
188          return inf;
189       inf = inf->next;
190    }
191 
192    return NULL;
193 }
194 
find_inferior_id(struct inferior_list * list,unsigned long id)195 struct inferior_list_entry * find_inferior_id (struct inferior_list *list,
196                                                unsigned long id)
197 {
198    struct inferior_list_entry *inf = list->head;
199 
200    while (inf != NULL) {
201       if (inf->id == id)
202          return inf;
203       inf = inf->next;
204    }
205 
206    return NULL;
207 }
208 
inferior_target_data(struct thread_info * inferior)209 void * inferior_target_data (struct thread_info *inferior)
210 {
211    return inferior->target_data;
212 }
213 
set_inferior_target_data(struct thread_info * inferior,void * data)214 void set_inferior_target_data (struct thread_info *inferior, void *data)
215 {
216    inferior->target_data = data;
217 }
218 
inferior_regcache_data(struct thread_info * inferior)219 void * inferior_regcache_data (struct thread_info *inferior)
220 {
221    return inferior->regcache_data;
222 }
223 
set_inferior_regcache_data(struct thread_info * inferior,void * data)224 void set_inferior_regcache_data (struct thread_info *inferior, void *data)
225 {
226    inferior->regcache_data = data;
227 }
228