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