1 /* TID parsing for GDB, the GNU debugger. 2 3 Copyright (C) 2015-2017 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 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 return *m_cur_tok == '\0'; 143 case STATE_THREAD_RANGE: 144 case STATE_STAR_RANGE: 145 return m_range_parser.finished (); 146 } 147 148 gdb_assert_not_reached (_("unhandled state")); 149 } 150 151 /* See tid-parse.h. */ 152 153 const char * 154 tid_range_parser::cur_tok () const 155 { 156 switch (m_state) 157 { 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 (); 163 } 164 165 gdb_assert_not_reached (_("unhandled state")); 166 } 167 168 void 169 tid_range_parser::skip_range () 170 { 171 gdb_assert (m_state == STATE_THREAD_RANGE 172 || m_state == STATE_STAR_RANGE); 173 174 m_range_parser.skip_range (); 175 init (m_range_parser.cur_tok (), m_default_inferior); 176 } 177 178 /* See tid-parse.h. */ 179 180 bool 181 tid_range_parser::tid_is_qualified () const 182 { 183 return m_qualified; 184 } 185 186 /* Helper for tid_range_parser::get_tid and 187 tid_range_parser::get_tid_range. Return the next range if THR_END 188 is non-NULL, return a single thread ID otherwise. */ 189 190 bool 191 tid_range_parser::get_tid_or_range (int *inf_num, 192 int *thr_start, int *thr_end) 193 { 194 if (m_state == STATE_INFERIOR) 195 { 196 const char *p; 197 const char *space; 198 199 space = skip_to_space (m_cur_tok); 200 201 p = m_cur_tok; 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. */ 209 p = m_cur_tok; 210 m_inf_num = get_positive_number_trailer (&p, '.', m_cur_tok); 211 if (m_inf_num == 0) 212 return 0; 213 214 m_qualified = true; 215 p = dot + 1; 216 217 if (isspace (*p)) 218 return false; 219 } 220 else 221 { 222 m_inf_num = m_default_inferior; 223 m_qualified = false; 224 p = m_cur_tok; 225 } 226 227 m_range_parser.init (p); 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. */ 232 m_range_parser.setup_range (1, INT_MAX, skip_spaces_const (p + 1)); 233 m_state = STATE_STAR_RANGE; 234 } 235 else 236 m_state = STATE_THREAD_RANGE; 237 } 238 239 *inf_num = m_inf_num; 240 *thr_start = m_range_parser.get_number (); 241 if (*thr_start < 0) 242 error (_("negative value: %s"), m_cur_tok); 243 if (*thr_start == 0) 244 { 245 m_state = STATE_INFERIOR; 246 return false; 247 } 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. */ 252 if (!m_range_parser.in_range ()) 253 { 254 m_state = STATE_INFERIOR; 255 m_cur_tok = m_range_parser.cur_tok (); 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. */ 263 if (thr_end != NULL 264 && (m_state == STATE_THREAD_RANGE 265 || m_state == STATE_STAR_RANGE)) 266 { 267 *thr_end = m_range_parser.end_value (); 268 269 skip_range (); 270 } 271 272 return (*inf_num != 0 && *thr_start != 0); 273 } 274 275 /* See tid-parse.h. */ 276 277 bool 278 tid_range_parser::get_tid_range (int *inf_num, 279 int *thr_start, int *thr_end) 280 { 281 gdb_assert (inf_num != NULL && thr_start != NULL && thr_end != NULL); 282 283 return get_tid_or_range (inf_num, thr_start, thr_end); 284 } 285 286 /* See tid-parse.h. */ 287 288 bool 289 tid_range_parser::get_tid (int *inf_num, int *thr_num) 290 { 291 gdb_assert (inf_num != NULL && thr_num != NULL); 292 293 return get_tid_or_range (inf_num, thr_num, NULL); 294 } 295 296 /* See tid-parse.h. */ 297 298 bool 299 tid_range_parser::in_star_range () const 300 { 301 return m_state == STATE_STAR_RANGE; 302 } 303 304 /* See gdbthread.h. */ 305 306 int 307 tid_is_in_list (const char *list, int default_inferior, 308 int inf_num, int thr_num) 309 { 310 if (list == NULL || *list == '\0') 311 return 1; 312 313 tid_range_parser parser (list, default_inferior); 314 while (!parser.finished ()) 315 { 316 int tmp_inf, tmp_thr_start, tmp_thr_end; 317 318 if (!parser.get_tid_range (&tmp_inf, &tmp_thr_start, &tmp_thr_end)) 319 invalid_thread_id_error (parser.cur_tok ()); 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 } 326