From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from simark.ca by simark.ca with LMTP id KH88K9fg72duliYAWB0awg (envelope-from ) for ; Fri, 04 Apr 2025 09:38:31 -0400 Authentication-Results: simark.ca; dkim=pass (2048-bit key; unprotected) header.d=intel.com header.i=@intel.com header.a=rsa-sha256 header.s=Intel header.b=HLEG6iQL; dkim-atps=neutral Received: by simark.ca (Postfix, from userid 112) id ADD7F1E0C3; Fri, 4 Apr 2025 09:38:31 -0400 (EDT) X-Spam-Checker-Version: SpamAssassin 4.0.1 (2024-03-25) on simark.ca X-Spam-Level: X-Spam-Status: No, score=-6.4 required=5.0 tests=ARC_SIGNED,ARC_VALID,BAYES_00, DKIMWL_WL_HIGH,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,MAILING_LIST_MULTI, RCVD_IN_DNSWL_MED autolearn=ham autolearn_force=no version=4.0.1 Received: from server2.sourceware.org (server2.sourceware.org [8.43.85.97]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (prime256v1) server-digest SHA256) (No client certificate requested) by simark.ca (Postfix) with ESMTPS id C8A431E05C for ; Fri, 4 Apr 2025 09:38:29 -0400 (EDT) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 58146383A28A for ; Fri, 4 Apr 2025 13:38:21 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 58146383A28A Authentication-Results: sourceware.org; dkim=pass (2048-bit key, unprotected) header.d=intel.com header.i=@intel.com header.a=rsa-sha256 header.s=Intel header.b=HLEG6iQL Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.12]) by sourceware.org (Postfix) with ESMTPS id 3F639384147B for ; Fri, 4 Apr 2025 13:37:29 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 3F639384147B Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=intel.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 3F639384147B Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=198.175.65.12 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1743773849; cv=none; b=EJsfCaUwR/NsDFWkN2hwqin05oFteRJD8LpgQh7PSGDTTrYpjMt3AbWS1kHW63bIXOGqIR1D32ar1FyVbrhypXHhwY0y7/z0kX2aJ8jbLvrrw9ibyHYgdFam0G92ueTFxke4HXgyxi/WJQ9AWd6o926NBmHb78u4eZPAVoiCKgo= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1743773849; c=relaxed/simple; bh=8Y0bWKuYdDrEvbda+AjUAlkBIxwwkChS9QgMhnq4wC4=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=L2jqiqiKo1ZAirbhovWJNaP4dwyDK9pC6GNXdPM9hC1hCK31TFC6sApPtzSsR+vfEO6K+gyW/Da9+1o+ZuxzQIPJgbtTycPuR9P0RbmQOTpXyT0tXH2um3QX4bBSOUQ7mkJmYJL3ufUILQpOpKhMj+FWCwqvkjhMT/8KHY4R4W8= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 3F639384147B DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1743773850; x=1775309850; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=8Y0bWKuYdDrEvbda+AjUAlkBIxwwkChS9QgMhnq4wC4=; b=HLEG6iQLAPqq0dVmP37A9DSDp7L/nvBgUzoCMaXmRKZxflJwpwXyQThl p/JSYmqiBKJF2FzZnCbqLFICE5Wr7dldTLkgGwgKwzI/igXL0CAMNtyQN 8DmP99rCLk0MaXKzsisaWg5KyNCkvh72Io4WRfj9mBX4xdRkc54vb3PEh hq1Jt6lpU1KpC8YRaJisV3d2LErDyt4q4XzNT1Xb8T9booB2o7dXMCy3u wDCiGUXQI02SVmicU4qMPfREp+O7iz0CL7dmpr1Cjv2tTBxX6cCqw913C 5xp99bZjYzaFQm5Gl5iL62yvLn9sJM/5FtrK57nxCW/VIUZacbbuz2Hmg w==; X-CSE-ConnectionGUID: CTMqFDffTduE9Wap1LmsVg== X-CSE-MsgGUID: Ot/BH57mTbmCmU7+1Bt71g== X-IronPort-AV: E=McAfee;i="6700,10204,11394"; a="56583698" X-IronPort-AV: E=Sophos;i="6.15,188,1739865600"; d="scan'208";a="56583698" Received: from orviesa002.jf.intel.com ([10.64.159.142]) by orvoesa104.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 04 Apr 2025 06:37:29 -0700 X-CSE-ConnectionGUID: EDmGOo40TlijtUo8M6aEvQ== X-CSE-MsgGUID: 1ITKZBAFQ6OMJOd4An85BQ== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.15,188,1739865600"; d="scan'208";a="158285569" Received: from gkldtt-dev-004.igk.intel.com (HELO localhost) ([10.123.221.202]) by orviesa002-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 04 Apr 2025 06:37:27 -0700 From: Tankut Baris Aktemur To: gdb-patches@sourceware.org Cc: guinevere@redhat.com, eliz@gnu.org Subject: [PATCH v3 2/2] gdb: add a '-stopped' option to "info threads" Date: Fri, 4 Apr 2025 15:36:46 +0200 Message-Id: X-Mailer: git-send-email 2.34.1 In-Reply-To: References: MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gdb-patches-bounces~public-inbox=simark.ca@sourceware.org Add a '-stopped' option to the "info threads" command to print stopped threads only and skip the running ones. This is a convenience flag to filter out the running threads in programs that have many threads. Suppose we have an application with 5 threads, 2 of which have hit a breakpoint. The "info threads" command in the non-stop mode gives: (gdb) info threads Id Target Id Frame * 1 Thread 0x7ffff7d99740 (running) 2 Thread 0x7ffff7d98700 something () at file.c:30 3 Thread 0x7ffff7597700 (running) 4 Thread 0x7ffff6d96700 something () at file.c:30 5 Thread 0x7ffff6595700 (running) (gdb) Using the "-stopped" flag, we get (gdb) info threads -stopped Id Target Id Frame 2 Thread 0x7ffff7d98700 something () at file.c:30 4 Thread 0x7ffff6d96700 something () at file.c:30 (gdb) When combined with a thread ID, the behavior is as follows: (gdb) info threads 3 Id Target Id Frame 3 Thread 0x7ffff7597700 (running) (gdb) info threads -stopped 3 No stopped threads match '3'. (gdb) Regression-tested on X86_64 Linux. Reviewed-By: Eli Zaretskii Reviewed-By: Guinevere Larsen --- gdb/NEWS | 5 + gdb/doc/gdb.texinfo | 6 +- gdb/testsuite/gdb.base/options.exp | 11 +- .../gdb.threads/info-threads-stopped.c | 78 +++++++++++++ .../gdb.threads/info-threads-stopped.exp | 107 ++++++++++++++++++ gdb/thread.c | 17 ++- 6 files changed, 220 insertions(+), 4 deletions(-) create mode 100644 gdb/testsuite/gdb.threads/info-threads-stopped.c create mode 100644 gdb/testsuite/gdb.threads/info-threads-stopped.exp diff --git a/gdb/NEWS b/gdb/NEWS index 6a557bb4af9..d5c55c3c938 100644 --- a/gdb/NEWS +++ b/gdb/NEWS @@ -56,6 +56,11 @@ info sharedlibrary command are now for the full memory range allocated to the shared library. +info threads [-gid] [-stopped] [ID]... + This command now takes an optional flag, '-stopped', that causes only + the stopped threads to be printed. The flag can be useful to get a + reduced list when there is a large number of unstopped threads. + * Python API ** New class gdb.Color for dealing with colors. diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index e034ac53295..3c03761dd00 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -3807,7 +3807,7 @@ Thread 1 "main" received signal SIGINT, Interrupt. @table @code @anchor{info_threads} @kindex info threads -@item info threads @r{[}-gid@r{]} @r{[}@var{thread-id-list}@r{]} +@item info threads @r{[}-gid@r{]} @r{[}-stopped@r{]} @r{[}@var{thread-id-list}@r{]} Display information about one or more threads. With no arguments displays information about all threads. You can specify the list of @@ -3857,6 +3857,10 @@ If you're debugging multiple inferiors, @value{GDBN} displays thread IDs using the qualified @var{inferior-num}.@var{thread-num} format. Otherwise, only @var{thread-num} is shown. +If you specify the @samp{-stopped} option, @value{GDBN} displays the +stopped threads only. This can be helpful to reduce the output list +if there is a large number of unstopped threads. + If you specify the @samp{-gid} option, @value{GDBN} displays a column indicating each thread's global thread ID: diff --git a/gdb/testsuite/gdb.base/options.exp b/gdb/testsuite/gdb.base/options.exp index 8760a918082..90902e94086 100644 --- a/gdb/testsuite/gdb.base/options.exp +++ b/gdb/testsuite/gdb.base/options.exp @@ -509,12 +509,21 @@ proc_with_prefix test-thread-apply {} { proc_with_prefix test-info-threads {} { test_gdb_complete_multiple "info threads " "" "" { "-gid" + "-stopped" "ID" } + test_gdb_complete_multiple "info threads " "-" "" { + "-gid" + "-stopped" + } + test_gdb_complete_unique \ - "info threads -" \ + "info threads -g" \ "info threads -gid" + test_gdb_complete_unique \ + "info threads -s" \ + "info threads -stopped" # "ID" isn't really something the user can type. test_gdb_complete_none "info threads I" diff --git a/gdb/testsuite/gdb.threads/info-threads-stopped.c b/gdb/testsuite/gdb.threads/info-threads-stopped.c new file mode 100644 index 00000000000..2c38ecca074 --- /dev/null +++ b/gdb/testsuite/gdb.threads/info-threads-stopped.c @@ -0,0 +1,78 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2022-2025 Free Software Foundation, Inc. + + 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 . */ + +#include +#include +#include +#include + +#define NUM 4 + +volatile int should_spin = 1; + +static void +something () +{ +} + +static void +spin () +{ + while (should_spin) + usleep (1); +} + +static void * +work (void *arg) +{ + int id = *((int *) arg); + + /* Sleep a bit to give the other threads a chance to run. */ + usleep (1); + + if (id % 2 == 0) + something (); /* break-here */ + else + spin (); + + pthread_exit (NULL); +} + +int +main () +{ + /* Ensure we stop if GDB crashes and DejaGNU fails to kill us. */ + alarm (10); + + pthread_t threads[NUM]; + void *thread_result; + int ids[NUM]; + + for (int i = 0; i < NUM; i++) + { + ids[i] = i + 2; + pthread_create (&threads[i], NULL, work, &(ids[i])); + } + + sleep (10); + should_spin = 0; + + for (int i = 0; i < NUM; i++) + pthread_join(threads[i], &thread_result); + + return 0; +} diff --git a/gdb/testsuite/gdb.threads/info-threads-stopped.exp b/gdb/testsuite/gdb.threads/info-threads-stopped.exp new file mode 100644 index 00000000000..37d6622697c --- /dev/null +++ b/gdb/testsuite/gdb.threads/info-threads-stopped.exp @@ -0,0 +1,107 @@ +# Copyright (C) 2022-2025 Free Software Foundation, Inc. + +# 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 . + +# Test for the '-stopped' flag of the "info threads" command. + +standard_testfile + +if {[gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" \ + executable debug] != "" } { + return -1 +} + +save_vars { GDBFLAGS } { + append GDBFLAGS " -ex \"set non-stop on\"" + clean_restart $binfile +} + +gdb_breakpoint "something" +gdb_run_cmd + +# Two threads hit the bp. +set fill "\[^\r\n\]+" +set num_hits 0 +gdb_test_multiple "" "hit the breakpoint" -lbl { + -re "\r\nThread ${fill} hit Breakpoint 1${fill}" { + incr num_hits + if {$num_hits < 2} { + exp_continue + } + } + -re "\r\n$gdb_prompt " { + exp_continue + } +} +gdb_assert {$num_hits == 2} "two threads hit the bp" + +# We are in non-stop mode. +# Send a simple command to resync the command prompt. +gdb_test "p 42" " = 42" + +# Count the number of running/stopped threads reported +# by the "info threads" command. We also capture thread ids +# for additional tests. +set running_tid "invalid" +set stopped_tid "invalid" + +foreach flag {"" "-stopped"} { + set num_running 0 + set num_stopped 0 + gdb_test_multiple "info threads $flag" "info threads $flag" { + -re "Id${fill}Target Id${fill}Frame${fill}" { + exp_continue + } + -re "^\r\n. (${decimal})${fill}Thread ${fill}.running." { + incr num_running + set running_tid $expect_out(1,string) + exp_continue + } + -re "^\r\n. (${decimal})${fill}Thread ${fill}something ${fill}${srcfile}:${decimal}" { + incr num_stopped + set stopped_tid $expect_out(1,string) + exp_continue + } + -re "^\r\n$gdb_prompt $" { + gdb_assert {$num_stopped == 2} "$gdb_test_name: num stopped" + if {$flag eq ""} { + gdb_assert {$num_running == 3} "$gdb_test_name: num running" + } else { + gdb_assert {$num_running == 0} "$gdb_test_name: num running" + } + } + } +} + +gdb_assert {$running_tid != "invalid"} "found a running thread" +gdb_assert {$stopped_tid != "invalid"} "found a stopped thread" + +# Test specifying thread ids. +gdb_test "info threads -stopped $running_tid" \ + "No stopped threads match '$running_tid'\." \ + "info thread -stopped for a running thread" + +set fill "\[^\r\n\]+" +set ws "\[ \t\]+" +gdb_test "info threads -stopped $stopped_tid" \ + [multi_line \ + "${ws}Id${ws}Target Id${ws}Frame${ws}" \ + "${ws}${stopped_tid}${ws}Thread ${fill} something ${fill}"] \ + "info thread -stopped for a stopped thread" + +gdb_test "info threads -stopped $running_tid $stopped_tid" \ + [multi_line \ + "${ws}Id${ws}Target Id${ws}Frame${ws}" \ + "${ws}${stopped_tid}${ws}Thread ${fill} something ${fill}"] \ + "info thread -stopped for a running and a stopped thread" diff --git a/gdb/thread.c b/gdb/thread.c index 7dc8e7018c5..87ee9f66680 100644 --- a/gdb/thread.c +++ b/gdb/thread.c @@ -1044,6 +1044,8 @@ struct info_threads_opts { /* For "-gid". */ bool show_global_ids = false; + /* For "-stopped". */ + bool show_stopped_threads = false; }; static const gdb::option::option_def info_threads_option_defs[] = { @@ -1053,6 +1055,11 @@ static const gdb::option::option_def info_threads_option_defs[] = { [] (info_threads_opts *opts) { return &opts->show_global_ids; }, N_("Show global thread IDs."), }, + gdb::option::flag_option_def { + "stopped", + [] (info_threads_opts *opts) { return &opts->show_stopped_threads; }, + N_("Show stopped threads only."), + }, }; @@ -1095,6 +1102,11 @@ should_print_thread (const char *requested_threads, int default_inf_num, if (thr->state == THREAD_EXITED) return false; + /* Skip a running thread if the user wants stopped threads only. */ + bool is_stopped = (thr->state == THREAD_STOPPED); + if (opts.show_stopped_threads && !is_stopped) + return false; + return true; } @@ -1286,7 +1298,8 @@ print_thread_info_1 (struct ui_out *uiout, const char *requested_threads, if (requested_threads == NULL || *requested_threads == '\0') uiout->message (_("No threads.\n")); else - uiout->message (_("No threads match '%s'.\n"), + uiout->message (_("No %sthreads match '%s'.\n"), + (opts.show_stopped_threads ? "stopped " : ""), requested_threads); return; } @@ -1342,7 +1355,7 @@ void print_thread_info (struct ui_out *uiout, const char *requested_threads, int pid) { - info_threads_opts opts {false}; + info_threads_opts opts {false, false}; print_thread_info_1 (uiout, requested_threads, 1, pid, opts); } -- 2.34.1 Intel Deutschland GmbH Registered Address: Am Campeon 10, 85579 Neubiberg, Germany Tel: +49 89 99 8853-0, www.intel.de Managing Directors: Sean Fennelly, Jeffrey Schneiderman, Tiffany Doon Silva Chairperson of the Supervisory Board: Nicole Lau Registered Office: Munich Commercial Register: Amtsgericht Muenchen HRB 186928