From patchwork Thu Jan 14 11:39:14 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Pedro Alves X-Patchwork-Id: 10377 Received: (qmail 4418 invoked by alias); 14 Jan 2016 11:39:25 -0000 Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org Delivered-To: mailing list gdb-patches@sourceware.org Received: (qmail 4367 invoked by uid 89); 14 Jan 2016 11:39:20 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-1.9 required=5.0 tests=BAYES_00, RP_MATCHES_RCVD, SPF_HELO_PASS autolearn=ham version=3.3.2 spammy= X-HELO: mx1.redhat.com Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES256-GCM-SHA384 encrypted) ESMTPS; Thu, 14 Jan 2016 11:39:19 +0000 Received: from int-mx11.intmail.prod.int.phx2.redhat.com (int-mx11.intmail.prod.int.phx2.redhat.com [10.5.11.24]) by mx1.redhat.com (Postfix) with ESMTPS id 2739F18B322 for ; Thu, 14 Jan 2016 11:39:18 +0000 (UTC) Received: from brno.lan (ovpn01.gateway.prod.ext.phx2.redhat.com [10.5.9.1]) by int-mx11.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id u0EBdGBS029356 for ; Thu, 14 Jan 2016 06:39:17 -0500 From: Pedro Alves To: gdb-patches@sourceware.org Subject: [PATCH 1/2] Fix "thread apply $conv_var" and misc other related problems Date: Thu, 14 Jan 2016 11:39:14 +0000 Message-Id: <1452771555-23153-2-git-send-email-palves@redhat.com> In-Reply-To: <1452771555-23153-1-git-send-email-palves@redhat.com> References: <1452771555-23153-1-git-send-email-palves@redhat.com> 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-14 Pedro Alves * 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-14 Pedro Alves * 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. --- gdb/testsuite/gdb.multi/tids.exp | 107 ++++++++++++++++++++++++++++++++++----- gdb/thread.c | 19 +++++-- gdb/tid-parse.c | 35 ++++++++++--- 3 files changed, 140 insertions(+), 21 deletions(-) diff --git a/gdb/testsuite/gdb.multi/tids.exp b/gdb/testsuite/gdb.multi/tids.exp index b72695d..28b15a3 100644 --- a/gdb/testsuite/gdb.multi/tids.exp +++ b/gdb/testsuite/gdb.multi/tids.exp @@ -90,7 +90,7 @@ 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" } @@ -98,7 +98,10 @@ proc thr_apply_info_thr_error {tid_list exp_error} { # 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} { +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 +186,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 +223,57 @@ 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 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" + + gdb_test "thread apply \$inf.1 p 1234" \ + "warning: Unknown thread 30.1" + # Now test a set of invalid thread IDs/ranges. thr_apply_info_thr_invalid "1." \ @@ -234,17 +294,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 cdd2a2f..f5d9cb0 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,24 @@ 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