Star wildcard ranges (e.g., "info thread 2.*")
authorPedro Alves <palves@redhat.com>
Fri, 15 Jan 2016 21:46:23 +0000 (21:46 +0000)
committerPedro Alves <palves@redhat.com>
Fri, 15 Jan 2016 21:46:23 +0000 (21:46 +0000)
Add support for specifying "all threads of inferior N", by writing "*"
as thread number/range in thread ID lists.

E.g., "info threads 2.*" or "thread apply 2.* bt".

gdb/ChangeLog:
2016-01-15  Pedro Alves  <palves@redhat.com>

* NEWS: Mention star wildcard ranges.
* cli/cli-utils.c (get_number_or_range): Check state->in_range first.
(number_range_setup_range): New function.
* cli/cli-utils.h (number_range_setup_range): New declaration.
* thread.c (thread_apply_command): Support star TID ranges.
* tid-parse.c (tid_range_parser_finished)
(tid_range_parser_string, tid_range_parser_skip)
(get_tid_or_range, get_tid_or_range): Handle
TID_RANGE_STATE_STAR_RANGE.
(tid_range_parser_star_range): New function.
* tid-parse.h (enum tid_range_state) <TID_RANGE_STATE_STAR_RANGE>:
New value.
(tid_range_parser_star_range): New declaration.

gdb/doc/ChangeLog:
2016-01-15  Pedro Alves  <palves@redhat.com>

* gdb.texinfo (Threads) <thread ID lists>: Document star ranges.

gdb/testsuite/ChangeLog:
2016-01-15  Pedro Alves  <palves@redhat.com>

* gdb.multi/tids.exp: Test star wildcard ranges.

gdb/ChangeLog
gdb/NEWS
gdb/cli/cli-utils.c
gdb/cli/cli-utils.h
gdb/doc/ChangeLog
gdb/doc/gdb.texinfo
gdb/testsuite/ChangeLog
gdb/testsuite/gdb.multi/tids.exp
gdb/thread.c
gdb/tid-parse.c
gdb/tid-parse.h

index 99245d70a884c6e9ce86f72f282dfe94be47f2a8..034e4f9d29bba88edbee6d58394ebcdeb42814cf 100644 (file)
@@ -1,3 +1,19 @@
+2016-01-15  Pedro Alves  <palves@redhat.com>
+
+       * NEWS: Mention star wildcard ranges.
+       * cli/cli-utils.c (get_number_or_range): Check state->in_range first.
+       (number_range_setup_range): New function.
+       * cli/cli-utils.h (number_range_setup_range): New declaration.
+       * thread.c (thread_apply_command): Support star TID ranges.
+       * tid-parse.c (tid_range_parser_finished)
+       (tid_range_parser_string, tid_range_parser_skip)
+       (get_tid_or_range, get_tid_or_range): Handle
+       TID_RANGE_STATE_STAR_RANGE.
+       (tid_range_parser_star_range): New function.
+       * tid-parse.h (enum tid_range_state) <TID_RANGE_STATE_STAR_RANGE>:
+       New value.
+       (tid_range_parser_star_range): New declaration.
+
 2016-01-15  Pedro Alves  <palves@redhat.com>
 
        * thread.c (thread_apply_command): Use the tid range parser to
index d9cbb8006462329bfd7242f5d476cdbbcdac1cc6..9d3a47ccb30d1c222ba1a235e04d93b907f4b418 100644 (file)
--- a/gdb/NEWS
+++ b/gdb/NEWS
      [Switching to thread 2.1 (Thread 0x7ffff7fc2740 (LWP 8157))] (running)
      (gdb)
 
+* In commands that accept a list of thread IDs, you can now refer to
+  all threads of an inferior using a star wildcard.  GDB accepts
+  "INF_NUM.*", to refer to all threads of inferior INF_NUM, and "*" to
+  refer to all threads of the current inferior.  For example, "info
+  threads 2.*".
+
 * You can use "info threads -gid" to display the global thread ID of
   all threads.
 
