Commit | Line | Data |
---|---|---|
5d5658a1 PA |
1 | /* TID parsing for GDB, the GNU debugger. |
2 | ||
3 | Copyright (C) 2015-2016 Free Software Foundation, Inc. | |
4 | ||
5 | This file is part of GDB. | |
6 | ||
7 | This program is free software; you can redistribute it and/or modify | |
8 | it under the terms of the GNU General Public License as published by | |
9 | the Free Software Foundation; either version 3 of the License, or | |
10 | (at your option) any later version. | |
11 | ||
12 | This program is distributed in the hope that it will be useful, | |
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | GNU General Public License for more details. | |
16 | ||
17 | You should have received a copy of the GNU General Public License | |
18 | along with this program. If not, see <http://www.gnu.org/licenses/>. */ | |
19 | ||
20 | #include "defs.h" | |
21 | #include "tid-parse.h" | |
22 | #include "inferior.h" | |
23 | #include "gdbthread.h" | |
24 | #include <ctype.h> | |
25 | ||
26 | /* See tid-parse.h. */ | |
27 | ||
28 | void ATTRIBUTE_NORETURN | |
29 | invalid_thread_id_error (const char *string) | |
30 | { | |
31 | error (_("Invalid thread ID: %s"), string); | |
32 | } | |
33 | ||
34 | /* See tid-parse.h. */ | |
35 | ||
36 | struct thread_info * | |
37 | parse_thread_id (const char *tidstr, const char **end) | |
38 | { | |
39 | const char *number = tidstr; | |
40 | const char *dot, *p1; | |
41 | struct thread_info *tp; | |
42 | struct inferior *inf; | |
43 | int thr_num; | |
44 | int explicit_inf_id = 0; | |
45 | ||
46 | dot = strchr (number, '.'); | |
47 | ||
48 | if (dot != NULL) | |
49 | { | |
50 | /* Parse number to the left of the dot. */ | |
51 | int inf_num; | |
52 | ||
53 | p1 = number; | |
54 | inf_num = get_number_trailer (&p1, '.'); | |
55 | if (inf_num == 0) | |
56 | invalid_thread_id_error (number); | |
57 | ||
58 | inf = find_inferior_id (inf_num); | |
59 | if (inf == NULL) | |
60 | error (_("No inferior number '%d'"), inf_num); | |
61 | ||
62 | explicit_inf_id = 1; | |
63 | p1 = dot + 1; | |
64 | } | |
65 | else | |
66 | { | |
67 | inf = current_inferior (); | |
68 | ||
69 | p1 = number; | |
70 | } | |
71 | ||
72 | thr_num = get_number_const (&p1); | |
73 | if (thr_num == 0) | |
74 | invalid_thread_id_error (number); | |
75 | ||
76 | ALL_THREADS (tp) | |
77 | { | |
78 | if (ptid_get_pid (tp->ptid) == inf->pid | |
79 | && tp->per_inf_num == thr_num) | |
80 | break; | |
81 | } | |
82 | ||
83 | if (tp == NULL) | |
84 | { | |
85 | if (show_inferior_qualified_tids () || explicit_inf_id) | |
86 | error (_("Unknown thread %d.%d."), inf->num, thr_num); | |
87 | else | |
88 | error (_("Unknown thread %d."), thr_num); | |
89 | } | |
90 | ||
91 | if (end != NULL) | |
92 | *end = p1; | |
93 | ||
94 | return tp; | |
95 | } | |
96 | ||
97 | /* See tid-parse.h. */ | |
98 | ||
99 | void | |
100 | tid_range_parser_init (struct tid_range_parser *parser, const char *tidlist, | |
101 | int default_inferior) | |
102 | { | |
103 | parser->state = TID_RANGE_STATE_INFERIOR; | |
104 | parser->string = tidlist; | |
105 | parser->inf_num = 0; | |
106 | parser->qualified = 0; | |
107 | parser->default_inferior = default_inferior; | |
108 | } | |
109 | ||
110 | /* See tid-parse.h. */ | |
111 | ||
112 | int | |
113 | tid_range_parser_finished (struct tid_range_parser *parser) | |
114 | { | |
115 | switch (parser->state) | |
116 | { | |
117 | case TID_RANGE_STATE_INFERIOR: | |
118 | return *parser->string == '\0'; | |
119 | case TID_RANGE_STATE_THREAD_RANGE: | |
120 | return parser->range_parser.finished; | |
121 | } | |
122 | ||
123 | gdb_assert_not_reached (_("unhandled state")); | |
124 | } | |
125 | ||
126 | /* See tid-parse.h. */ | |
127 | ||
128 | const char * | |
129 | tid_range_parser_string (struct tid_range_parser *parser) | |
130 | { | |
131 | switch (parser->state) | |
132 | { | |
133 | case TID_RANGE_STATE_INFERIOR: | |
134 | return parser->string; | |
135 | case TID_RANGE_STATE_THREAD_RANGE: | |
136 | return parser->range_parser.string; | |
137 | } | |
138 | ||
139 | gdb_assert_not_reached (_("unhandled state")); | |
140 | } | |
141 | ||
142 | /* See tid-parse.h. */ | |
143 | ||
144 | void | |
145 | tid_range_parser_skip (struct tid_range_parser *parser) | |
146 | { | |
147 | gdb_assert ((parser->state == TID_RANGE_STATE_THREAD_RANGE) | |
148 | && parser->range_parser.in_range); | |
149 | ||
150 | tid_range_parser_init (parser, parser->range_parser.end_ptr, | |
151 | parser->default_inferior); | |
152 | } | |
153 | ||
154 | /* See tid-parse.h. */ | |
155 | ||
156 | int | |
157 | tid_range_parser_qualified (struct tid_range_parser *parser) | |
158 | { | |
159 | return parser->qualified; | |
160 | } | |
161 | ||
162 | /* Helper for tid_range_parser_get_tid and | |
163 | tid_range_parser_get_tid_range. Return the next range if THR_END | |
164 | is non-NULL, return a single thread ID otherwise. */ | |
165 | ||
166 | static int | |
167 | get_tid_or_range (struct tid_range_parser *parser, int *inf_num, | |
168 | int *thr_start, int *thr_end) | |
169 | { | |
170 | if (parser->state == TID_RANGE_STATE_INFERIOR) | |
171 | { | |
172 | const char *p; | |
173 | const char *space; | |
174 | ||
175 | space = skip_to_space (parser->string); | |
176 | ||
177 | p = parser->string; | |
178 | while (p < space && *p != '.') | |
179 | p++; | |
180 | if (p < space) | |
181 | { | |
182 | const char *dot = p; | |
183 | ||
184 | /* Parse number to the left of the dot. */ | |
185 | p = parser->string; | |
186 | parser->inf_num = get_number_trailer (&p, '.'); | |
187 | if (parser->inf_num == 0) | |
188 | invalid_thread_id_error (parser->string); | |
189 | ||
190 | parser->qualified = 1; | |
191 | p = dot + 1; | |
192 | ||
193 | if (isspace (*p)) | |
194 | invalid_thread_id_error (parser->string); | |
195 | } | |
196 | else | |
197 | { | |
198 | parser->inf_num = parser->default_inferior; | |
199 | parser->qualified = 0; | |
200 | p = parser->string; | |
201 | } | |
202 | ||
203 | init_number_or_range (&parser->range_parser, p); | |
204 | parser->state = TID_RANGE_STATE_THREAD_RANGE; | |
205 | } | |
206 | ||
207 | *inf_num = parser->inf_num; | |
208 | *thr_start = get_number_or_range (&parser->range_parser); | |
209 | if (*thr_start == 0) | |
210 | invalid_thread_id_error (parser->string); | |
211 | ||
212 | /* If we successfully parsed a thread number or finished parsing a | |
213 | thread range, switch back to assuming the next TID is | |
214 | inferior-qualified. */ | |
215 | if (parser->range_parser.end_ptr == NULL | |
216 | || parser->range_parser.string == parser->range_parser.end_ptr) | |
217 | { | |
218 | parser->state = TID_RANGE_STATE_INFERIOR; | |
219 | parser->string = parser->range_parser.string; | |
220 | ||
221 | if (thr_end != NULL) | |
222 | *thr_end = *thr_start; | |
223 | } | |
224 | ||
225 | /* If we're midway through a range, and the caller wants the end | |
226 | value, return it and skip to the end of the range. */ | |
227 | if (thr_end != NULL && parser->state == TID_RANGE_STATE_THREAD_RANGE) | |
228 | { | |
229 | *thr_end = parser->range_parser.end_value; | |
230 | tid_range_parser_skip (parser); | |
231 | } | |
232 | ||
233 | return (*inf_num != 0 && *thr_start != 0); | |
234 | } | |
235 | ||
236 | /* See tid-parse.h. */ | |
237 | ||
238 | int | |
239 | tid_range_parser_get_tid_range (struct tid_range_parser *parser, int *inf_num, | |
240 | int *thr_start, int *thr_end) | |
241 | { | |
242 | gdb_assert (inf_num != NULL && thr_start != NULL && thr_end != NULL); | |
243 | ||
244 | return get_tid_or_range (parser, inf_num, thr_start, thr_end); | |
245 | } | |
246 | ||
247 | /* See tid-parse.h. */ | |
248 | ||
249 | int | |
250 | tid_range_parser_get_tid (struct tid_range_parser *parser, | |
251 | int *inf_num, int *thr_num) | |
252 | { | |
253 | gdb_assert (inf_num != NULL && thr_num != NULL); | |
254 | ||
255 | return get_tid_or_range (parser, inf_num, thr_num, NULL); | |
256 | } | |
257 | ||
258 | /* See tid-parse.h. */ | |
259 | ||
260 | int | |
261 | tid_is_in_list (const char *list, int default_inferior, | |
262 | int inf_num, int thr_num) | |
263 | { | |
264 | struct tid_range_parser parser; | |
265 | ||
266 | if (list == NULL || *list == '\0') | |
267 | return 1; | |
268 | ||
269 | tid_range_parser_init (&parser, list, default_inferior); | |
270 | while (!tid_range_parser_finished (&parser)) | |
271 | { | |
272 | int tmp_inf, tmp_thr_start, tmp_thr_end; | |
273 | ||
274 | if (!tid_range_parser_get_tid_range (&parser, &tmp_inf, | |
275 | &tmp_thr_start, &tmp_thr_end)) | |
276 | invalid_thread_id_error (parser.string); | |
277 | if (tmp_inf == inf_num | |
278 | && tmp_thr_start <= thr_num && thr_num <= tmp_thr_end) | |
279 | return 1; | |
280 | } | |
281 | return 0; | |
282 | } |