Fix "thread apply $conv_var" and misc other related problems
[external/binutils.git] / gdb / tid-parse.c
1 /* TID parsing for GDB, the GNU debugger.
2
3    Copyright (C) 2015-2016 Free Software Foundation, Inc.
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
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
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;
71       inf_num = get_positive_number_trailer (&p1, '.', number);
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
89   thr_num = get_positive_number_trailer (&p1, 0, number);
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
116 void
117 tid_range_parser_init (struct tid_range_parser *parser, const char *tidlist,
118                        int default_inferior)
119 {
120   parser->state = TID_RANGE_STATE_INFERIOR;
121   parser->string = tidlist;
122   parser->inf_num = 0;
123   parser->qualified = 0;
124   parser->default_inferior = default_inferior;
125 }
126
127 /* See tid-parse.h.  */
128
129 int
130 tid_range_parser_finished (struct tid_range_parser *parser)
131 {
132   switch (parser->state)
133     {
134     case TID_RANGE_STATE_INFERIOR:
135       return *parser->string == '\0';
136     case TID_RANGE_STATE_THREAD_RANGE:
137       return parser->range_parser.finished;
138     }
139
140   gdb_assert_not_reached (_("unhandled state"));
141 }
142
143 /* See tid-parse.h.  */
144
145 const char *
146 tid_range_parser_string (struct tid_range_parser *parser)
147 {
148   switch (parser->state)
149     {
150     case TID_RANGE_STATE_INFERIOR:
151       return parser->string;
152     case TID_RANGE_STATE_THREAD_RANGE:
153       return parser->range_parser.string;
154     }
155
156   gdb_assert_not_reached (_("unhandled state"));
157 }
158
159 /* See tid-parse.h.  */
160
161 void
162 tid_range_parser_skip (struct tid_range_parser *parser)
163 {
164   gdb_assert ((parser->state == TID_RANGE_STATE_THREAD_RANGE)
165               && parser->range_parser.in_range);
166
167   tid_range_parser_init (parser, parser->range_parser.end_ptr,
168                          parser->default_inferior);
169 }
170
171 /* See tid-parse.h.  */
172
173 int
174 tid_range_parser_qualified (struct tid_range_parser *parser)
175 {
176   return parser->qualified;
177 }
178
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.  */
182
183 static int
184 get_tid_or_range (struct tid_range_parser *parser, int *inf_num,
185                   int *thr_start, int *thr_end)
186 {
187   if (parser->state == TID_RANGE_STATE_INFERIOR)
188     {
189       const char *p;
190       const char *space;
191
192       space = skip_to_space (parser->string);
193
194       p = parser->string;
195       while (p < space && *p != '.')
196         p++;
197       if (p < space)
198         {
199           const char *dot = p;
200
201           /* Parse number to the left of the dot.  */
202           p = parser->string;
203           parser->inf_num
204             = get_positive_number_trailer (&p, '.', parser->string);
205           if (parser->inf_num == 0)
206             return 0;
207
208           parser->qualified = 1;
209           p = dot + 1;
210
211           if (isspace (*p))
212             return 0;
213         }
214       else
215         {
216           parser->inf_num = parser->default_inferior;
217           parser->qualified = 0;
218           p = parser->string;
219         }
220
221       init_number_or_range (&parser->range_parser, p);
222       parser->state = TID_RANGE_STATE_THREAD_RANGE;
223     }
224
225   *inf_num = parser->inf_num;
226   *thr_start = get_number_or_range (&parser->range_parser);
227   if (*thr_start < 0)
228     error (_("negative value: %s"), parser->string);
229   if (*thr_start == 0)
230     {
231       parser->state = TID_RANGE_STATE_INFERIOR;
232       return 0;
233     }
234
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)
240     {
241       parser->state = TID_RANGE_STATE_INFERIOR;
242       parser->string = parser->range_parser.string;
243
244       if (thr_end != NULL)
245         *thr_end = *thr_start;
246     }
247
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)
251     {
252       *thr_end = parser->range_parser.end_value;
253       tid_range_parser_skip (parser);
254     }
255
256   return (*inf_num != 0 && *thr_start != 0);
257 }
258
259 /* See tid-parse.h.  */
260
261 int
262 tid_range_parser_get_tid_range (struct tid_range_parser *parser, int *inf_num,
263                                 int *thr_start, int *thr_end)
264 {
265   gdb_assert (inf_num != NULL && thr_start != NULL && thr_end != NULL);
266
267   return get_tid_or_range (parser, inf_num, thr_start, thr_end);
268 }
269
270 /* See tid-parse.h.  */
271
272 int
273 tid_range_parser_get_tid (struct tid_range_parser *parser,
274                           int *inf_num, int *thr_num)
275 {
276   gdb_assert (inf_num != NULL && thr_num != NULL);
277
278   return get_tid_or_range (parser, inf_num, thr_num, NULL);
279 }
280
281 /* See tid-parse.h.  */
282
283 int
284 tid_is_in_list (const char *list, int default_inferior,
285                 int inf_num, int thr_num)
286 {
287   struct tid_range_parser parser;
288
289   if (list == NULL || *list == '\0')
290     return 1;
291
292   tid_range_parser_init (&parser, list, default_inferior);
293   while (!tid_range_parser_finished (&parser))
294     {
295       int tmp_inf, tmp_thr_start, tmp_thr_end;
296
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)
302         return 1;
303     }
304   return 0;
305 }