index a68b67d5ffbf9430bf6459f248b705055fcf6051..0946db06c49f0e45f27142855009706a10b678fc 100644 (file)
@@ -134,7 +134,21 @@ init_number_or_range (struct get_number_or_range_state *state,
 int
 get_number_or_range (struct get_number_or_range_state *state)
 {
-  if (*state->string != '-')
+  if (state->in_range)
+    {
+      /* All number-parsing has already been done.  Return the next
+        integer value (one greater than the saved previous value).
+        Do not advance the token pointer until the end of range is
+        reached.  */
+
+      if (++state->last_retval == state->end_value)
+       {
+         /* End of range reached; advance token pointer.  */
+         state->string = state->end_ptr;
+         state->in_range = 0;
+       }
+    }
+  else if (*state->string != '-')
     {
       /* Default case: state->string is pointing either to a solo
         number, or to the first number of a range.  */
@@ -165,27 +179,26 @@ get_number_or_range (struct get_number_or_range_state *state)
            state->in_range = 1;
        }
     }
-  else if (! state->in_range)
-    error (_("negative value"));
   else
-    {
-      /* state->string points to the '-' that betokens a range.  All
-        number-parsing has already been done.  Return the next
-        integer value (one greater than the saved previous value).
-        Do not advance the token pointer until the end of range
-        is reached.  */
-
-      if (++state->last_retval == state->end_value)
-       {
-         /* End of range reached; advance token pointer.  */
-         state->string = state->end_ptr;
-         state->in_range = 0;
-       }
-    }
+    error (_("negative value"));
   state->finished = *state->string == '\0';
   return state->last_retval;
 }
 
