This is the mail archive of the gdb-cvs@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[binutils-gdb] Fix "thread apply $conv_var" and misc other related problems


https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=3f5b7598805c8253c43c989a540a2408c8b685ad

commit 3f5b7598805c8253c43c989a540a2408c8b685ad
Author: Pedro Alves <palves@redhat.com>
Date:   Fri Jan 15 21:46:22 2016 +0000

    Fix "thread apply $conv_var" and misc other related problems
    
    This fixes a few bugs in "thread apply".
    
    While this works:
    
     (gdb) thread apply 1 p 1234
    
     Thread 1 (Thread 0x7ffff7fc1740 (LWP 14048)):
     $1 = 1234
    
    This doesn't:
    
     (gdb) thread apply $thr p 1234
    
     Thread 1 (Thread 0x7ffff7fc1740 (LWP 12039)):
     Invalid thread ID: p 1234
     (gdb)
    
    ~~~~
    
    Also, while this works:
     (gdb) thread apply 1
     Please specify a command following the thread ID list
    
    This doesn't:
     (gdb) thread apply $thr
     Thread 1 (Thread 0x7ffff7fc1740 (LWP 12039)):
     [Current thread is 1 (Thread 0x7ffff7fc1740 (LWP 12039))]
     (gdb)
    
    ~~~~
    
    And, while this works:
     (gdb) thread apply
     Please specify a thread ID list
    
    This obviously bogus invocation is just silent:
     (gdb) thread apply bt
     (gdb)
    
    gdb/ChangeLog:
    2016-01-15  Pedro Alves  <palves@redhat.com>
    
    	* thread.c (thread_apply_command): Use the tid range parser to
    	advance past the thread ID list.
    	* tid-parse.c (get_positive_number_trailer): New function.
    	(parse_thread_id): Use it.
    	(get_tid_or_range): Use it.  Return 0 instead of throwing invalid
    	thread ID error.
    	(get_tid_or_range): Detect negative values.  Return 0 instead of
    	throwing invalid thread ID error.
    
    gdb/testsuite/ChangeLog:
    2016-01-15  Pedro Alves  <palves@redhat.com>
    
    	* gdb.multi/tids.exp (thr_apply_info_thr_error): Remove "p 1234"
    	command from "thread apply" invocation.
    	(thr_apply_info_thr_invalid): Default the expected output to the
    	input tid list.
    	(top level): Add tests that use convenience variables.  Add tests
    	for "thread apply" with a valid TID list, but missing the command.

Diff:
---
 gdb/ChangeLog                    |  11 ++++
 gdb/testsuite/ChangeLog          |   9 ++++
 gdb/testsuite/gdb.multi/tids.exp | 112 ++++++++++++++++++++++++++++++++++-----
 gdb/thread.c                     |  20 +++++--
 gdb/tid-parse.c                  |  35 +++++++++---
 5 files changed, 165 insertions(+), 22 deletions(-)

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index ad4049c..99245d7 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,14 @@
+2016-01-15  Pedro Alves  <palves@redhat.com>
+
+	* thread.c (thread_apply_command): Use the tid range parser to
+	advance past the thread ID list.
+	* tid-parse.c (get_positive_number_trailer): New function.
+	(parse_thread_id): Use it.
+	(get_tid_or_range): Use it.  Return 0 instead of throwing invalid
+	thread ID error.
+	(get_tid_or_range): Detect negative values.  Return 0 instead of
+	throwing invalid thread ID error.
+
 2016-01-14  Yao Qi  <yao.qi@linaro.org>
 
 	* arm-linux-tdep.c (arm_linux_get_next_pcs_syscall_next_pc):
diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog
index dcdc09c..e5e38b3 100644
--- a/gdb/testsuite/ChangeLog
+++ b/gdb/testsuite/ChangeLog
@@ -1,3 +1,12 @@
+2016-01-15  Pedro Alves  <palves@redhat.com>
+
+	* gdb.multi/tids.exp (thr_apply_info_thr_error): Remove "p 1234"
+	command from "thread apply" invocation.
+	(thr_apply_info_thr_invalid): Default the expected output to the
+	input tid list.
+	(top level): Add tests that use convenience variables.  Add tests
+	for "thread apply" with a valid TID list, but missing the command.
+
 2016-01-13  Pedro Alves  <palves@redhat.com>
 
 	* gdb.base/default.exp: Expect $_gthread as well.
diff --git a/gdb/testsuite/gdb.multi/tids.exp b/gdb/testsuite/gdb.multi/tids.exp
index b72695d..5763234 100644
--- a/gdb/testsuite/gdb.multi/tids.exp
+++ b/gdb/testsuite/gdb.multi/tids.exp
@@ -90,15 +90,19 @@ proc thr_apply_info_thr_error {tid_list exp_error}  {
     gdb_test "info threads $tid_list" \
 	$exp_error
 
-    gdb_test "thread apply $tid_list p 1234" \
+    gdb_test "thread apply $tid_list" \
 	$exp_error \
 	"thread apply $tid_list"
 }
 
 # Issue both "info threads TID_LIST" and "thread apply TID_LIST" and
 # expect the command to error out with "Invalid thread ID: $EXPECTED".
