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 case TID_RANGE_STATE_STAR_RANGE
:
138 return parser
->range_parser
.finished
;
141 gdb_assert_not_reached (_("unhandled state"));
144 /* See tid-parse.h. */
147 tid_range_parser_string (struct tid_range_parser
*parser
)
149 switch (parser
->state
)
151 case TID_RANGE_STATE_INFERIOR
:
152 return parser
->string
;
153 case TID_RANGE_STATE_THREAD_RANGE
:
154 case TID_RANGE_STATE_STAR_RANGE
:
155 return parser
->range_parser
.string
;
158 gdb_assert_not_reached (_("unhandled state"));
161 /* See tid-parse.h. */
164 tid_range_parser_skip (struct tid_range_parser
*parser
)
166 gdb_assert ((parser
->state
== TID_RANGE_STATE_THREAD_RANGE
167 || parser
->state
== TID_RANGE_STATE_STAR_RANGE
)
168 && parser
->range_parser
.in_range
);
170 tid_range_parser_init (parser
, parser
->range_parser
.end_ptr
,
171 parser
->default_inferior
);
174 /* See tid-parse.h. */
177 tid_range_parser_qualified (struct tid_range_parser
*parser
)
179 return parser
->qualified
;
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. */
187 get_tid_or_range (struct tid_range_parser
*parser
, int *inf_num
,
188 int *thr_start
, int *thr_end
)
190 if (parser
->state
== TID_RANGE_STATE_INFERIOR
)
195 space
= skip_to_space (parser
->string
);
198 while (p
< space
&& *p
!= '.')
204 /* Parse number to the left of the dot. */
207 = get_positive_number_trailer (&p
, '.', parser
->string
);
208 if (parser
->inf_num
== 0)
211 parser
->qualified
= 1;
219 parser
->inf_num
= parser
->default_inferior
;
220 parser
->qualified
= 0;
224 init_number_or_range (&parser
->range_parser
, p
);
225 if (p
[0] == '*' && (p
[1] == '\0' || isspace (p
[1])))
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
;
234 parser
->state
= TID_RANGE_STATE_THREAD_RANGE
;
237 *inf_num
= parser
->inf_num
;
238 *thr_start
= get_number_or_range (&parser
->range_parser
);
240 error (_("negative value: %s"), parser
->string
);
243 parser
->state
= TID_RANGE_STATE_INFERIOR
;
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
)
253 parser
->state
= TID_RANGE_STATE_INFERIOR
;
254 parser
->string
= parser
->range_parser
.string
;
257 *thr_end
= *thr_start
;
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. */
263 && (parser
->state
== TID_RANGE_STATE_THREAD_RANGE
264 || parser
->state
== TID_RANGE_STATE_STAR_RANGE
))
266 *thr_end
= parser
->range_parser
.end_value
;
267 tid_range_parser_skip (parser
);
270 return (*inf_num
!= 0 && *thr_start
!= 0);
273 /* See tid-parse.h. */
276 tid_range_parser_get_tid_range (struct tid_range_parser
*parser
, int *inf_num
,
277 int *thr_start
, int *thr_end
)
279 gdb_assert (inf_num
!= NULL
&& thr_start
!= NULL
&& thr_end
!= NULL
);
281 return get_tid_or_range (parser
, inf_num
, thr_start
, thr_end
);
284 /* See tid-parse.h. */
287 tid_range_parser_get_tid (struct tid_range_parser
*parser
,
288 int *inf_num
, int *thr_num
)
290 gdb_assert (inf_num
!= NULL
&& thr_num
!= NULL
);
292 return get_tid_or_range (parser
, inf_num
, thr_num
, NULL
);
295 /* See tid-parse.h. */
298 tid_range_parser_star_range (struct tid_range_parser
*parser
)
300 return parser
->state
== TID_RANGE_STATE_STAR_RANGE
;
303 /* See gdbthread.h. */
306 tid_is_in_list (const char *list
, int default_inferior
,
307 int inf_num
, int thr_num
)
309 struct tid_range_parser parser
;
311 if (list
== NULL
|| *list
== '\0')
314 tid_range_parser_init (&parser
, list
, default_inferior
);
315 while (!tid_range_parser_finished (&parser
))
317 int tmp_inf
, tmp_thr_start
, tmp_thr_end
;
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
)