Commit | Line | Data |
---|---|---|
5d5658a1 PA |
1 | /* TID parsing for GDB, the GNU debugger. |
2 | ||
e2882c85 | 3 | Copyright (C) 2015-2018 Free Software Foundation, Inc. |
5d5658a1 PA |
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 | ||
28 | void ATTRIBUTE_NORETURN | |
29 | invalid_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 | ||
40 | static int | |
41 | get_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 | ||
53 | struct thread_info * | |
54 | parse_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 | ||
bfd28288 PA |
116 | tid_range_parser::tid_range_parser (const char *tidlist, |
117 | int default_inferior) | |
118 | { | |
119 | init (tidlist, default_inferior); | |
120 | } | |
121 | ||
122 | /* See tid-parse.h. */ | |
123 | ||
5d5658a1 | 124 | void |
bfd28288 | 125 | tid_range_parser::init (const char *tidlist, int default_inferior) |
5d5658a1 | 126 | { |
bfd28288 PA |
127 | m_state = STATE_INFERIOR; |
128 | m_cur_tok = tidlist; | |
129 | m_inf_num = 0; | |
130 | m_qualified = false; | |
131 | m_default_inferior = default_inferior; | |
5d5658a1 PA |
132 | } |
133 | ||
134 | /* See tid-parse.h. */ | |
135 | ||
bfd28288 PA |
136 | bool |
137 | tid_range_parser::finished () const | |
5d5658a1 | 138 | { |
bfd28288 | 139 | switch (m_state) |
5d5658a1 | 140 | { |
bfd28288 PA |
141 | case STATE_INFERIOR: |
142 | return *m_cur_tok == '\0'; | |
143 | case STATE_THREAD_RANGE: | |
144 | case STATE_STAR_RANGE: | |
145 | return m_range_parser.finished (); | |
5d5658a1 PA |
146 | } |
147 | ||
148 | gdb_assert_not_reached (_("unhandled state")); | |
149 | } | |
150 | ||
151 | /* See tid-parse.h. */ | |
152 | ||
153 | const char * | |
bfd28288 | 154 | tid_range_parser::cur_tok () const |
5d5658a1 | 155 | { |
bfd28288 | 156 | switch (m_state) |
5d5658a1 | 157 | { |
bfd28288 PA |
158 | case STATE_INFERIOR: |
159 | return m_cur_tok; | |
160 | case STATE_THREAD_RANGE: | |
161 | case STATE_STAR_RANGE: | |
162 | return m_range_parser.cur_tok (); | |
5d5658a1 PA |
163 | } |
164 | ||
165 | gdb_assert_not_reached (_("unhandled state")); | |
166 | } | |
167 | ||
5d5658a1 | 168 | void |
bfd28288 | 169 | tid_range_parser::skip_range () |
5d5658a1 | 170 | { |
bfd28288 PA |
171 | gdb_assert (m_state == STATE_THREAD_RANGE |
172 | || m_state == STATE_STAR_RANGE); | |
5d5658a1 | 173 | |
bfd28288 PA |
174 | m_range_parser.skip_range (); |
175 | init (m_range_parser.cur_tok (), m_default_inferior); | |
5d5658a1 PA |
176 | } |
177 | ||
178 | /* See tid-parse.h. */ | |
179 | ||
bfd28288 PA |
180 | bool |
181 | tid_range_parser::tid_is_qualified () const | |
5d5658a1 | 182 | { |
bfd28288 | 183 | return m_qualified; |
5d5658a1 PA |
184 | } |
185 | ||
bfd28288 PA |
186 | /* Helper for tid_range_parser::get_tid and |
187 | tid_range_parser::get_tid_range. Return the next range if THR_END | |
5d5658a1 PA |
188 | is non-NULL, return a single thread ID otherwise. */ |
189 | ||
bfd28288 PA |
190 | bool |
191 | tid_range_parser::get_tid_or_range (int *inf_num, | |
192 | int *thr_start, int *thr_end) | |
5d5658a1 | 193 | { |
bfd28288 | 194 | if (m_state == STATE_INFERIOR) |
5d5658a1 PA |
195 | { |
196 | const char *p; | |
197 | const char *space; | |
198 | ||
bfd28288 | 199 | space = skip_to_space (m_cur_tok); |
5d5658a1 | 200 | |
bfd28288 | 201 | p = m_cur_tok; |
5d5658a1 PA |
202 | while (p < space && *p != '.') |
203 | p++; | |
204 | if (p < space) | |
205 | { | |
206 | const char *dot = p; | |
207 | ||
208 | /* Parse number to the left of the dot. */ | |
bfd28288 PA |
209 | p = m_cur_tok; |
210 | m_inf_num = get_positive_number_trailer (&p, '.', m_cur_tok); | |
211 | if (m_inf_num == 0) | |
3f5b7598 | 212 | return 0; |
5d5658a1 | 213 | |
bfd28288 | 214 | m_qualified = true; |
5d5658a1 PA |
215 | p = dot + 1; |
216 | ||
217 | if (isspace (*p)) | |
bfd28288 | 218 | return false; |
5d5658a1 PA |
219 | } |
220 | else | |
221 | { | |
bfd28288 PA |
222 | m_inf_num = m_default_inferior; |
223 | m_qualified = false; | |
224 | p = m_cur_tok; | |
5d5658a1 PA |
225 | } |
226 | ||
bfd28288 | 227 | m_range_parser.init (p); |
71ef29a8 PA |
228 | if (p[0] == '*' && (p[1] == '\0' || isspace (p[1]))) |
229 | { | |
230 | /* Setup the number range parser to return numbers in the | |
231 | whole [1,INT_MAX] range. */ | |
f1735a53 | 232 | m_range_parser.setup_range (1, INT_MAX, skip_spaces (p + 1)); |
bfd28288 | 233 | m_state = STATE_STAR_RANGE; |
71ef29a8 PA |
234 | } |
235 | else | |
bfd28288 | 236 | m_state = STATE_THREAD_RANGE; |
5d5658a1 PA |
237 | } |
238 | ||
bfd28288 PA |
239 | *inf_num = m_inf_num; |
240 | *thr_start = m_range_parser.get_number (); | |
3f5b7598 | 241 | if (*thr_start < 0) |
bfd28288 | 242 | error (_("negative value: %s"), m_cur_tok); |
5d5658a1 | 243 | if (*thr_start == 0) |
3f5b7598 | 244 | { |
bfd28288 PA |
245 | m_state = STATE_INFERIOR; |
246 | return false; | |
3f5b7598 | 247 | } |
5d5658a1 PA |
248 | |
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. */ | |
bfd28288 | 252 | if (!m_range_parser.in_range ()) |
5d5658a1 | 253 | { |
bfd28288 PA |
254 | m_state = STATE_INFERIOR; |
255 | m_cur_tok = m_range_parser.cur_tok (); | |
5d5658a1 PA |
256 | |
257 | if (thr_end != NULL) | |
258 | *thr_end = *thr_start; | |
259 | } | |
260 | ||
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. */ | |
71ef29a8 | 263 | if (thr_end != NULL |
bfd28288 PA |
264 | && (m_state == STATE_THREAD_RANGE |
265 | || m_state == STATE_STAR_RANGE)) | |
5d5658a1 | 266 | { |
bfd28288 PA |
267 | *thr_end = m_range_parser.end_value (); |
268 | ||
269 | skip_range (); | |
5d5658a1 PA |
270 | } |
271 | ||
272 | return (*inf_num != 0 && *thr_start != 0); | |
273 | } | |
274 | ||
275 | /* See tid-parse.h. */ | |
276 | ||
bfd28288 PA |
277 | bool |
278 | tid_range_parser::get_tid_range (int *inf_num, | |
279 | int *thr_start, int *thr_end) | |
5d5658a1 PA |
280 | { |
281 | gdb_assert (inf_num != NULL && thr_start != NULL && thr_end != NULL); | |
282 | ||
bfd28288 | 283 | return get_tid_or_range (inf_num, thr_start, thr_end); |
5d5658a1 PA |
284 | } |
285 | ||
286 | /* See tid-parse.h. */ | |
287 | ||
bfd28288 PA |
288 | bool |
289 | tid_range_parser::get_tid (int *inf_num, int *thr_num) | |
5d5658a1 PA |
290 | { |
291 | gdb_assert (inf_num != NULL && thr_num != NULL); | |
292 | ||
bfd28288 | 293 | return get_tid_or_range (inf_num, thr_num, NULL); |
5d5658a1 PA |
294 | } |
295 | ||
296 | /* See tid-parse.h. */ | |
297 | ||
bfd28288 PA |
298 | bool |
299 | tid_range_parser::in_star_range () const | |
71ef29a8 | 300 | { |
bfd28288 | 301 | return m_state == STATE_STAR_RANGE; |
71ef29a8 PA |
302 | } |
303 | ||
304 | /* See gdbthread.h. */ | |
305 | ||
5d5658a1 PA |
306 | int |
307 | tid_is_in_list (const char *list, int default_inferior, | |
308 | int inf_num, int thr_num) | |
309 | { | |
5d5658a1 PA |
310 | if (list == NULL || *list == '\0') |
311 | return 1; | |
312 | ||
bfd28288 PA |
313 | tid_range_parser parser (list, default_inferior); |
314 | while (!parser.finished ()) | |
5d5658a1 PA |
315 | { |
316 | int tmp_inf, tmp_thr_start, tmp_thr_end; | |
317 | ||
bfd28288 PA |
318 | if (!parser.get_tid_range (&tmp_inf, &tmp_thr_start, &tmp_thr_end)) |
319 | invalid_thread_id_error (parser.cur_tok ()); | |
5d5658a1 PA |
320 | if (tmp_inf == inf_num |
321 | && tmp_thr_start <= thr_num && thr_num <= tmp_thr_end) | |
322 | return 1; | |
323 | } | |
324 | return 0; | |
325 | } |