From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from simark.ca by simark.ca with LMTP id mJcXBD622WeGHRQAWB0awg (envelope-from ) for ; Tue, 18 Mar 2025 14:06:54 -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=jW57EGG+; dkim-atps=neutral Received: by simark.ca (Postfix, from userid 112) id 0D3551E0C0; Tue, 18 Mar 2025 14:06:54 -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 9DAC61E0C0 for ; Tue, 18 Mar 2025 14:06:52 -0400 (EDT) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 447D23858C56 for ; Tue, 18 Mar 2025 18:06:52 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 447D23858C56 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=jW57EGG+ Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.17]) by sourceware.org (Postfix) with ESMTPS id 7B7DA3858C39 for ; Tue, 18 Mar 2025 18:05:46 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 7B7DA3858C39 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 7B7DA3858C39 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=198.175.65.17 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1742321146; cv=none; b=f+BiW9IYtg9s8lfQFFU8JNp00iex23PBrxTrj2J3fbzkbajrquOijORHeR7z+98TH28Fwj3cgd8RLbO26sCzy50GYq3S5Eb9sWl6aJOq+fbQU+PwFKZv3uYQaGkkoAVSUTmYY36hHAx1UgcZBkgFQ7MpIcetiXu/BFGiosIqs34= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1742321146; c=relaxed/simple; bh=GLMZBEfmUrTSH4HsJ030ux1n6qgvBpz5kkUweLbc3JA=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=kIg3vYVVIvb8Bzk7GigoO3buYhfJ5rZAuqFRvZSzb31hXV0bKzC1HfXA/cYNwvqG3sC1+IIMPmiBSi8pyiBajjst9DHrCys0tvFf0m0g40s9AlSvdsmDASLXAtFEYpHu9IhQKgqLIOZV+Gm4mWukVVrbKYh46YKZLHekgo1w5tM= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 7B7DA3858C39 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1742321146; x=1773857146; h=from:to:subject:date:message-id:in-reply-to:references: mime-version:content-transfer-encoding; bh=GLMZBEfmUrTSH4HsJ030ux1n6qgvBpz5kkUweLbc3JA=; b=jW57EGG+pnFDTK/fNw/Ou5Q6R8LN2RqZtr0OCPMaXZV5eBk4MCI8sZLe CoS21Z+ykskjXc55HhSvSLS+8zoI4C6YKp2SrAJy9epRvtsFTMVrJ0ZLC Cv1bMgAY9KB8rkX82My04ooKExeKyKTmk/Qk+Ep+BKomTIVVrmGzVvnV/ t+CkTYJX4ci9kWb4edLPp7MR+NsL7jN0c8FK6I5M/ygi7owAzKPgwOsvq JCKXy38umFHVYHFCJQYZXHEb/VBMMD2BT6Vxw8K4iIjUqc+3wqaSyXYqk 2qrqa6seCklLdcdkvIKxfecS5UBrKMALlkWxEyQQr81MvpQsrfeGjnA9R w==; X-CSE-ConnectionGUID: TinGS0prSNOqRKmyE2jW5w== X-CSE-MsgGUID: q5rP77vbRP+cEceNrOtpBw== X-IronPort-AV: E=McAfee;i="6700,10204,11377"; a="43495946" X-IronPort-AV: E=Sophos;i="6.14,257,1736841600"; d="scan'208";a="43495946" Received: from fmviesa009.fm.intel.com ([10.60.135.149]) by orvoesa109.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 18 Mar 2025 11:05:46 -0700 X-CSE-ConnectionGUID: Ph7oUvuuTJ+XMNHzwD/Fuw== X-CSE-MsgGUID: +KPgpLd2S4SAwZ8M4tYhHA== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.14,257,1736841600"; d="scan'208";a="123089054" Received: from gkldtt-dev-004.igk.intel.com (HELO localhost) ([10.123.221.202]) by fmviesa009-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 18 Mar 2025 11:05:45 -0700 From: Tankut Baris Aktemur To: gdb-patches@sourceware.org Subject: [PATCH v2 2/2] gdb: add a '-stopped' option to "info threads" Date: Tue, 18 Mar 2025 19:05:01 +0100 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 --- gdb/NEWS | 7 ++ 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 | 75 ++++++++++++++++++ gdb/thread.c | 17 +++- 6 files changed, 190 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 0aac7a7b13a..be24ed0a251 100644 --- a/gdb/NEWS +++ b/gdb/NEWS @@ -45,6 +45,13 @@ show riscv numeric-register-names (e.g 'x1') or their abi names (e.g. 'ra'). Defaults to 'off', matching the old behaviour (abi names). +* Changed commands + +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 473431011d1..537e2e2230b 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 a1ca39eab11..a343867f189 100644 --- a/gdb/testsuite/gdb.base/options.exp +++ b/gdb/testsuite/gdb.base/options.exp @@ -508,12 +508,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..3e6476c2f41 --- /dev/null +++ b/gdb/testsuite/gdb.threads/info-threads-stopped.exp @@ -0,0 +1,75 @@ +# 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" + +# Count the number of running/stopped threads reported +# by the "info threads" command. +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 + exp_continue + } + -re "^\r\n. ${decimal}${fill}Thread ${fill}something ${fill}" { + incr num_stopped + 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" + } + } + } +} 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