gdb/djgpp: Add Hygon Dhyana processor support
[external/binutils.git] / gdb / tid-parse.c
1 /* TID parsing for GDB, the GNU debugger.
2
3    Copyright (C) 2015-2019 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 inferior *inf;
59   int thr_num;
60   int explicit_inf_id = 0;
61
62   dot = strchr (number, '.');
63
64   if (dot != NULL)
65     {
66       /* Parse number to the left of the dot.  */
67       int inf_num;
68
69       p1 = number;
70       inf_num = get_positive_number_trailer (&p1, '.', number);
71       if (inf_num == 0)
72         invalid_thread_id_error (number);
73
74       inf = find_inferior_id (inf_num);
75       if (inf == NULL)
76         error (_("No inferior number '%d'"), inf_num);
77
78       explicit_inf_id = 1;
79       p1 = dot + 1;
80     }
81   else
82     {
83       inf = current_inferior ();
84
85       p1 = number;
86     }
87
88   thr_num = get_positive_number_trailer (&p1, 0, number);
89   if (thr_num == 0)
90     invalid_thread_id_error (number);
91
92   thread_info *tp = nullptr;
93   for (thread_info *it : inf->threads ())
94     if (it->per_inf_num == thr_num)
95       {
96         tp = it;
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 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
124 void
125 tid_range_parser::init (const char *tidlist, int default_inferior)
126 {
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;
132 }
133
134 /* See tid-parse.h.  */
135
136 bool
137 tid_range_parser::finished () const
138 {
139   switch (m_state)
140     {
141     case STATE_INFERIOR:
142       /* Parsing is finished when at end of string or null string,
143          or we are not in a range and not in front of an integer, negative
144          integer, convenience var or negative convenience var.  */
145       return (*m_cur_tok == '\0'
146               || !(isdigit (*m_cur_tok)
147                    || *m_cur_tok == '$'
148                    || *m_cur_tok == '*'));
149     case STATE_THREAD_RANGE:
150     case STATE_STAR_RANGE:
151       return m_range_parser.finished ();
152     }
153
154   gdb_assert_not_reached (_("unhandled state"));
155 }
156
157 /* See tid-parse.h.  */
158
159 const char *
160 tid_range_parser::cur_tok () const
161 {
162   switch (m_state)
163     {
164     case STATE_INFERIOR:
165       return m_cur_tok;
166     case STATE_THREAD_RANGE:
167     case STATE_STAR_RANGE:
168       return m_range_parser.cur_tok ();
169     }
170
171   gdb_assert_not_reached (_("unhandled state"));
172 }
173
174 void
175 tid_range_parser::skip_range ()
176 {
177   gdb_assert (m_state == STATE_THREAD_RANGE
178               || m_state == STATE_STAR_RANGE);
179
180   m_range_parser.skip_range ();
181   init (m_range_parser.cur_tok (), m_default_inferior);
182 }
183
184 /* See tid-parse.h.  */
185
186 bool
187 tid_range_parser::tid_is_qualified () const
188 {
189   return m_qualified;
190 }
191
192 /* Helper for tid_range_parser::get_tid and
193    tid_range_parser::get_tid_range.  Return the next range if THR_END
194    is non-NULL, return a single thread ID otherwise.  */
195
196 bool
197 tid_range_parser::get_tid_or_range (int *inf_num,
198                                     int *thr_start, int *thr_end)
199 {
200   if (m_state == STATE_INFERIOR)
201     {
202       const char *p;
203       const char *space;
204
205       space = skip_to_space (m_cur_tok);
206
207       p = m_cur_tok;
208       while (p < space && *p != '.')
209         p++;
210       if (p < space)
211         {
212           const char *dot = p;
213
214           /* Parse number to the left of the dot.  */
215           p = m_cur_tok;
216           m_inf_num = get_positive_number_trailer (&p, '.', m_cur_tok);
217           if (m_inf_num == 0)
218             return 0;
219
220           m_qualified = true;
221           p = dot + 1;
222
223           if (isspace (*p))
224             return false;
225         }
226       else
227         {
228           m_inf_num = m_default_inferior;
229           m_qualified = false;
230           p = m_cur_tok;
231         }
232
233       m_range_parser.init (p);
234       if (p[0] == '*' && (p[1] == '\0' || isspace (p[1])))
235         {
236           /* Setup the number range parser to return numbers in the
237              whole [1,INT_MAX] range.  */
238           m_range_parser.setup_range (1, INT_MAX, skip_spaces (p + 1));
239           m_state = STATE_STAR_RANGE;
240         }
241       else
242         m_state = STATE_THREAD_RANGE;
243     }
244
245   *inf_num = m_inf_num;
246   *thr_start = m_range_parser.get_number ();
247   if (*thr_start < 0)
248     error (_("negative value: %s"), m_cur_tok);
249   if (*thr_start == 0)
250     {
251       m_state = STATE_INFERIOR;
252       return false;
253     }
254
255   /* If we successfully parsed a thread number or finished parsing a
256      thread range, switch back to assuming the next TID is
257      inferior-qualified.  */
258   if (!m_range_parser.in_range ())
259     {
260       m_state = STATE_INFERIOR;
261       m_cur_tok = m_range_parser.cur_tok ();
262
263       if (thr_end != NULL)
264         *thr_end = *thr_start;
265     }
266
267   /* If we're midway through a range, and the caller wants the end
268      value, return it and skip to the end of the range.  */
269   if (thr_end != NULL
270       && (m_state == STATE_THREAD_RANGE
271           || m_state == STATE_STAR_RANGE))
272     {
273       *thr_end = m_range_parser.end_value ();
274
275       skip_range ();
276     }
277
278   return (*inf_num != 0 && *thr_start != 0);
279 }
280
281 /* See tid-parse.h.  */
282
283 bool
284 tid_range_parser::get_tid_range (int *inf_num,
285                                  int *thr_start, int *thr_end)
286 {
287   gdb_assert (inf_num != NULL && thr_start != NULL && thr_end != NULL);
288
289   return get_tid_or_range (inf_num, thr_start, thr_end);
290 }
291
292 /* See tid-parse.h.  */
293
294 bool
295 tid_range_parser::get_tid (int *inf_num, int *thr_num)
296 {
297   gdb_assert (inf_num != NULL && thr_num != NULL);
298
299   return get_tid_or_range (inf_num, thr_num, NULL);
300 }
301
302 /* See tid-parse.h.  */
303
304 bool
305 tid_range_parser::in_star_range () const
306 {
307   return m_state == STATE_STAR_RANGE;
308 }
309
310 bool
311 tid_range_parser::in_thread_range () const
312 {
313   return m_state == STATE_THREAD_RANGE;
314 }
315
316 /* See tid-parse.h.  */
317
318 int
319 tid_is_in_list (const char *list, int default_inferior,
320                 int inf_num, int thr_num)
321 {
322   if (list == NULL || *list == '\0')
323     return 1;
324
325   tid_range_parser parser (list, default_inferior);
326   if (parser.finished ())
327     invalid_thread_id_error (parser.cur_tok ());
328   while (!parser.finished ())
329     {
330       int tmp_inf, tmp_thr_start, tmp_thr_end;
331
332       if (!parser.get_tid_range (&tmp_inf, &tmp_thr_start, &tmp_thr_end))
333         invalid_thread_id_error (parser.cur_tok ());
334       if (tmp_inf == inf_num
335           && tmp_thr_start <= thr_num && thr_num <= tmp_thr_end)
336         return 1;
337     }
338   return 0;
339 }