+/* See documentation in cli-utils.h.  */
+
+void
+number_range_setup_range (struct get_number_or_range_state *state,
+                         int start_value, int end_value, const char *end_ptr)
+{
+  gdb_assert (start_value > 0);
+
+  state->in_range = 1;
+  state->end_ptr = end_ptr;
+  state->last_retval = start_value - 1;
+  state->end_value = end_value;
+}
+
 /* Accept a number and a string-form list of numbers such as is 
    accepted by get_number_or_range.  Return TRUE if the number is
    in the list.
index ebf11f28b952aaf0f3fee21f94a5430e62a1d4df..a31fff539697b690d74f2c90319b5b3e867a9e3c 100644 (file)
@@ -90,6 +90,14 @@ extern void init_number_or_range (struct get_number_or_range_state *state,
 
 extern int get_number_or_range (struct get_number_or_range_state *state);
 
+/* Setups STATE such that get_number_or_range returns numbers in range
+   START_VALUE to END_VALUE.  When get_number_or_range returns
+   END_VALUE, the STATE string is advanced to END_PTR.  */
+
+extern void number_range_setup_range (struct get_number_or_range_state *state,
+                                     int start_value, int end_value,
+                                     const char *end_ptr);
+
 /* Accept a number and a string-form list of numbers such as is 
    accepted by get_number_or_range.  Return TRUE if the number is
    in the list.
index 4b59057eeb8e80c859cab94ee74ea7dacdb7a55e..db280b960d091c06b1697de6a07ef176bde92028 100644 (file)
@@ -1,3 +1,7 @@
+2016-01-15  Pedro Alves  <palves@redhat.com>
+
+       * gdb.texinfo (Threads) <thread ID lists>: Document star ranges.
+
 2016-01-13  Pedro Alves  <palves@redhat.com>
 
        * gdb.texinfo (Threads): Document the $_gthread convenience
index 7da31c84c535a687c738419c9c92e169a429f10c..a08a196409dad0e044b282652a660d0615485650 100644 (file)
@@ -2912,16 +2912,35 @@ of inferior 1, the initial inferior.
 @anchor{thread ID lists}
 @cindex thread ID lists
 Some commands accept a space-separated @dfn{thread ID list} as
-argument.  A list element can be a thread ID as shown in the first
-field of the @samp{info threads} display, with or without an inferior
-qualifier (e.g., @samp{2.1} or @samp{1}); or can be a range of thread
-numbers, again with or without an inferior qualifier, as in
-@var{inf1}.@var{thr1}-@var{thr2} or @var{thr1}-@var{thr2} (e.g.,
-@samp{1.2-4} or @samp{2-4}).  For example, if the current inferior is
-1, the thread list @samp{1 2-3 4.5 6.7-9} includes threads 1 to 3 of
-inferior 1, thread 5 of inferior 4 and threads 7 to 9 of inferior 6.
-That is, in expanded qualified form, the same as @samp{1.1 1.2 1.3 4.5
-6.7 6.8 6.9}.
+argument.  A list element can be:
+
+@enumerate
+@item
+A thread ID as shown in the first field of the @samp{info threads}
+display, with or without an inferior qualifier.  E.g., @samp{2.1} or
+@samp{1}.
+
+@item
+A range of thread numbers, again with or without an inferior
+qualifier, as in @var{inf}.@var{thr1}-@var{thr2} or
+@var{thr1}-@var{thr2}.  E.g., @samp{1.2-4} or @samp{2-4}.
+
+@item
+All threads of an inferior, specified with a star wildcard, with or
+without an inferior qualifier, as in @var{inf}.@code{*} (e.g.,
+@samp{1.*}) or @code{*}.  The former refers to all threads of the
+given inferior, and the latter form without an inferior qualifier
+refers to all threads of the current inferior.
+
+@end enumerate
+
+For example, if the current inferior is 1, and inferior 7 has one
+thread with ID 7.1, the thread list @samp{1 2-3 4.5 6.7-9 7.*}
+includes threads 1 to 3 of inferior 1, thread 5 of inferior 4, threads
+7 to 9 of inferior 6 and all threads of inferior 7.  That is, in
+expanded qualified form, the same as @samp{1.1 1.2 1.3 4.5 6.7 6.8 6.9
+7.1}.
+
 
 @anchor{global thread numbers}
 @cindex global thread number
index e5e38b3b18073afbbb3ee39779de114fadff64ad..7ba90d7d64eebcd9ef596aa996aa46a8d4cb919c 100644 (file)
@@ -1,3 +1,7 @@
+2016-01-15  Pedro Alves  <palves@redhat.com>
+
+       * gdb.multi/tids.exp: Test star wildcard ranges.
+
 2016-01-15  Pedro Alves  <palves@redhat.com>
 
        * gdb.multi/tids.exp (thr_apply_info_thr_error): Remove "p 1234"
index 57632346fb7654f9eae8e491decb369ad59ec471..5d8701effb02c67ffae4d0c2762f05ff26567e07 100644 (file)
@@ -277,6 +277,36 @@ with_test_prefix "two inferiors" {
        "warning: Unknown thread 30.1" \
        "thread apply \$inf.1"
 
+    # Star ranges.
+
+    thr_apply_info_thr "1.*" \
+       "1.1 1.2 1.3"
+
+    thr_apply_info_thr "*" \
+       "1.1 1.2 1.3"
+
+    thr_apply_info_thr "1.* 2.1" \
+       "1.1 1.2 1.3 2.1"
+
+    thr_apply_info_thr "2.1 1.*" \
+       "1.1 1.2 1.3 2.1" \
+       "2.1 1.1 1.2 1.3"
+
+    thr_apply_info_thr "1.* 2.*" \
+       "1.1 1.2 1.3 2.1 2.2 2.3"
+
+    thr_apply_info_thr "2.* 1.*" \
+       "1.1 1.2 1.3 2.1 2.2 2.3" \
+       "2.1 2.2 2.3 1.1 1.2 1.3"
+
+    # There's no inferior 3, but "info threads" treats the thread list
+    # as a filter, so it's OK.  "thread apply" complains about the
+    # unknown inferior through.
+    info_threads "1.1 3.*" \
+       "1.1"
+    gdb_test "thread apply 1.1 3.* p 1" \
+       "Thread 1.1.*warning: Unknown inferior 3"
+
     # Now test a set of invalid thread IDs/ranges.
 
     thr_apply_info_thr_invalid "1." \
@@ -318,6 +348,11 @@ with_test_prefix "two inferiors" {
        thr_apply_info_thr_error "${prefix}-\$one" "negative value"
        thr_apply_info_thr_error "${prefix}\$minus_one" \
            "negative value: ${prefix_re}\\\$minus_one"
+
+       thr_apply_info_thr_error "${prefix}1-*" "inverted range"
+       thr_apply_info_thr_invalid "${prefix}*1"
+       thr_apply_info_thr_invalid "${prefix}*foo"
+       thr_apply_info_thr_invalid "${prefix}foo*"
     }
 
     # Check that a valid thread ID list with a missing command errors
@@ -330,6 +365,7 @@ with_test_prefix "two inferiors" {
        gdb_test "thread apply 1-2" $output
        gdb_test "thread apply 1.1-2" $output
        gdb_test "thread apply $thr" $output
+       gdb_test "thread apply 1.*" $output
     }
 
     # Check that we do parse the inferior number and don't confuse it.
index 56de6e1c089f3106fc43bc62b853b9223deb0c6a..c7f14674c6865f2a37d981705eca85a1f5c5e6fd 100644 (file)
@@ -1864,6 +1864,26 @@ thread_apply_command (char *tidlist, int from_tty)
       inf = find_inferior_id (inf_num);
       if (inf != NULL)
        tp = find_thread_id (inf, thr_num);
+
+      if (tid_range_parser_star_range (&parser))
+       {
+         if (inf == NULL)
+           {
+             warning (_("Unknown inferior %d"), inf_num);
+             tid_range_parser_skip (&parser);
+             continue;
+           }
+
+         /* No use looking for threads past the highest thread number
+            the inferior ever had.  */
+         if (thr_num >= inf->highest_thread_num)
+           tid_range_parser_skip (&parser);
+
+         /* Be quiet about unknown threads numbers.  */
+         if (tp == NULL)
+           continue;
+       }
+
       if (tp == NULL)
        {
          if (show_inferior_qualified_tids ()
index 45b7ff56dc2f6c8301ea329a7c085f362b3f0523..68133c6f4865b6edccaf633bc3cf2e82ccfd1dbf 100644 (file)
@@ -134,6 +134,7 @@ tid_range_parser_finished (struct tid_range_parser *parser)
     case TID_RANGE_STATE_INFERIOR:
       return *parser->string == '\0';
     case TID_RANGE_STATE_THREAD_RANGE:
+    case TID_RANGE_STATE_STAR_RANGE:
       return parser->range_parser.finished;
     }
 
@@ -150,6 +151,7 @@ tid_range_parser_string (struct tid_range_parser *parser)
     case TID_RANGE_STATE_INFERIOR:
       return parser->string;
     case TID_RANGE_STATE_THREAD_RANGE:
+    case TID_RANGE_STATE_STAR_RANGE:
       return parser->range_parser.string;
     }
 
