1 /* TID parsing for GDB, the GNU debugger.
3 Copyright (C) 2015-2019 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;
60 int explicit_inf_id = 0;
62 dot = strchr (number, '.');
66 /* Parse number to the left of the dot. */
70 inf_num = get_positive_number_trailer (&p1, '.', number);
72 invalid_thread_id_error (number);
74 inf = find_inferior_id (inf_num);
76 error (_("No inferior number '%d'"), inf_num);
83 inf = current_inferior ();
88 thr_num = get_positive_number_trailer (&p1, 0, number);
90 invalid_thread_id_error (number);
92 thread_info *tp = nullptr;
93 for (thread_info *it : inf->threads ())
94 if (it->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. */
116 tid_range_parser::tid_range_parser (const char *tidlist,
117 int default_inferior)
119 init (tidlist, default_inferior);
122 /* See tid-parse.h. */
125 tid_range_parser::init (const char *tidlist, int default_inferior)
127 m_state = STATE_INFERIOR;
131 m_default_inferior = default_inferior;
134 /* See tid-parse.h. */
137 tid_range_parser::finished () const
142 return *m_cur_tok == '\0';
143 case STATE_THREAD_RANGE:
144 case STATE_STAR_RANGE:
145 return m_range_parser.finished ();
148 gdb_assert_not_reached (_("unhandled state"));
151 /* See tid-parse.h. */
154 tid_range_parser::cur_tok () const
160 case STATE_THREAD_RANGE:
161 case STATE_STAR_RANGE:
162 return m_range_parser.cur_tok ();
165 gdb_assert_not_reached (_("unhandled state"));
169 tid_range_parser::skip_range ()
171 gdb_assert (m_state == STATE_THREAD_RANGE
172 || m_state == STATE_STAR_RANGE);
174 m_range_parser.skip_range ();
175 init (m_range_parser.cur_tok (), m_default_inferior);
178 /* See tid-parse.h. */
181 tid_range_parser::tid_is_qualified () const
186 /* Helper for tid_range_parser::get_tid and
187 tid_range_parser::get_tid_range. Return the next range if THR_END
188 is non-NULL, return a single thread ID otherwise. */
191 tid_range_parser::get_tid_or_range (int *inf_num,
192 int *thr_start, int *thr_end)
194 if (m_state == STATE_INFERIOR)
199 space = skip_to_space (m_cur_tok);
202 while (p < space && *p != '.')
208 /* Parse number to the left of the dot. */
210 m_inf_num = get_positive_number_trailer (&p, '.', m_cur_tok);
222 m_inf_num = m_default_inferior;
227 m_range_parser.init (p);
228 if (p[0] == '*' && (p[1] == '\0' || isspace (p[1])))
230 /* Setup the number range parser to return numbers in the
231 whole [1,INT_MAX] range. */
232 m_range_parser.setup_range (1, INT_MAX, skip_spaces (p + 1));
233 m_state = STATE_STAR_RANGE;
236 m_state = STATE_THREAD_RANGE;
239 *inf_num = m_inf_num;
240 *thr_start = m_range_parser.get_number ();
242 error (_("negative value: %s"), m_cur_tok);
245 m_state = STATE_INFERIOR;
249 /* If we successfully parsed a thread number or finished parsing a
250 thread range, switch back to assuming the next TID is
251 inferior-qualified. */
252 if (!m_range_parser.in_range ())
254 m_state = STATE_INFERIOR;
255 m_cur_tok = m_range_parser.cur_tok ();
258 *thr_end = *thr_start;
261 /* If we're midway through a range, and the caller wants the end
262 value, return it and skip to the end of the range. */
264 && (m_state == STATE_THREAD_RANGE
265 || m_state == STATE_STAR_RANGE))
267 *thr_end = m_range_parser.end_value ();
272 return (*inf_num != 0 && *thr_start != 0);
275 /* See tid-parse.h. */
278 tid_range_parser::get_tid_range (int *inf_num,
279 int *thr_start, int *thr_end)
281 gdb_assert (inf_num != NULL && thr_start != NULL && thr_end != NULL);
283 return get_tid_or_range (inf_num, thr_start, thr_end);
286 /* See tid-parse.h. */
289 tid_range_parser::get_tid (int *inf_num, int *thr_num)
291 gdb_assert (inf_num != NULL && thr_num != NULL);
293 return get_tid_or_range (inf_num, thr_num, NULL);
296 /* See tid-parse.h. */
299 tid_range_parser::in_star_range () const
301 return m_state == STATE_STAR_RANGE;
304 /* See tid-parse.h. */
307 tid_is_in_list (const char *list, int default_inferior,
308 int inf_num, int thr_num)
310 if (list == NULL || *list == '\0')
313 tid_range_parser parser (list, default_inferior);
314 while (!parser.finished ())
316 int tmp_inf, tmp_thr_start, tmp_thr_end;
318 if (!parser.get_tid_range (&tmp_inf, &tmp_thr_start, &tmp_thr_end))
319 invalid_thread_id_error (parser.cur_tok ());
320 if (tmp_inf == inf_num
321 && tmp_thr_start <= thr_num && thr_num <= tmp_thr_end)