* utils.c (xmalloc,xcalloc,xstrdup): New fns.
[deliverable/binutils-gdb.git] / gdb / gdbserver / inferiors.c
1 /* Inferior process information for the remote server for GDB.
2 Copyright (C) 2002, 2005, 2007, 2008 Free Software Foundation, Inc.
3
4 Contributed by MontaVista Software.
5
6 This file is part of GDB.
7
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>. */
20
21 #include <stdlib.h>
22
23 #include "server.h"
24
25 struct thread_info
26 {
27 struct inferior_list_entry entry;
28 void *target_data;
29 void *regcache_data;
30 unsigned int gdb_id;
31 };
32
33 struct inferior_list all_threads;
34 struct inferior_list all_dlls;
35 int dlls_changed;
36
37 struct thread_info *current_inferior;
38
39 #define get_thread(inf) ((struct thread_info *)(inf))
40 #define get_dll(inf) ((struct dll_info *)(inf))
41
42 void
43 add_inferior_to_list (struct inferior_list *list,
44 struct inferior_list_entry *new_inferior)
45 {
46 new_inferior->next = NULL;
47 if (list->tail != NULL)
48 list->tail->next = new_inferior;
49 else
50 list->head = new_inferior;
51 list->tail = new_inferior;
52 }
53
54 void
55 for_each_inferior (struct inferior_list *list,
56 void (*action) (struct inferior_list_entry *))
57 {
58 struct inferior_list_entry *cur = list->head, *next;
59
60 while (cur != NULL)
61 {
62 next = cur->next;
63 (*action) (cur);
64 cur = next;
65 }
66 }
67
68 void
69 remove_inferior (struct inferior_list *list,
70 struct inferior_list_entry *entry)
71 {
72 struct inferior_list_entry **cur;
73
74 if (list->head == entry)
75 {
76 list->head = entry->next;
77 if (list->tail == entry)
78 list->tail = list->head;
79 return;
80 }
81
82 cur = &list->head;
83 while (*cur && (*cur)->next != entry)
84 cur = &(*cur)->next;
85
86 if (*cur == NULL)
87 return;
88
89 (*cur)->next = entry->next;
90
91 if (list->tail == entry)
92 list->tail = *cur;
93 }
94
95 void
96 add_thread (unsigned long thread_id, void *target_data, unsigned int gdb_id)
97 {
98 struct thread_info *new_thread = xmalloc (sizeof (*new_thread));
99
100 memset (new_thread, 0, sizeof (*new_thread));
101
102 new_thread->entry.id = thread_id;
103
104 add_inferior_to_list (&all_threads, & new_thread->entry);
105
106 if (current_inferior == NULL)
107 current_inferior = new_thread;
108
109 new_thread->target_data = target_data;
110 set_inferior_regcache_data (new_thread, new_register_cache ());
111 new_thread->gdb_id = gdb_id;
112 }
113
114 unsigned int
115 thread_id_to_gdb_id (unsigned long thread_id)
116 {
117 struct inferior_list_entry *inf = all_threads.head;
118
119 while (inf != NULL)
120 {
121 struct thread_info *thread = get_thread (inf);
122 if (inf->id == thread_id)
123 return thread->gdb_id;
124 inf = inf->next;
125 }
126
127 return 0;
128 }
129
130 unsigned int
131 thread_to_gdb_id (struct thread_info *thread)
132 {
133 return thread->gdb_id;
134 }
135
136 struct thread_info *
137 gdb_id_to_thread (unsigned int gdb_id)
138 {
139 struct inferior_list_entry *inf = all_threads.head;
140
141 while (inf != NULL)
142 {
143 struct thread_info *thread = get_thread (inf);
144 if (thread->gdb_id == gdb_id)
145 return thread;
146 inf = inf->next;
147 }
148
149 return NULL;
150 }
151
152 unsigned long
153 gdb_id_to_thread_id (unsigned int gdb_id)
154 {
155 struct thread_info *thread = gdb_id_to_thread (gdb_id);
156
157 return thread ? thread->entry.id : 0;
158 }
159
160 static void
161 free_one_thread (struct inferior_list_entry *inf)
162 {
163 struct thread_info *thread = get_thread (inf);
164 free_register_cache (inferior_regcache_data (thread));
165 free (thread);
166 }
167
168 void
169 remove_thread (struct thread_info *thread)
170 {
171 remove_inferior (&all_threads, (struct inferior_list_entry *) thread);
172 free_one_thread (&thread->entry);
173 }
174
175 struct inferior_list_entry *
176 find_inferior (struct inferior_list *list,
177 int (*func) (struct inferior_list_entry *, void *), void *arg)
178 {
179 struct inferior_list_entry *inf = list->head;
180
181 while (inf != NULL)
182 {
183 if ((*func) (inf, arg))
184 return inf;
185 inf = inf->next;
186 }
187
188 return NULL;
189 }
190
191 struct inferior_list_entry *
192 find_inferior_id (struct inferior_list *list, unsigned long id)
193 {
194 struct inferior_list_entry *inf = list->head;
195
196 while (inf != NULL)
197 {
198 if (inf->id == id)
199 return inf;
200 inf = inf->next;
201 }
202
203 return NULL;
204 }
205
206 void *
207 inferior_target_data (struct thread_info *inferior)
208 {
209 return inferior->target_data;
210 }
211
212 void
213 set_inferior_target_data (struct thread_info *inferior, void *data)
214 {
215 inferior->target_data = data;
216 }
217
218 void *
219 inferior_regcache_data (struct thread_info *inferior)
220 {
221 return inferior->regcache_data;
222 }
223
224 void
225 set_inferior_regcache_data (struct thread_info *inferior, void *data)
226 {
227 inferior->regcache_data = data;
228 }
229
230 static void
231 free_one_dll (struct inferior_list_entry *inf)
232 {
233 struct dll_info *dll = get_dll (inf);
234 if (dll->name != NULL)
235 free (dll->name);
236 free (dll);
237 }
238
239 /* Find a DLL with the same name and/or base address. A NULL name in
240 the key is ignored; so is an all-ones base address. */
241
242 static int
243 match_dll (struct inferior_list_entry *inf, void *arg)
244 {
245 struct dll_info *iter = (void *) inf;
246 struct dll_info *key = arg;
247
248 if (key->base_addr != ~(CORE_ADDR) 0
249 && iter->base_addr == key->base_addr)
250 return 1;
251 else if (key->name != NULL
252 && iter->name != NULL
253 && strcmp (key->name, iter->name) == 0)
254 return 1;
255
256 return 0;
257 }
258
259 /* Record a newly loaded DLL at BASE_ADDR. */
260
261 void
262 loaded_dll (const char *name, CORE_ADDR base_addr)
263 {
264 struct dll_info *new_dll = xmalloc (sizeof (*new_dll));
265 memset (new_dll, 0, sizeof (*new_dll));
266
267 new_dll->entry.id = -1;
268
269 new_dll->name = xstrdup (name);
270 new_dll->base_addr = base_addr;
271
272 add_inferior_to_list (&all_dlls, &new_dll->entry);
273 dlls_changed = 1;
274 }
275
276 /* Record that the DLL with NAME and BASE_ADDR has been unloaded. */
277
278 void
279 unloaded_dll (const char *name, CORE_ADDR base_addr)
280 {
281 struct dll_info *dll;
282 struct dll_info key_dll;
283
284 /* Be careful not to put the key DLL in any list. */
285 key_dll.name = (char *) name;
286 key_dll.base_addr = base_addr;
287
288 dll = (void *) find_inferior (&all_dlls, match_dll, &key_dll);
289 remove_inferior (&all_dlls, &dll->entry);
290 free_one_dll (&dll->entry);
291 dlls_changed = 1;
292 }
293
294 #define clear_list(LIST) \
295 do { (LIST)->head = (LIST)->tail = NULL; } while (0)
296
297 void
298 clear_inferiors (void)
299 {
300 for_each_inferior (&all_threads, free_one_thread);
301 for_each_inferior (&all_dlls, free_one_dll);
302
303 clear_list (&all_threads);
304 clear_list (&all_dlls);
305
306 current_inferior = NULL;
307 }
308
309 /* Two utility functions for a truly degenerate inferior_list: a simple
310 PID listing. */
311
312 void
313 add_pid_to_list (struct inferior_list *list, unsigned long pid)
314 {
315 struct inferior_list_entry *new_entry;
316
317 new_entry = xmalloc (sizeof (struct inferior_list_entry));
318 new_entry->id = pid;
319 add_inferior_to_list (list, new_entry);
320 }
321
322 int
323 pull_pid_from_list (struct inferior_list *list, unsigned long pid)
324 {
325 struct inferior_list_entry *new_entry;
326
327 new_entry = find_inferior_id (list, pid);
328 if (new_entry == NULL)
329 return 0;
330 else
331 {
332 remove_inferior (list, new_entry);
333 free (new_entry);
334 return 1;
335 }
336 }
This page took 0.037114 seconds and 5 git commands to generate.