tid-parse.c 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339
  1. /* TID parsing for GDB, the GNU debugger.
  2. Copyright (C) 2015-2022 Free Software Foundation, Inc.
  3. This file is part of GDB.
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 3 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program. If not, see <http://www.gnu.org/licenses/>. */
  14. #include "defs.h"
  15. #include "tid-parse.h"
  16. #include "inferior.h"
  17. #include "gdbthread.h"
  18. #include <ctype.h>
  19. /* See tid-parse.h. */
  20. void ATTRIBUTE_NORETURN
  21. invalid_thread_id_error (const char *string)
  22. {
  23. error (_("Invalid thread ID: %s"), string);
  24. }
  25. /* Wrapper for get_number_trailer that throws an error if we get back
  26. a negative number. We'll see a negative value if the number is
  27. stored in a negative convenience variable (e.g., $minus_one = -1).
  28. STRING is the parser string to be used in the error message if we
  29. do get back a negative number. */
  30. static int
  31. get_positive_number_trailer (const char **pp, int trailer, const char *string)
  32. {
  33. int num;
  34. num = get_number_trailer (pp, trailer);
  35. if (num < 0)
  36. error (_("negative value: %s"), string);
  37. return num;
  38. }
  39. /* See tid-parse.h. */
  40. struct thread_info *
  41. parse_thread_id (const char *tidstr, const char **end)
  42. {
  43. const char *number = tidstr;
  44. const char *dot, *p1;
  45. struct inferior *inf;
  46. int thr_num;
  47. int explicit_inf_id = 0;
  48. dot = strchr (number, '.');
  49. if (dot != NULL)
  50. {
  51. /* Parse number to the left of the dot. */
  52. int inf_num;
  53. p1 = number;
  54. inf_num = get_positive_number_trailer (&p1, '.', number);
  55. if (inf_num == 0)
  56. invalid_thread_id_error (number);
  57. inf = find_inferior_id (inf_num);
  58. if (inf == NULL)
  59. error (_("No inferior number '%d'"), inf_num);
  60. explicit_inf_id = 1;
  61. p1 = dot + 1;
  62. }
  63. else
  64. {
  65. inf = current_inferior ();
  66. p1 = number;
  67. }
  68. thr_num = get_positive_number_trailer (&p1, 0, number);
  69. if (thr_num == 0)
  70. invalid_thread_id_error (number);
  71. thread_info *tp = nullptr;
  72. for (thread_info *it : inf->threads ())
  73. if (it->per_inf_num == thr_num)
  74. {
  75. tp = it;
  76. break;
  77. }
  78. if (tp == NULL)
  79. {
  80. if (show_inferior_qualified_tids () || explicit_inf_id)
  81. error (_("Unknown thread %d.%d."), inf->num, thr_num);
  82. else
  83. error (_("Unknown thread %d."), thr_num);
  84. }
  85. if (end != NULL)
  86. *end = p1;
  87. return tp;
  88. }
  89. /* See tid-parse.h. */
  90. tid_range_parser::tid_range_parser (const char *tidlist,
  91. int default_inferior)
  92. {
  93. init (tidlist, default_inferior);
  94. }
  95. /* See tid-parse.h. */
  96. void
  97. tid_range_parser::init (const char *tidlist, int default_inferior)
  98. {
  99. m_state = STATE_INFERIOR;
  100. m_cur_tok = tidlist;
  101. m_inf_num = 0;
  102. m_qualified = false;
  103. m_default_inferior = default_inferior;
  104. }
  105. /* See tid-parse.h. */
  106. bool
  107. tid_range_parser::finished () const
  108. {
  109. switch (m_state)
  110. {
  111. case STATE_INFERIOR:
  112. /* Parsing is finished when at end of string or null string,
  113. or we are not in a range and not in front of an integer, negative
  114. integer, convenience var or negative convenience var. */
  115. return (*m_cur_tok == '\0'
  116. || !(isdigit (*m_cur_tok)
  117. || *m_cur_tok == '$'
  118. || *m_cur_tok == '*'));
  119. case STATE_THREAD_RANGE:
  120. case STATE_STAR_RANGE:
  121. return m_range_parser.finished ();
  122. }
  123. gdb_assert_not_reached ("unhandled state");
  124. }
  125. /* See tid-parse.h. */
  126. const char *
  127. tid_range_parser::cur_tok () const
  128. {
  129. switch (m_state)
  130. {
  131. case STATE_INFERIOR:
  132. return m_cur_tok;
  133. case STATE_THREAD_RANGE:
  134. case STATE_STAR_RANGE:
  135. return m_range_parser.cur_tok ();
  136. }
  137. gdb_assert_not_reached ("unhandled state");
  138. }
  139. void
  140. tid_range_parser::skip_range ()
  141. {
  142. gdb_assert (m_state == STATE_THREAD_RANGE
  143. || m_state == STATE_STAR_RANGE);
  144. m_range_parser.skip_range ();
  145. init (m_range_parser.cur_tok (), m_default_inferior);
  146. }
  147. /* See tid-parse.h. */
  148. bool
  149. tid_range_parser::tid_is_qualified () const
  150. {
  151. return m_qualified;
  152. }
  153. /* Helper for tid_range_parser::get_tid and
  154. tid_range_parser::get_tid_range. Return the next range if THR_END
  155. is non-NULL, return a single thread ID otherwise. */
  156. bool
  157. tid_range_parser::get_tid_or_range (int *inf_num,
  158. int *thr_start, int *thr_end)
  159. {
  160. if (m_state == STATE_INFERIOR)
  161. {
  162. const char *p;
  163. const char *space;
  164. space = skip_to_space (m_cur_tok);
  165. p = m_cur_tok;
  166. while (p < space && *p != '.')
  167. p++;
  168. if (p < space)
  169. {
  170. const char *dot = p;
  171. /* Parse number to the left of the dot. */
  172. p = m_cur_tok;
  173. m_inf_num = get_positive_number_trailer (&p, '.', m_cur_tok);
  174. if (m_inf_num == 0)
  175. return 0;
  176. m_qualified = true;
  177. p = dot + 1;
  178. if (isspace (*p))
  179. return false;
  180. }
  181. else
  182. {
  183. m_inf_num = m_default_inferior;
  184. m_qualified = false;
  185. p = m_cur_tok;
  186. }
  187. m_range_parser.init (p);
  188. if (p[0] == '*' && (p[1] == '\0' || isspace (p[1])))
  189. {
  190. /* Setup the number range parser to return numbers in the
  191. whole [1,INT_MAX] range. */
  192. m_range_parser.setup_range (1, INT_MAX, skip_spaces (p + 1));
  193. m_state = STATE_STAR_RANGE;
  194. }
  195. else
  196. m_state = STATE_THREAD_RANGE;
  197. }
  198. *inf_num = m_inf_num;
  199. *thr_start = m_range_parser.get_number ();
  200. if (*thr_start < 0)
  201. error (_("negative value: %s"), m_cur_tok);
  202. if (*thr_start == 0)
  203. {
  204. m_state = STATE_INFERIOR;
  205. return false;
  206. }
  207. /* If we successfully parsed a thread number or finished parsing a
  208. thread range, switch back to assuming the next TID is
  209. inferior-qualified. */
  210. if (!m_range_parser.in_range ())
  211. {
  212. m_state = STATE_INFERIOR;
  213. m_cur_tok = m_range_parser.cur_tok ();
  214. if (thr_end != NULL)
  215. *thr_end = *thr_start;
  216. }
  217. /* If we're midway through a range, and the caller wants the end
  218. value, return it and skip to the end of the range. */
  219. if (thr_end != NULL
  220. && (m_state == STATE_THREAD_RANGE
  221. || m_state == STATE_STAR_RANGE))
  222. {
  223. *thr_end = m_range_parser.end_value ();
  224. skip_range ();
  225. }
  226. return (*inf_num != 0 && *thr_start != 0);
  227. }
  228. /* See tid-parse.h. */
  229. bool
  230. tid_range_parser::get_tid_range (int *inf_num,
  231. int *thr_start, int *thr_end)
  232. {
  233. gdb_assert (inf_num != NULL && thr_start != NULL && thr_end != NULL);
  234. return get_tid_or_range (inf_num, thr_start, thr_end);
  235. }
  236. /* See tid-parse.h. */
  237. bool
  238. tid_range_parser::get_tid (int *inf_num, int *thr_num)
  239. {
  240. gdb_assert (inf_num != NULL && thr_num != NULL);
  241. return get_tid_or_range (inf_num, thr_num, NULL);
  242. }
  243. /* See tid-parse.h. */
  244. bool
  245. tid_range_parser::in_star_range () const
  246. {
  247. return m_state == STATE_STAR_RANGE;
  248. }
  249. bool
  250. tid_range_parser::in_thread_range () const
  251. {
  252. return m_state == STATE_THREAD_RANGE;
  253. }
  254. /* See tid-parse.h. */
  255. int
  256. tid_is_in_list (const char *list, int default_inferior,
  257. int inf_num, int thr_num)
  258. {
  259. if (list == NULL || *list == '\0')
  260. return 1;
  261. tid_range_parser parser (list, default_inferior);
  262. if (parser.finished ())
  263. invalid_thread_id_error (parser.cur_tok ());
  264. while (!parser.finished ())
  265. {
  266. int tmp_inf, tmp_thr_start, tmp_thr_end;
  267. if (!parser.get_tid_range (&tmp_inf, &tmp_thr_start, &tmp_thr_end))
  268. invalid_thread_id_error (parser.cur_tok ());
  269. if (tmp_inf == inf_num
  270. && tmp_thr_start <= thr_num && thr_num <= tmp_thr_end)
  271. return 1;
  272. }
  273. return 0;
  274. }