@@ -161,7 +163,8 @@ tid_range_parser_string (struct tid_range_parser *parser)
 void
 tid_range_parser_skip (struct tid_range_parser *parser)
 {
-  gdb_assert ((parser->state == TID_RANGE_STATE_THREAD_RANGE)
+  gdb_assert ((parser->state == TID_RANGE_STATE_THREAD_RANGE
+              || parser->state == TID_RANGE_STATE_STAR_RANGE)
              && parser->range_parser.in_range);
 
   tid_range_parser_init (parser, parser->range_parser.end_ptr,
@@ -219,7 +222,16 @@ get_tid_or_range (struct tid_range_parser *parser, int *inf_num,
        }
 
       init_number_or_range (&parser->range_parser, p);
-      parser->state = TID_RANGE_STATE_THREAD_RANGE;
+      if (p[0] == '*' && (p[1] == '\0' || isspace (p[1])))
+       {
+         /* Setup the number range parser to return numbers in the
+            whole [1,INT_MAX] range.  */
+         number_range_setup_range (&parser->range_parser, 1, INT_MAX,
+                                   skip_spaces_const (p + 1));
+         parser->state = TID_RANGE_STATE_STAR_RANGE;
+       }
+      else
+       parser->state = TID_RANGE_STATE_THREAD_RANGE;
     }
 
   *inf_num = parser->inf_num;
@@ -247,7 +259,9 @@ get_tid_or_range (struct tid_range_parser *parser, int *inf_num,
 
   /* 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)
+  if (thr_end != NULL
+      && (parser->state == TID_RANGE_STATE_THREAD_RANGE
+         || parser->state == TID_RANGE_STATE_STAR_RANGE))
     {
       *thr_end = parser->range_parser.end_value;
       tid_range_parser_skip (parser);
@@ -280,6 +294,14 @@ tid_range_parser_get_tid (struct tid_range_parser *parser,
 
 /* See tid-parse.h.  */
 
+int
+tid_range_parser_star_range (struct tid_range_parser *parser)
+{
+  return parser->state == TID_RANGE_STATE_STAR_RANGE;
+}
+
+/* See gdbthread.h.  */
+
 int
 tid_is_in_list (const char *list, int default_inferior,
                int inf_num, int thr_num)
index a690edfe319b1bcac623b01ea8649c0eeea24284..830cf36a7471ddd7a769220f714a600ba6632afb 100644 (file)
@@ -44,6 +44,9 @@ enum tid_range_state
 
   /* Parsing the thread number or thread number range.  */
   TID_RANGE_STATE_THREAD_RANGE,
+
+  /* Parsing a star wildcard thread range.  E.g., "1.*".  */
+  TID_RANGE_STATE_STAR_RANGE,
 };
 
 /* An object of this type is passed to tid_range_parser_get_tid.  It
@@ -142,6 +145,10 @@ extern int tid_range_parser_get_tid_range (struct tid_range_parser *parser,
                                           int *inf_num,
                                           int *thr_start, int *thr_end);
 
+/* Returns non-zero if processing a star wildcard (e.g., "1.*")
+   range.  */
+extern int tid_range_parser_star_range (struct tid_range_parser *parser);
+
 /* Returns non-zero if parsing has completed.  */
 extern int tid_range_parser_finished (struct tid_range_parser *parser);