Automatic date update in version.in
[deliverable/binutils-gdb.git] / gdb / tid-parse.c
CommitLineData
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
28void ATTRIBUTE_NORETURN
29invalid_thread_id_error (const char *string)
30{
31 error (_("Invalid thread ID: %s"), string);
32}
33
3f5b7598
PA
34/* Wrapper for get_number_trailer that throws an error if we get back
35 a negative number. We'll see a negative value if the number is
36 stored in a negative convenience variable (e.g., $minus_one = -1).
37 STRING is the parser string to be used in the error message if we
38 do get back a negative number. */
39
40static int
41get_positive_number_trailer (const char **pp, int trailer, const char *string)
42{
43 int num;
44
45 num = get_number_trailer (pp, trailer);
46 if (num < 0)
47 error (_("negative value: %s"), string);
48 return num;
49}
50
5d5658a1
PA
51/* See tid-parse.h. */
52
53struct thread_info *
54parse_thread_id (const char *tidstr, const char **end)
55{
56 const char *number = tidstr;
57 const char *dot, *p1;
58 struct thread_info *tp;
59 struct inferior *inf;
60 int thr_num;
61 int explicit_inf_id = 0;
62
63 dot = strchr (number, '.');
64
65 if (dot != NULL)
66 {
67 /* Parse number to the left of the dot. */
68 int inf_num;
69
70 p1 = number;
3f5b7598 71 inf_num = get_positive_number_trailer (&p1, '.', number);
5d5658a1
PA
72 if (inf_num == 0)
73 invalid_thread_id_error (number);
74
75 inf = find_inferior_id (inf_num);
76 if (inf == NULL)
77 error (_("No inferior number '%d'"), inf_num);
78
79 explicit_inf_id = 1;
80 p1 = dot + 1;
81 }
82 else
83 {
84 inf = current_inferior ();
85
86 p1 = number;
87 }
88
3f5b7598 89 thr_num = get_positive_number_trailer (&p1, 0, number);
5d5658a1
PA
90 if (thr_num == 0)
91 invalid_thread_id_error (number);
92
93 ALL_THREADS (tp)
94 {
95 if (ptid_get_pid (tp->ptid) == inf->pid
96 && tp->per_inf_num == thr_num)
97 break;
98 }
99
100 if (tp == NULL)
101 {
102 if (show_inferior_qualified_tids () || explicit_inf_id)
103 error (_("Unknown thread %d.%d."), inf->num, thr_num);
104 else
105 error (_("Unknown thread %d."), thr_num);
106 }
107
108 if (end != NULL)
109 *end = p1;
110
111 return tp;
112}
113
114/* See tid-parse.h. */
115
116void
117tid_range_parser_init (struct tid_range_parser *parser, const char *tidlist,
118 int default_inferior)
119{
120 parser->state = TID_RANGE_STATE_INFERIOR;
121 parser->string = tidlist;
122 parser->inf_num = 0;
123 parser->qualified = 0;
124 parser->default_inferior = default_inferior;
125}
126
127/* See tid-parse.h. */
128
129int
130tid_range_parser_finished (struct tid_range_parser *parser)
131{
132 switch (parser->state)
133 {
134 case TID_RANGE_STATE_INFERIOR:
135 return *parser->string == '\0';
136 case TID_RANGE_STATE_THREAD_RANGE:
71ef29a8 137 case TID_RANGE_STATE_STAR_RANGE:
5d5658a1
PA
138 return parser->range_parser.finished;
139 }
140
141 gdb_assert_not_reached (_("unhandled state"));
142}
143
144/* See tid-parse.h. */
145
146const char *
147tid_range_parser_string (struct tid_range_parser *parser)
148{
149 switch (parser->state)
150 {
151 case TID_RANGE_STATE_INFERIOR:
152 return parser->string;
153 case TID_RANGE_STATE_THREAD_RANGE:
71ef29a8 154 case TID_RANGE_STATE_STAR_RANGE:
5d5658a1
PA
155 return parser->range_parser.string;
156 }
157
158 gdb_assert_not_reached (_("unhandled state"));
159}
160
161/* See tid-parse.h. */
162
163void
164tid_range_parser_skip (struct tid_range_parser *parser)
165{
71ef29a8
PA
166 gdb_assert ((parser->state == TID_RANGE_STATE_THREAD_RANGE
167 || parser->state == TID_RANGE_STATE_STAR_RANGE)
5d5658a1
PA
168 && parser->range_parser.in_range);
169
170 tid_range_parser_init (parser, parser->range_parser.end_ptr,
171 parser->default_inferior);
172}
173
174/* See tid-parse.h. */
175
176int
177tid_range_parser_qualified (struct tid_range_parser *parser)
178{
179 return parser->qualified;
180}
181
182/* Helper for tid_range_parser_get_tid and
183 tid_range_parser_get_tid_range. Return the next range if THR_END
184 is non-NULL, return a single thread ID otherwise. */
185
186static int
187get_tid_or_range (struct tid_range_parser *parser, int *inf_num,
188 int *thr_start, int *thr_end)
189{
190 if (parser->state == TID_RANGE_STATE_INFERIOR)
191 {
192 const char *p;
193 const char *space;
194
195 space = skip_to_space (parser->string);
196
197 p = parser->string;
198 while (p < space && *p != '.')
199 p++;
200 if (p < space)
201 {
202 const char *dot = p;
203
204 /* Parse number to the left of the dot. */
205 p = parser->string;
3f5b7598
PA
206 parser->inf_num
207 = get_positive_number_trailer (&p, '.', parser->string);
5d5658a1 208 if (parser->inf_num == 0)
3f5b7598 209 return 0;
5d5658a1
PA
210
211 parser->qualified = 1;
212 p = dot + 1;
213
214 if (isspace (*p))
3f5b7598 215 return 0;
5d5658a1
PA
216 }
217 else
218 {
219 parser->inf_num = parser->default_inferior;
220 parser->qualified = 0;
221 p = parser->string;
222 }
223
224 init_number_or_range (&parser->range_parser, p);
71ef29a8
PA
225 if (p[0] == '*' && (p[1] == '\0' || isspace (p[1])))
226 {
227 /* Setup the number range parser to return numbers in the
228 whole [1,INT_MAX] range. */
229 number_range_setup_range (&parser->range_parser, 1, INT_MAX,
230 skip_spaces_const (p + 1));
231 parser->state = TID_RANGE_STATE_STAR_RANGE;
232 }
233 else
234 parser->state = TID_RANGE_STATE_THREAD_RANGE;
5d5658a1
PA
235 }
236
237 *inf_num = parser->inf_num;
238 *thr_start = get_number_or_range (&parser->range_parser);
3f5b7598
PA
239 if (*thr_start < 0)
240 error (_("negative value: %s"), parser->string);
5d5658a1 241 if (*thr_start == 0)
3f5b7598
PA
242 {
243 parser->state = TID_RANGE_STATE_INFERIOR;
244 return 0;
245 }
5d5658a1
PA
246
247 /* If we successfully parsed a thread number or finished parsing a
248 thread range, switch back to assuming the next TID is
249 inferior-qualified. */
250 if (parser->range_parser.end_ptr == NULL
251 || parser->range_parser.string == parser->range_parser.end_ptr)
252 {
253 parser->state = TID_RANGE_STATE_INFERIOR;
254 parser->string = parser->range_parser.string;
255
256 if (thr_end != NULL)
257 *thr_end = *thr_start;
258 }
259
260 /* If we're midway through a range, and the caller wants the end
261 value, return it and skip to the end of the range. */
71ef29a8
PA
262 if (thr_end != NULL
263 && (parser->state == TID_RANGE_STATE_THREAD_RANGE
264 || parser->state == TID_RANGE_STATE_STAR_RANGE))
5d5658a1
PA
265 {
266 *thr_end = parser->range_parser.end_value;
267 tid_range_parser_skip (parser);
268 }
269
270 return (*inf_num != 0 && *thr_start != 0);
271}
272
273/* See tid-parse.h. */
274
275int
276tid_range_parser_get_tid_range (struct tid_range_parser *parser, int *inf_num,
277 int *thr_start, int *thr_end)
278{
279 gdb_assert (inf_num != NULL && thr_start != NULL && thr_end != NULL);
280
281 return get_tid_or_range (parser, inf_num, thr_start, thr_end);
282}
283
284/* See tid-parse.h. */
285
286int
287tid_range_parser_get_tid (struct tid_range_parser *parser,
288 int *inf_num, int *thr_num)
289{
290 gdb_assert (inf_num != NULL && thr_num != NULL);
291
292 return get_tid_or_range (parser, inf_num, thr_num, NULL);
293}
294
295/* See tid-parse.h. */
296
71ef29a8
PA
297int
298tid_range_parser_star_range (struct tid_range_parser *parser)
299{
300 return parser->state == TID_RANGE_STATE_STAR_RANGE;
301}
302
303/* See gdbthread.h. */
304
5d5658a1
PA
305int
306tid_is_in_list (const char *list, int default_inferior,
307 int inf_num, int thr_num)
308{
309 struct tid_range_parser parser;
310
311 if (list == NULL || *list == '\0')
312 return 1;
313
314 tid_range_parser_init (&parser, list, default_inferior);
315 while (!tid_range_parser_finished (&parser))
316 {
317 int tmp_inf, tmp_thr_start, tmp_thr_end;
318
319 if (!tid_range_parser_get_tid_range (&parser, &tmp_inf,
320 &tmp_thr_start, &tmp_thr_end))
321 invalid_thread_id_error (parser.string);
322 if (tmp_inf == inf_num
323 && tmp_thr_start <= thr_num && thr_num <= tmp_thr_end)
324 return 1;
325 }
326 return 0;
327}
This page took 0.117121 seconds and 4 git commands to generate.