aboutsummaryrefslogtreecommitdiff
path: root/gdb/tid-parse.c
diff options
context:
space:
mode:
Diffstat (limited to 'gdb/tid-parse.c')
-rw-r--r--gdb/tid-parse.c282
1 files changed, 282 insertions, 0 deletions
diff --git a/gdb/tid-parse.c b/gdb/tid-parse.c
new file mode 100644
index 0000000..21b872d
--- /dev/null
+++ b/gdb/tid-parse.c
@@ -0,0 +1,282 @@
+/* TID parsing for GDB, the GNU debugger.
+
+ Copyright (C) 2015-2016 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "defs.h"
+#include "tid-parse.h"
+#include "inferior.h"
+#include "gdbthread.h"
+#include <ctype.h>
+
+/* See tid-parse.h. */
+
+void ATTRIBUTE_NORETURN
+invalid_thread_id_error (const char *string)
+{
+ error (_("Invalid thread ID: %s"), string);
+}
+
+/* See tid-parse.h. */
+
+struct thread_info *
+parse_thread_id (const char *tidstr, const char **end)
+{
+ const char *number = tidstr;
+ const char *dot, *p1;
+ struct thread_info *tp;
+ struct inferior *inf;
+ int thr_num;
+ int explicit_inf_id = 0;
+
+ dot = strchr (number, '.');
+
+ if (dot != NULL)
+ {
+ /* Parse number to the left of the dot. */
+ int inf_num;
+
+ p1 = number;
+ inf_num = get_number_trailer (&p1, '.');
+ if (inf_num == 0)
+ invalid_thread_id_error (number);
+
+ inf = find_inferior_id (inf_num);
+ if (inf == NULL)
+ error (_("No inferior number '%d'"), inf_num);
+
+ explicit_inf_id = 1;
+ p1 = dot + 1;
+ }
+ else
+ {
+ inf = current_inferior ();
+
+ p1 = number;
+ }
+
+ thr_num = get_number_const (&p1);
+ if (thr_num == 0)
+ invalid_thread_id_error (number);
+
+ ALL_THREADS (tp)
+ {
+ if (ptid_get_pid (tp->ptid) == inf->pid
+ && tp->per_inf_num == thr_num)
+ break;
+ }
+
+ if (tp == NULL)
+ {
+ if (show_inferior_qualified_tids () || explicit_inf_id)
+ error (_("Unknown thread %d.%d."), inf->num, thr_num);
+ else
+ error (_("Unknown thread %d."), thr_num);
+ }
+
+ if (end != NULL)
+ *end = p1;
+
+ return tp;
+}
+
+/* See tid-parse.h. */
+
+void
+tid_range_parser_init (struct tid_range_parser *parser, const char *tidlist,
+ int default_inferior)
+{
+ parser->state = TID_RANGE_STATE_INFERIOR;
+ parser->string = tidlist;
+ parser->inf_num = 0;
+ parser->qualified = 0;
+ parser->default_inferior = default_inferior;
+}
+
+/* See tid-parse.h. */
+
+int
+tid_range_parser_finished (struct tid_range_parser *parser)
+{
+ switch (parser->state)
+ {
+ case TID_RANGE_STATE_INFERIOR:
+ return *parser->string == '\0';
+ case TID_RANGE_STATE_THREAD_RANGE:
+ return parser->range_parser.finished;
+ }
+
+ gdb_assert_not_reached (_("unhandled state"));
+}
+
+/* See tid-parse.h. */
+
+const char *
+tid_range_parser_string (struct tid_range_parser *parser)
+{
+ switch (parser->state)
+ {
+ case TID_RANGE_STATE_INFERIOR:
+ return parser->string;
+ case TID_RANGE_STATE_THREAD_RANGE:
+ return parser->range_parser.string;
+ }
+
+ gdb_assert_not_reached (_("unhandled state"));
+}
+
+/* See tid-parse.h. */
+
+void
+tid_range_parser_skip (struct tid_range_parser *parser)
+{
+ gdb_assert ((parser->state == TID_RANGE_STATE_THREAD_RANGE)
+ && parser->range_parser.in_range);
+
+ tid_range_parser_init (parser, parser->range_parser.end_ptr,
+ parser->default_inferior);
+}
+
+/* See tid-parse.h. */
+
+int
+tid_range_parser_qualified (struct tid_range_parser *parser)
+{
+ return parser->qualified;
+}
+
+/* Helper for tid_range_parser_get_tid and
+ tid_range_parser_get_tid_range. Return the next range if THR_END
+ is non-NULL, return a single thread ID otherwise. */
+
+static int
+get_tid_or_range (struct tid_range_parser *parser, int *inf_num,
+ int *thr_start, int *thr_end)
+{
+ if (parser->state == TID_RANGE_STATE_INFERIOR)
+ {
+ const char *p;
+ const char *space;
+
+ space = skip_to_space (parser->string);
+
+ p = parser->string;
+ while (p < space && *p != '.')
+ p++;
+ if (p < space)
+ {
+ const char *dot = p;
+
+ /* Parse number to the left of the dot. */
+ p = parser->string;
+ parser->inf_num = get_number_trailer (&p, '.');
+ if (parser->inf_num == 0)
+ invalid_thread_id_error (parser->string);
+
+ parser->qualified = 1;
+ p = dot + 1;
+
+ if (isspace (*p))
+ invalid_thread_id_error (parser->string);
+ }
+ else
+ {
+ parser->inf_num = parser->default_inferior;
+ parser->qualified = 0;
+ p = parser->string;
+ }
+
+ init_number_or_range (&parser->range_parser, p);
+ parser->state = TID_RANGE_STATE_THREAD_RANGE;
+ }
+
+ *inf_num = parser->inf_num;
+ *thr_start = get_number_or_range (&parser->range_parser);
+ if (*thr_start == 0)
+ invalid_thread_id_error (parser->string);
+
+ /* If we successfully parsed a thread number or finished parsing a
+ thread range, switch back to assuming the next TID is
+ inferior-qualified. */
+ if (parser->range_parser.end_ptr == NULL
+ || parser->range_parser.string == parser->range_parser.end_ptr)
+ {
+ parser->state = TID_RANGE_STATE_INFERIOR;
+ parser->string = parser->range_parser.string;
+
+ if (thr_end != NULL)
+ *thr_end = *thr_start;
+ }
+
+ /* If we're midway through a range, and the caller wants the end
+ value, return it and skip to the end of the range. */
+ if (thr_end != NULL && parser->state == TID_RANGE_STATE_THREAD_RANGE)
+ {
+ *thr_end = parser->range_parser.end_value;
+ tid_range_parser_skip (parser);
+ }
+
+ return (*inf_num != 0 && *thr_start != 0);
+}
+
+/* See tid-parse.h. */
+
+int
+tid_range_parser_get_tid_range (struct tid_range_parser *parser, int *inf_num,
+ int *thr_start, int *thr_end)
+{
+ gdb_assert (inf_num != NULL && thr_start != NULL && thr_end != NULL);
+
+ return get_tid_or_range (parser, inf_num, thr_start, thr_end);
+}
+
+/* See tid-parse.h. */
+
+int
+tid_range_parser_get_tid (struct tid_range_parser *parser,
+ int *inf_num, int *thr_num)
+{
+ gdb_assert (inf_num != NULL && thr_num != NULL);
+
+ return get_tid_or_range (parser, inf_num, thr_num, NULL);
+}
+
+/* See tid-parse.h. */
+
+int
+tid_is_in_list (const char *list, int default_inferior,
+ int inf_num, int thr_num)
+{
+ struct tid_range_parser parser;
+
+ if (list == NULL || *list == '\0')
+ return 1;
+
+ tid_range_parser_init (&parser, list, default_inferior);
+ while (!tid_range_parser_finished (&parser))
+ {
+ int tmp_inf, tmp_thr_start, tmp_thr_end;
+
+ if (!tid_range_parser_get_tid_range (&parser, &tmp_inf,
+ &tmp_thr_start, &tmp_thr_end))
+ invalid_thread_id_error (parser.string);
+ if (tmp_inf == inf_num
+ && tmp_thr_start <= thr_num && thr_num <= tmp_thr_end)
+ return 1;
+ }
+ return 0;
+}