-# EXPECTED is a literal string, not a regexp.
-proc thr_apply_info_thr_invalid {tid_list expected} {
+# EXPECTED is a literal string, not a regexp.  If EXPECTED is omitted,
+# TID_LIST is expected instead.
+proc thr_apply_info_thr_invalid {tid_list {expected ""}} {
+    if {$expected == ""} {
+	set expected $tid_list
+    }
     set expected [string_to_regexp $expected]
     gdb_test "info threads $tid_list" \
 	"Invalid thread ID: $expected"
@@ -183,6 +187,12 @@ with_test_prefix "two inferiors" {
 	gdb_continue_to_breakpoint "twice"
     }
 
+    thr_apply_info_thr "1" \
+	"1.1"
+
+    thr_apply_info_thr "1.1" \
+	"1.1"
+
     thr_apply_info_thr "1 2 3" \
 	"1.1 1.2 1.3"
 
@@ -214,6 +224,59 @@ with_test_prefix "two inferiors" {
     thr_apply_info_thr "1.1-2 2.2-3" \
 	"1.1 1.2 2.2 2.3"
 
+    # Now test using GDB convenience variables.
+
+    gdb_test "p \$inf = 1" " = 1"
+    gdb_test "p \$thr_start = 2" " = 2"
+    gdb_test "p \$thr_end = 3" " = 3"
+
+    # Convenience variable for the inferior number, only.
+    thr_apply_info_thr "\$inf.2" \
+	"1.2"
+    thr_apply_info_thr "\$inf.2-3" \
+	"1.2 1.3"
+
+    # Convenience variables for thread numbers as well.
+    foreach prefix {"" "1." "\$inf."} {
+	thr_apply_info_thr "${prefix}\$thr_start" \
+	    "1.2"
+	thr_apply_info_thr "${prefix}\$thr_start-\$thr_end" \
+	    "1.2 1.3"
+	thr_apply_info_thr "${prefix}2-\$thr_end" \
+	    "1.2 1.3"
+	thr_apply_info_thr "${prefix}\$thr_start-3" \
+	    "1.2 1.3"
+
+	# Undefined convenience variable.
+	set prefix_re [string_to_regexp $prefix]
+	thr_apply_info_thr_error "${prefix}\$conv123" \
+	    [multi_line \
+		 "Convenience variable must have integer value\." \
+		 "Invalid thread ID: ${prefix_re}\\\$conv123"]
+    }
+
+    # Convenience variables pointing at an inexisting thread and/or
+    # inferior.
+    gdb_test "p \$inf = 30" " = 30"
+    gdb_test "p \$thr = 20" " = 20"
+    # Try both the convenience variable and the literal number.
+    foreach thr {"\$thr" "20" "1.20" "\$inf.1" "30.1" } {
+	set expected [string_to_regexp $thr]
+	gdb_test "info threads $thr" "No threads match '${expected}'."
+	# "info threads" works like a filter.  If there's any other
+	# valid thread in the list, there's no error.
+	info_threads "$thr 1.1" "1.1"
+	info_threads "1.1 $thr" "1.1"
+    }
+
+    gdb_test "thread apply \$thr p 1234" \
+	"warning: Unknown thread 1.20" \
+	"thread apply \$thr"
+
+    gdb_test "thread apply \$inf.1 p 1234" \
+	"warning: Unknown thread 30.1" \
+	"thread apply \$inf.1"
+
     # Now test a set of invalid thread IDs/ranges.
 
     thr_apply_info_thr_invalid "1." \
@@ -234,17 +297,40 @@ with_test_prefix "two inferiors" {
     thr_apply_info_thr_invalid "1-2.1" \
 	"1-2.1"
 
-    thr_apply_info_thr_error "1-0" "inverted range"
-    thr_apply_info_thr_error "1.1-0" "inverted range"
-
-    thr_apply_info_thr_error "1-" "inverted range"
-    thr_apply_info_thr_error "1.1-" "inverted range"
-
-    thr_apply_info_thr_error "2-1" "inverted range"
-    thr_apply_info_thr_error "1.2-1" "inverted range"
+    gdb_test "p \$zero = 0" " = 0"
+    gdb_test "p \$one = 1" " = 1"
+    gdb_test "p \$minus_one = -11" " = -11"
+    foreach prefix {"" "1." "$one."} {
+	set prefix_re [string_to_regexp $prefix]
+
+	thr_apply_info_thr_invalid "${prefix}foo"
+	thr_apply_info_thr_invalid "${prefix}1foo"
+	thr_apply_info_thr_invalid "${prefix}foo1"
+
+	thr_apply_info_thr_error "${prefix}1-0" "inverted range"
+	thr_apply_info_thr_error "${prefix}1-\$zero" "inverted range"
+	thr_apply_info_thr_error "${prefix}\$one-0" "inverted range"
+	thr_apply_info_thr_error "${prefix}\$one-\$zero" "inverted range"
+	thr_apply_info_thr_error "${prefix}1-" "inverted range"
+	thr_apply_info_thr_error "${prefix}2-1" "inverted range"
+	thr_apply_info_thr_error "${prefix}2-\$one" "inverted range"
+	thr_apply_info_thr_error "${prefix}-1" "negative value"
+	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 "-1" "negative value"
-    thr_apply_info_thr_error "1.-1" "negative value"
+    # Check that a valid thread ID list with a missing command errors
+    # out.
+    with_test_prefix "missing command" {
+	set output "Please specify a command following the thread ID list"
+	gdb_test "thread apply 1" $output
+	gdb_test "thread apply 1.1" $output
+	gdb_test "thread apply 1.1 1.2" $output
+	gdb_test "thread apply 1-2" $output
+	gdb_test "thread apply 1.1-2" $output
+	gdb_test "thread apply $thr" $output
+    }
 
     # Check that we do parse the inferior number and don't confuse it.
     gdb_test "info threads 3.1" \
diff --git a/gdb/thread.c b/gdb/thread.c
index b3b3995..56de6e1 100644
--- a/gdb/thread.c
+++ b/gdb/thread.c
@@ -1818,7 +1818,7 @@ thread_apply_all_command (char *cmd, int from_tty)
 static void
 thread_apply_command (char *tidlist, int from_tty)
 {
-  char *cmd;
+  char *cmd = NULL;
   struct cleanup *old_chain;
   char *saved_cmd;
   struct tid_range_parser parser;
@@ -1826,11 +1826,25 @@ thread_apply_command (char *tidlist, int from_tty)
   if (tidlist == NULL || *tidlist == '\000')
     error (_("Please specify a thread ID list"));
 
-  for (cmd = tidlist; *cmd != '\000' && !isalpha (*cmd); cmd++);
+  tid_range_parser_init (&parser, tidlist, current_inferior ()->num);
+  while (!tid_range_parser_finished (&parser))
+    {
+      int inf_num, thr_start, thr_end;
+
+      if (!tid_range_parser_get_tid_range (&parser,
+					   &inf_num, &thr_start, &thr_end))
+	{
+	  cmd = (char *) tid_range_parser_string (&parser);
+	  break;
+	}
+    }
 
-  if (*cmd == '\000')
+  if (cmd == NULL)
     error (_("Please specify a command following the thread ID list"));
 
+  if (tidlist == cmd || !isalpha (cmd[0]))
+    invalid_thread_id_error (cmd);
+
   /* Save a copy of the command in case it is clobbered by
      execute_command.  */
   saved_cmd = xstrdup (cmd);
diff --git a/gdb/tid-parse.c b/gdb/tid-parse.c
index 21b872d..45b7ff5 100644
--- a/gdb/tid-parse.c
+++ b/gdb/tid-parse.c
@@ -31,6 +31,23 @@ invalid_thread_id_error (const char *string)
   error (_("Invalid thread ID: %s"), string);
 }
 
+/* Wrapper for get_number_trailer that throws an error if we get back
+   a negative number.  We'll see a negative value if the number is
+   stored in a negative convenience variable (e.g., $minus_one = -1).
+   STRING is the parser string to be used in the error message if we
+   do get back a negative number.  */
+
+static int
+get_positive_number_trailer (const char **pp, int trailer, const char *string)
+{
+  int num;
+
+  num = get_number_trailer (pp, trailer);
+  if (num < 0)
+    error (_("negative value: %s"), string);
+  return num;
+}
+
 /* See tid-parse.h.  */
 
 struct thread_info *
@@ -51,7 +68,7 @@ parse_thread_id (const char *tidstr, const char **end)
       int inf_num;
 
       p1 = number;
-      inf_num = get_number_trailer (&p1, '.');
+      inf_num = get_positive_number_trailer (&p1, '.', number);
       if (inf_num == 0)
 	invalid_thread_id_error (number);
 
@@ -69,7 +86,7 @@ parse_thread_id (const char *tidstr, const char **end)
       p1 = number;
     }
 
-  thr_num = get_number_const (&p1);
+  thr_num = get_positive_number_trailer (&p1, 0, number);
   if (thr_num == 0)
     invalid_thread_id_error (number);
 
@@ -183,15 +200,16 @@ get_tid_or_range (struct tid_range_parser *parser, int *inf_num,
 
 	  /* Parse number to the left of the dot.  */
 	  p = parser->string;
-	  parser->inf_num = get_number_trailer (&p, '.');
+	  parser->inf_num
+	    = get_positive_number_trailer (&p, '.', parser->string);
 	  if (parser->inf_num == 0)
-	    invalid_thread_id_error (parser->string);
+	    return 0;
 
 	  parser->qualified = 1;
 	  p = dot + 1;
 
 	  if (isspace (*p))
-	    invalid_thread_id_error (parser->string);
+	    return 0;
 	}
       else
 	{
@@ -206,8 +224,13 @@ get_tid_or_range (struct tid_range_parser *parser, int *inf_num,
 
   *inf_num = parser->inf_num;
   *thr_start = get_number_or_range (&parser->range_parser);
+  if (*thr_start < 0)
+    error (_("negative value: %s"), parser->string);
   if (*thr_start == 0)
-    invalid_thread_id_error (parser->string);
+    {
+      parser->state = TID_RANGE_STATE_INFERIOR;
+      return 0;
+    }
 
   /* If we successfully parsed a thread number or finished parsing a
      thread range, switch back to assuming the next TID is


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]