arm, objdump: print obsolote warning when 26-bit set in instructions
[binutils-gdb.git] / gdb / tid-parse.c
blob442d5b33693cdf8850fd65814578a2ecb7b44c24
1 /* TID parsing for GDB, the GNU debugger.
3 Copyright (C) 2015-2024 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/>. */
20 #include "tid-parse.h"
21 #include "inferior.h"
22 #include "gdbthread.h"
23 #include <ctype.h>
25 /* See tid-parse.h. */
27 [[noreturn]] void
28 invalid_thread_id_error (const char *string)
30 error (_("Invalid thread ID: %s"), string);
33 /* Wrapper for get_number_trailer that throws an error if we get back
34 a negative number. We'll see a negative value if the number is
35 stored in a negative convenience variable (e.g., $minus_one = -1).
36 STRING is the parser string to be used in the error message if we
37 do get back a negative number. */
39 static int
40 get_positive_number_trailer (const char **pp, int trailer, const char *string)
42 int num;
44 num = get_number_trailer (pp, trailer);
45 if (num < 0)
46 error (_("negative value: %s"), string);
47 return num;
50 /* Parse TIDSTR as a per-inferior thread ID, in either INF_NUM.THR_NUM
51 or THR_NUM form, and return a pair, the first item of the pair is
52 INF_NUM and the second item is THR_NUM.
54 If TIDSTR does not include an INF_NUM component, then the first item in
55 the pair will be 0 (which is an invalid inferior number), this indicates
56 that TIDSTR references the current inferior.
58 This function does not validate the INF_NUM and THR_NUM are actually
59 valid numbers, that is, they might reference inferiors or threads that
60 don't actually exist; this function just splits the string into its
61 component parts.
63 If there is an error parsing TIDSTR then this function will raise an
64 exception. */
66 static std::pair<int, int>
67 parse_thread_id_1 (const char *tidstr, const char **end)
69 const char *number = tidstr;
70 const char *dot, *p1;
71 int thr_num, inf_num;
73 dot = strchr (number, '.');
75 if (dot != NULL)
77 /* Parse number to the left of the dot. */
78 p1 = number;
79 inf_num = get_positive_number_trailer (&p1, '.', number);
80 if (inf_num == 0)
81 invalid_thread_id_error (number);
82 p1 = dot + 1;
84 else
86 inf_num = 0;
87 p1 = number;
90 thr_num = get_positive_number_trailer (&p1, 0, number);
91 if (thr_num == 0)
92 invalid_thread_id_error (number);
94 if (end != nullptr)
95 *end = p1;
97 return { inf_num, thr_num };
100 /* See tid-parse.h. */
102 struct thread_info *
103 parse_thread_id (const char *tidstr, const char **end)
105 const auto [inf_num, thr_num] = parse_thread_id_1 (tidstr, end);
107 inferior *inf;
108 bool explicit_inf_id = false;
110 if (inf_num != 0)
112 inf = find_inferior_id (inf_num);
113 if (inf == nullptr)
114 error (_("No inferior number '%d'"), inf_num);
115 explicit_inf_id = true;
117 else
118 inf = current_inferior ();
120 thread_info *tp = nullptr;
121 for (thread_info *it : inf->threads ())
122 if (it->per_inf_num == thr_num)
124 tp = it;
125 break;
128 if (tp == nullptr)
130 if (show_inferior_qualified_tids () || explicit_inf_id)
131 error (_("Unknown thread %d.%d."), inf->num, thr_num);
132 else
133 error (_("Unknown thread %d."), thr_num);
136 return tp;
139 /* See tid-parse.h. */
141 bool
142 is_thread_id (const char *tidstr, const char **end)
146 (void) parse_thread_id_1 (tidstr, end);
147 return true;
149 catch (const gdb_exception_error &)
151 return false;
155 /* See tid-parse.h. */
157 tid_range_parser::tid_range_parser (const char *tidlist,
158 int default_inferior)
160 init (tidlist, default_inferior);
163 /* See tid-parse.h. */
165 void
166 tid_range_parser::init (const char *tidlist, int default_inferior)
168 m_state = STATE_INFERIOR;
169 m_cur_tok = tidlist;
170 m_inf_num = 0;
171 m_qualified = false;
172 m_default_inferior = default_inferior;
175 /* See tid-parse.h. */
177 bool
178 tid_range_parser::finished () const
180 switch (m_state)
182 case STATE_INFERIOR:
183 /* Parsing is finished when at end of string or null string,
184 or we are not in a range and not in front of an integer, negative
185 integer, convenience var or negative convenience var. */
186 return (*m_cur_tok == '\0'
187 || !(isdigit (*m_cur_tok)
188 || *m_cur_tok == '$'
189 || *m_cur_tok == '*'));
190 case STATE_THREAD_RANGE:
191 case STATE_STAR_RANGE:
192 return m_range_parser.finished ();
195 gdb_assert_not_reached ("unhandled state");
198 /* See tid-parse.h. */
200 const char *
201 tid_range_parser::cur_tok () const
203 switch (m_state)
205 case STATE_INFERIOR:
206 return m_cur_tok;
207 case STATE_THREAD_RANGE:
208 case STATE_STAR_RANGE:
209 return m_range_parser.cur_tok ();
212 gdb_assert_not_reached ("unhandled state");
215 void
216 tid_range_parser::skip_range ()
218 gdb_assert (m_state == STATE_THREAD_RANGE
219 || m_state == STATE_STAR_RANGE);
221 m_range_parser.skip_range ();
222 init (m_range_parser.cur_tok (), m_default_inferior);
225 /* See tid-parse.h. */
227 bool
228 tid_range_parser::tid_is_qualified () const
230 return m_qualified;
233 /* Helper for tid_range_parser::get_tid and
234 tid_range_parser::get_tid_range. Return the next range if THR_END
235 is non-NULL, return a single thread ID otherwise. */
237 bool
238 tid_range_parser::get_tid_or_range (int *inf_num,
239 int *thr_start, int *thr_end)
241 if (m_state == STATE_INFERIOR)
243 const char *p;
244 const char *space;
246 space = skip_to_space (m_cur_tok);
248 p = m_cur_tok;
249 while (p < space && *p != '.')
250 p++;
251 if (p < space)
253 const char *dot = p;
255 /* Parse number to the left of the dot. */
256 p = m_cur_tok;
257 m_inf_num = get_positive_number_trailer (&p, '.', m_cur_tok);
258 if (m_inf_num == 0)
259 return 0;
261 m_qualified = true;
262 p = dot + 1;
264 if (isspace (*p))
265 return false;
267 else
269 m_inf_num = m_default_inferior;
270 m_qualified = false;
271 p = m_cur_tok;
274 m_range_parser.init (p);
275 if (p[0] == '*' && (p[1] == '\0' || isspace (p[1])))
277 /* Setup the number range parser to return numbers in the
278 whole [1,INT_MAX] range. */
279 m_range_parser.setup_range (1, INT_MAX, skip_spaces (p + 1));
280 m_state = STATE_STAR_RANGE;
282 else
283 m_state = STATE_THREAD_RANGE;
286 *inf_num = m_inf_num;
287 *thr_start = m_range_parser.get_number ();
288 if (*thr_start < 0)
289 error (_("negative value: %s"), m_cur_tok);
290 if (*thr_start == 0)
292 m_state = STATE_INFERIOR;
293 return false;
296 /* If we successfully parsed a thread number or finished parsing a
297 thread range, switch back to assuming the next TID is
298 inferior-qualified. */
299 if (!m_range_parser.in_range ())
301 m_state = STATE_INFERIOR;
302 m_cur_tok = m_range_parser.cur_tok ();
304 if (thr_end != NULL)
305 *thr_end = *thr_start;
308 /* If we're midway through a range, and the caller wants the end
309 value, return it and skip to the end of the range. */
310 if (thr_end != NULL
311 && (m_state == STATE_THREAD_RANGE
312 || m_state == STATE_STAR_RANGE))
314 *thr_end = m_range_parser.end_value ();
316 skip_range ();
319 return (*inf_num != 0 && *thr_start != 0);
322 /* See tid-parse.h. */
324 bool
325 tid_range_parser::get_tid_range (int *inf_num,
326 int *thr_start, int *thr_end)
328 gdb_assert (inf_num != NULL && thr_start != NULL && thr_end != NULL);
330 return get_tid_or_range (inf_num, thr_start, thr_end);
333 /* See tid-parse.h. */
335 bool
336 tid_range_parser::get_tid (int *inf_num, int *thr_num)
338 gdb_assert (inf_num != NULL && thr_num != NULL);
340 return get_tid_or_range (inf_num, thr_num, NULL);
343 /* See tid-parse.h. */
345 bool
346 tid_range_parser::in_star_range () const
348 return m_state == STATE_STAR_RANGE;
351 bool
352 tid_range_parser::in_thread_range () const
354 return m_state == STATE_THREAD_RANGE;
357 /* See tid-parse.h. */
360 tid_is_in_list (const char *list, int default_inferior,
361 int inf_num, int thr_num)
363 if (list == NULL || *list == '\0')
364 return 1;
366 tid_range_parser parser (list, default_inferior);
367 if (parser.finished ())
368 invalid_thread_id_error (parser.cur_tok ());
369 while (!parser.finished ())
371 int tmp_inf, tmp_thr_start, tmp_thr_end;
373 if (!parser.get_tid_range (&tmp_inf, &tmp_thr_start, &tmp_thr_end))
374 invalid_thread_id_error (parser.cur_tok ());
375 if (tmp_inf == inf_num
376 && tmp_thr_start <= thr_num && thr_num <= tmp_thr_end)
377 return 1;
379 return 0;