1 /* TID parsing for GDB, the GNU debugger.
3 Copyright (C) 2015-2016 Free Software Foundation, Inc.
5 This file is part of GDB.
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.
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.
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/>. */
21 #include "tid-parse.h"
23 #include "gdbthread.h"
26 /* See tid-parse.h. */
28 void ATTRIBUTE_NORETURN
29 invalid_thread_id_error (const char *string)
31 error (_("Invalid thread ID: %s"), string);
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. */
41 get_positive_number_trailer (const char **pp, int trailer, const char *string)
45 num = get_number_trailer (pp, trailer);
47 error (_("negative value: %s"), string);
51 /* See tid-parse.h. */
54 parse_thread_id (const char *tidstr, const char **end)
56 const char *number = tidstr;
58 struct thread_info *tp;
61 int explicit_inf_id = 0;
63 dot = strchr (number, '.');
67 /* Parse number to the left of the dot. */
71 inf_num = get_positive_number_trailer (&p1, '.', number);
73 invalid_thread_id_error (number);
75 inf = find_inferior_id (inf_num);
77 error (_("No inferior number '%d'"), inf_num);
84 inf = current_inferior ();
89 thr_num = get_positive_number_trailer (&p1, 0, number);
91 invalid_thread_id_error (number);
95 if (ptid_get_pid (tp->ptid) == inf->pid
96 && tp->per_inf_num == thr_num)
102 if (show_inferior_qualified_tids () || explicit_inf_id)
103 error (_("Unknown thread %d.%d."), inf->num, thr_num);
105 error (_("Unknown thread %d."), thr_num);
114 /* See tid-parse.h. */
117 tid_range_parser_init (struct tid_range_parser *parser, const char *tidlist,
118 int default_inferior)
120 parser->state = TID_RANGE_STATE_INFERIOR;
121 parser->string = tidlist;
123 parser->qualified = 0;
124 parser->default_inferior = default_inferior;
127 /* See tid-parse.h. */
130 tid_range_parser_finished (struct tid_range_parser *parser)
132 switch (parser->state)
134 case TID_RANGE_STATE_INFERIOR:
135 return *parser->string == '\0';
136 case TID_RANGE_STATE_THREAD_RANGE:
137 return parser->range_parser.finished;
140 gdb_assert_not_reached (_("unhandled state"));
143 /* See tid-parse.h. */
146 tid_range_parser_string (struct tid_range_parser *parser)
148 switch (parser->state)
150 case TID_RANGE_STATE_INFERIOR:
151 return parser->string;
152 case TID_RANGE_STATE_THREAD_RANGE:
153 return parser->range_parser.string;
156 gdb_assert_not_reached (_("unhandled state"));
159 /* See tid-parse.h. */
162 tid_range_parser_skip (struct tid_range_parser *parser)
164 gdb_assert ((parser->state == TID_RANGE_STATE_THREAD_RANGE)
165 && parser->range_parser.in_range);
167 tid_range_parser_init (parser, parser->range_parser.end_ptr,
168 parser->default_inferior);
171 /* See tid-parse.h. */
174 tid_range_parser_qualified (struct tid_range_parser *parser)
176 return parser->qualified;
179 /* Helper for tid_range_parser_get_tid and
180 tid_range_parser_get_tid_range. Return the next range if THR_END
181 is non-NULL, return a single thread ID otherwise. */
184 get_tid_or_range (struct tid_range_parser *parser, int *inf_num,
185 int *thr_start, int *thr_end)
187 if (parser->state == TID_RANGE_STATE_INFERIOR)
192 space = skip_to_space (parser->string);
195 while (p < space && *p != '.')
201 /* Parse number to the left of the dot. */
204 = get_positive_number_trailer (&p, '.', parser->string);
205 if (parser->inf_num == 0)
208 parser->qualified = 1;
216 parser->inf_num = parser->default_inferior;
217 parser->qualified = 0;
221 init_number_or_range (&parser->range_parser, p);
222 parser->state = TID_RANGE_STATE_THREAD_RANGE;
225 *inf_num = parser->inf_num;
226 *thr_start = get_number_or_range (&parser->range_parser);
228 error (_("negative value: %s"), parser->string);
231 parser->state = TID_RANGE_STATE_INFERIOR;
235 /* If we successfully parsed a thread number or finished parsing a
236 thread range, switch back to assuming the next TID is
237 inferior-qualified. */
238 if (parser->range_parser.end_ptr == NULL
239 || parser->range_parser.string == parser->range_parser.end_ptr)
241 parser->state = TID_RANGE_STATE_INFERIOR;
242 parser->string = parser->range_parser.string;
245 *thr_end = *thr_start;
248 /* If we're midway through a range, and the caller wants the end
249 value, return it and skip to the end of the range. */
250 if (thr_end != NULL && parser->state == TID_RANGE_STATE_THREAD_RANGE)
252 *thr_end = parser->range_parser.end_value;
253 tid_range_parser_skip (parser);
256 return (*inf_num != 0 && *thr_start != 0);
259 /* See tid-parse.h. */
262 tid_range_parser_get_tid_range (struct tid_range_parser *parser, int *inf_num,
263 int *thr_start, int *thr_end)
265 gdb_assert (inf_num != NULL && thr_start != NULL && thr_end != NULL);
267 return get_tid_or_range (parser, inf_num, thr_start, thr_end);
270 /* See tid-parse.h. */
273 tid_range_parser_get_tid (struct tid_range_parser *parser,
274 int *inf_num, int *thr_num)
276 gdb_assert (inf_num != NULL && thr_num != NULL);
278 return get_tid_or_range (parser, inf_num, thr_num, NULL);
281 /* See tid-parse.h. */
284 tid_is_in_list (const char *list, int default_inferior,
285 int inf_num, int thr_num)
287 struct tid_range_parser parser;
289 if (list == NULL || *list == '\0')
292 tid_range_parser_init (&parser, list, default_inferior);
293 while (!tid_range_parser_finished (&parser))
295 int tmp_inf, tmp_thr_start, tmp_thr_end;
297 if (!tid_range_parser_get_tid_range (&parser, &tmp_inf,
298 &tmp_thr_start, &tmp_thr_end))
299 invalid_thread_id_error (parser.string);
300 if (tmp_inf == inf_num
301 && tmp_thr_start <= thr_num && thr_num <= tmp_thr_end)