From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from simark.ca by simark.ca with LMTP id aPwzHD1SW2d4TxEAWB0awg (envelope-from ) for ; Thu, 12 Dec 2024 16:14:37 -0500 Authentication-Results: simark.ca; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=YTjO8F+k; dkim-atps=neutral Received: by simark.ca (Postfix, from userid 112) id 6F6151E097; Thu, 12 Dec 2024 16:14:37 -0500 (EST) X-Spam-Checker-Version: SpamAssassin 4.0.0 (2022-12-13) 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=unavailable autolearn_force=no version=4.0.0 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 294D61E05C for ; Thu, 12 Dec 2024 16:14:36 -0500 (EST) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id CE0F9385840A for ; Thu, 12 Dec 2024 21:14:35 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org CE0F9385840A Authentication-Results: sourceware.org; dkim=pass (1024-bit key, unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=YTjO8F+k Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by sourceware.org (Postfix) with ESMTP id 6DE873858D29 for ; Thu, 12 Dec 2024 21:07:46 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 6DE873858D29 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=redhat.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 6DE873858D29 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1734037666; cv=none; b=cFlsY11oPH/lpXuraR0WwlGJebyBLgJUbZrCZkPB7wwthCuLy7k8wpAq7FjkhfxyEDrzdWGSaS5dOY9rG9Sm9nDBnk5yR+39A4bk+LfApEwksLhcVk8QWJaQbRTo3UgsUX9pr7UsrJBhYv3d7iPHcrRc+c/3rK0+QtJ6Us8rzUA= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1734037666; c=relaxed/simple; bh=8L2DsXimpU7rdh1Uw8E/z95VlfysechgbcoRAqfa8bA=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=LldY6bCfQ9Ivl9WpEG+SBCXE0Nww5EIYGAC1UWFgusl1kv18LfgDH2rDDkuK0HMg+xa+ro3vdMzmHI0Z7E1QMvQoMJab3LyYpRzZAmZS3x94lA6ExCRbngwTmsS8KUdSHv5SXYVR6Lwnc7a4U254CrnqZs64le8/OyP3Wo6wmgI= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 6DE873858D29 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1734037666; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=0yKBi1YCwMMiQX/o2PSFNKPY7vh3sPpfLePSU0ok8to=; b=YTjO8F+kS7XCTu9hkRFk5vZ8uYSxe6+BKPuGv52t3c0sQeWNjPKvH2KnMJA7wYYK1zs+0S kDld7ruIPWOJrce1cQtHcAE7Q2Z0uPWrJu3hAXDFNf7QWTYUUUvUmjNXyWNpu4etzLIxXt PnpC0JqYstkNDECmfDS8noQ6KHuDCmw= Received: from mx-prod-mc-03.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-543-Abo519Z8PYyYHVm7DELzvQ-1; Thu, 12 Dec 2024 16:07:44 -0500 X-MC-Unique: Abo519Z8PYyYHVm7DELzvQ-1 X-Mimecast-MFC-AGG-ID: Abo519Z8PYyYHVm7DELzvQ Received: from mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.12]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id E47671956048 for ; Thu, 12 Dec 2024 21:07:43 +0000 (UTC) Received: from guittard.redhat.com (unknown [10.22.80.142]) by mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id F2793195394B for ; Thu, 12 Dec 2024 21:07:42 +0000 (UTC) From: Keith Seitz To: gdb-patches@sourceware.org Subject: [PATCH v2] Add gstack script Date: Thu, 12 Dec 2024 13:07:41 -0800 Message-ID: <08a19a3debe4a1e3c6072a807e79566277a7c0dc.1734022384.git.keiths@redhat.com> In-Reply-To: References: MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.12 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: igZpJ2QkQ65EuIPqyLZ9uLKi0DE8c8Xz7weP1Vr3kEo_1734037664 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: 8bit content-type: text/plain; charset="US-ASCII"; x-default=true 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 --- Changes in v2 - Review feedback from Andrew Burgess o Don't chmod gstack.in in configure.ac. o Fix testsuite issues which could mislead users into thinking that tests succeeded when they did not. --- This commit adds support for a `gstack' command which Fedora has been carrying for many years. gstack is a natural counterpart to the gcore command. Whereas gcore dumps a core file, gstack prints stack traces of a running process. There are many improvements over Fedora's version of this script. The dependency on procfs is gone; gstack will run anywhere gdb runs. The only runtime dependencies are bash and awk. The script includes suggestions from gdb/32325 to include versioning and help. [If this approach to gdb/32325 is acceptable, I could propagate the solution to gcore/gdb-add-index.] I've rewritten the documentation, integrating it into the User Manual. The manpage is now output using this one source. Example run (on x86_64 Fedora 40) $ gstack --help Usage: gstack [-h|--help] [-v|--version] PID Print a stack trace of a running program -h, --help Print this message then exit. -v, --version Print version information then exit. $ gstack -v GNU gstack (GDB) 16.0.50.20241119-git $ gstack 12345678 Process 12345678 not found. $ gstack $(pidof emacs) Thread 6 (Thread 0x7f382a8006c0 (LWP 1265626) "pool-spawner"): #0 0x00007f383ffca3dd in syscall () at /lib64/libc.so.6 #1 0x00007f3849cc0ccd in g_cond_wait () at /lib64/libglib-2.0.so.0 #2 0x00007f3849c2c61b in g_async_queue_pop_intern_unlocked () at /lib64/libglib-2.0.so.0 #3 0x00007f3849c93a03 in g_thread_pool_spawn_thread () at /lib64/libglib-2.0.so.0 #4 0x00007f3849c92813 in g_thread_proxy () at /lib64/libglib-2.0.so.0 #5 0x00007f383ff486d7 in start_thread () at /lib64/libc.so.6 #6 0x00007f383ffcc60c in clone3 () at /lib64/libc.so.6 Thread 5 (Thread 0x7f3829e006c0 (LWP 1265627) "gmain"): #0 0x00007f383ffbe87d in poll () at /lib64/libc.so.6 #1 0x00007f3849cc3c34 in g_main_context_iterate_unlocked.isra () at /lib64/libglib-2.0.so.0 #2 0x00007f3849c63383 in g_main_context_iteration () at /lib64/libglib-2.0.so.0 #3 0x00007f3849c633e1 in glib_worker_main () at /lib64/libglib-2.0.so.0 #4 0x00007f3849c92813 in g_thread_proxy () at /lib64/libglib-2.0.so.0 #5 0x00007f383ff486d7 in start_thread () at /lib64/libc.so.6 #6 0x00007f383ffcc60c in clone3 () at /lib64/libc.so.6 Thread 4 (Thread 0x7f38294006c0 (LWP 1265628) "gdbus"): #0 0x00007f383ffbe87d in poll () at /lib64/libc.so.6 #1 0x00007f3849cc3c34 in g_main_context_iterate_unlocked.isra () at /lib64/libglib-2.0.so.0 #2 0x00007f3849c67f37 in g_main_loop_run () at /lib64/libglib-2.0.so.0 #3 0x00007f3849ec7682 in gdbus_shared_thread_func.lto_priv () at /lib64/libgio-2.0.so.0 #4 0x00007f3849c92813 in g_thread_proxy () at /lib64/libglib-2.0.so.0 #5 0x00007f383ff486d7 in start_thread () at /lib64/libc.so.6 #6 0x00007f383ffcc60c in clone3 () at /lib64/libc.so.6 Thread 3 (Thread 0x7f3828a006c0 (LWP 1265629) "emacs"): #0 0x00007f383ffca3dd in syscall () at /lib64/libc.so.6 #1 0x00007f3849cc0ccd in g_cond_wait () at /lib64/libglib-2.0.so.0 #2 0x00007f3849c2c61b in g_async_queue_pop_intern_unlocked () at /lib64/libglib-2.0.so.0 #3 0x00007f3849c2c67c in g_async_queue_pop () at /lib64/libglib-2.0.so.0 #4 0x00007f3842c340d9 in fc_thread_func () at /lib64/libpangoft2-1.0.so.0 #5 0x00007f3849c92813 in g_thread_proxy () at /lib64/libglib-2.0.so.0 #6 0x00007f383ff486d7 in start_thread () at /lib64/libc.so.6 #7 0x00007f383ffcc60c in clone3 () at /lib64/libc.so.6 Thread 2 (Thread 0x7f3823e006c0 (LWP 1265630) "dconf worker"): #0 0x00007f383ffbe87d in poll () at /lib64/libc.so.6 #1 0x00007f3849cc3c34 in g_main_context_iterate_unlocked.isra () at /lib64/libglib-2.0.so.0 #2 0x00007f3849c63383 in g_main_context_iteration () at /lib64/libglib-2.0.so.0 #3 0x00007f382a845705 in dconf_gdbus_worker_thread () at /usr/lib64/gio/modules/libdconfsettings.so #4 0x00007f3849c92813 in g_thread_proxy () at /lib64/libglib-2.0.so.0 #5 0x00007f383ff486d7 in start_thread () at /lib64/libc.so.6 #6 0x00007f383ffcc60c in clone3 () at /lib64/libc.so.6 Thread 1 (Thread 0x7f383b642280 (LWP 1265621) "emacs"): #0 0x00007f383ffc9197 in pselect () at /lib64/libc.so.6 #1 0x00000000006b9e01 in really_call_select.lto_priv () #2 0x00000000006e1979 in xg_select () #3 0x00000000006899d1 in wait_reading_process_output () #4 0x000000000057e91c in kbd_buffer_get_event () #5 0x0000000000580bc6 in read_char () #6 0x0000000000589c03 in read_key_sequence.lto_priv () #7 0x0000000000576135 in command_loop_1.lto_priv () #8 0x00000000006131ce in internal_condition_case () #9 0x000000000057569e in command_loop_2 () #10 0x0000000000613127 in internal_catch () #11 0x0000000000575af3 in command_loop () #12 0x0000000000575bef in recursive_edit_1 () #13 0x0000000000575ddd in Frecursive_edit () #14 0x00000000004795a9 in main () Since this is essentially a complete rewrite of the original script and documentation, I've chosen to only keep a 2024 copyright date. --- gdb/Makefile.in | 38 ++++++++- gdb/NEWS | 3 + gdb/configure | 14 +++- gdb/configure.ac | 7 ++ gdb/doc/Makefile.in | 11 ++- gdb/doc/gdb.texinfo | 48 ++++++++++++ gdb/gstack-1.in | 126 ++++++++++++++++++++++++++++++ gdb/testsuite/gdb.base/gstack.c | 32 ++++++++ gdb/testsuite/gdb.base/gstack.exp | 85 ++++++++++++++++++++ 9 files changed, 359 insertions(+), 5 deletions(-) create mode 100755 gdb/gstack-1.in create mode 100644 gdb/testsuite/gdb.base/gstack.c create mode 100644 gdb/testsuite/gdb.base/gstack.exp diff --git a/gdb/Makefile.in b/gdb/Makefile.in index 52950759711..aae7a8b4790 100644 --- a/gdb/Makefile.in +++ b/gdb/Makefile.in @@ -590,6 +590,7 @@ CONFIG_CLEAN = @CONFIG_CLEAN@ CONFIG_INSTALL = @CONFIG_INSTALL@ CONFIG_UNINSTALL = @CONFIG_UNINSTALL@ HAVE_NATIVE_GCORE_TARGET = @HAVE_NATIVE_GCORE_TARGET@ +HAVE_GSTACK = @HAVE_GSTACK@ CONFIG_SRC_SUBDIR = arch cli dwarf2 mi compile tui unittests guile python \ target nat @@ -1945,7 +1946,7 @@ generated_files = \ # Flags needed to compile Python code PYTHON_CFLAGS = @PYTHON_CFLAGS@ -all: gdb$(EXEEXT) $(CONFIG_ALL) gdb-gdb.py gdb-gdb.gdb gcore +all: gdb$(EXEEXT) $(CONFIG_ALL) gdb-gdb.py gdb-gdb.gdb gcore gstack @$(MAKE) $(FLAGS_TO_PASS) DO=all "DODIRS=$(SUBDIRS)" subdir_do # Rule for compiling .c files in the top-level gdb directory. @@ -2104,6 +2105,19 @@ install-only: $(CONFIG_INSTALL) $(INSTALL_SCRIPT) gcore \ $(DESTDIR)$(bindir)/$$transformed_name; \ fi + if test "x${HAVE_GSTACK}" != x; \ + then \ + transformed_name=`t='$(program_transform_name)'; \ + echo gstack | sed -e "$$t"` ; \ + if test "x$$transformed_name" = x; then \ + transformed_name=gstack ; \ + else \ + true ; \ + fi ; \ + $(SHELL) $(srcdir)/../mkinstalldirs $(DESTDIR)$(bindir) ; \ + $(INSTALL_SCRIPT) gstack \ + $(DESTDIR)$(bindir)/$$transformed_name; \ + fi transformed_name=`t='$(program_transform_name)'; \ echo gdb-add-index | sed -e "$$t"` ; \ if test "x$$transformed_name" = x; then \ @@ -2148,6 +2162,17 @@ uninstall: force $(CONFIG_UNINSTALL) fi ; \ rm -f $(DESTDIR)$(bindir)/$$transformed_name; \ fi + if test "x$(HAVE_GSTACK)" != x; \ + then \ + transformed_name=`t='$(program_transform_name)'; \ + echo gstack | sed -e "$$t"` ; \ + if test "x$$transformed_name" = x; then \ + transformed_name=gstack ; \ + else \ + true ; \ + fi ; \ + rm -f $(DESTDIR)$(bindir)/$$transformed_name; \ + fi transformed_name=`t='$(program_transform_name)'; \ echo gdb-add-index | sed -e "$$t"` ; \ if test "x$$transformed_name" = x; then \ @@ -2259,7 +2284,7 @@ clean mostlyclean: $(CONFIG_CLEAN) # functionality described is if the distributed files are unmodified. distclean: clean @$(MAKE) $(FLAGS_TO_PASS) DO=distclean "DODIRS=$(CLEANDIRS)" subdir_do - rm -f nm.h config.status config.h stamp-h b jit-reader.h gcore stamp-nmh + rm -f nm.h config.status config.h stamp-h b jit-reader.h gcore gstack gstack.in stamp-nmh rm -f gdb-gdb.py gdb-gdb.gdb rm -f y.output yacc.acts yacc.tmp y.tab.h rm -f config.log config.cache @@ -2320,6 +2345,15 @@ jit-reader.h: $(srcdir)/jit-reader.in config.status gcore: $(srcdir)/gcore.in config.status $(ECHO_GEN) $(SHELL) config.status $(SILENT_FLAG) $@ +gstack: gstack.in version.c + $(ECHO_GEN) \ + vv=`grep 'version\[\] = ' version.c | grep -o '".*"' | tr -d \"`; \ + sed -e "s,@VERSION@,$$vv," $< > $@ + @chmod +x $@ + +gstack.in: $(srcdir)/gstack-1.in config.status + $(ECHO_GEN) $(SHELL) config.status $(SILENT_FLAG) $@ + gdb-gdb.py: $(srcdir)/gdb-gdb.py.in config.status $(ECHO_GEN) $(SHELL) config.status $(SILENT_FLAG) $@ diff --git a/gdb/NEWS b/gdb/NEWS index 7f0bd7edfc8..465217b388c 100644 --- a/gdb/NEWS +++ b/gdb/NEWS @@ -62,6 +62,9 @@ * Support for process record/replay and reverse debugging on loongarch*-linux* targets has been added. +* Newly installed $prefix/bin/gstack uses GDB to print stack traces of + running processes. + * Python API ** Added gdb.record.clear. Clears the trace data of the current recording. diff --git a/gdb/configure b/gdb/configure index de750f4fafe..1531f62f76a 100755 --- a/gdb/configure +++ b/gdb/configure @@ -760,6 +760,7 @@ HAVE_NATIVE_GCORE_TARGET TARGET_OBS AMD_DBGAPI_LIBS AMD_DBGAPI_CFLAGS +HAVE_GSTACK ENABLE_BFD_64_BIT_FALSE ENABLE_BFD_64_BIT_TRUE subdirs @@ -11499,7 +11500,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF -#line 11502 "configure" +#line 11503 "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -11605,7 +11606,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF -#line 11608 "configure" +#line 11609 "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -25008,6 +25009,12 @@ if test x${all_targets} = xtrue; then fi fi +HAVE_GSTACK=0 +if test $gdb_native = yes; then + HAVE_GSTACK=1 +fi + + # AMD debugger API support. @@ -33761,6 +33768,8 @@ fi ac_config_files="$ac_config_files gcore" +ac_config_files="$ac_config_files gstack.in:gstack-1.in" + ac_config_files="$ac_config_files Makefile gdb-gdb.gdb gdb-gdb.py doc/Makefile data-directory/Makefile" @@ -34861,6 +34870,7 @@ do "jit-reader.h") CONFIG_FILES="$CONFIG_FILES jit-reader.h:jit-reader.in" ;; "nm.h") CONFIG_LINKS="$CONFIG_LINKS nm.h:$GDB_NM_FILE" ;; "gcore") CONFIG_FILES="$CONFIG_FILES gcore" ;; + "gstack.in") CONFIG_FILES="$CONFIG_FILES gstack.in:gstack-1.in" ;; "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; "gdb-gdb.gdb") CONFIG_FILES="$CONFIG_FILES gdb-gdb.gdb" ;; "gdb-gdb.py") CONFIG_FILES="$CONFIG_FILES gdb-gdb.py" ;; diff --git a/gdb/configure.ac b/gdb/configure.ac index 230c0be79c7..e9312b1bc64 100644 --- a/gdb/configure.ac +++ b/gdb/configure.ac @@ -261,6 +261,12 @@ if test x${all_targets} = xtrue; then fi fi +HAVE_GSTACK=0 +if test $gdb_native = yes; then + HAVE_GSTACK=1 +fi +AC_SUBST(HAVE_GSTACK) + # AMD debugger API support. AC_ARG_WITH([amd-dbgapi], @@ -2264,6 +2270,7 @@ GDB_AC_SELFTEST([ GDB_AC_TRANSFORM([gdb], [GDB_TRANSFORM_NAME]) GDB_AC_TRANSFORM([gcore], [GCORE_TRANSFORM_NAME]) AC_CONFIG_FILES([gcore], [chmod +x gcore]) +AC_CONFIG_FILES([gstack.in:gstack-1.in]) AC_CONFIG_FILES([Makefile gdb-gdb.gdb gdb-gdb.py doc/Makefile data-directory/Makefile]) AC_OUTPUT diff --git a/gdb/doc/Makefile.in b/gdb/doc/Makefile.in index 181325fd0c9..c75714b5de2 100644 --- a/gdb/doc/Makefile.in +++ b/gdb/doc/Makefile.in @@ -188,7 +188,7 @@ TEXI2POD = perl $(srcdir)/../../etc/texi2pod.pl \ POD2MAN = pod2man --center="GNU Development Tools" # List of man pages generated from gdb.texi -MAN1S = gdb.1 gdbserver.1 gcore.1 gdb-add-index.1 +MAN1S = gdb.1 gdbserver.1 gcore.1 gstack.1 gdb-add-index.1 MAN5S = gdbinit.5 MANS = $(MAN1S) $(MAN5S) @@ -199,6 +199,7 @@ POD_FILE_TMPS = $(patsubst %.1,%.pod,$(MAN1S)) \ HAVE_NATIVE_GCORE_TARGET = @HAVE_NATIVE_GCORE_TARGET@ HAVE_NATIVE_GCORE_HOST = @HAVE_NATIVE_GCORE_HOST@ +HAVE_GSTACK = @HAVE_GSTACK@ ### @@ -339,6 +340,10 @@ install-man1: $(MAN1S) -a "$$p" = gcore.1; then \ continue; \ fi; \ + if test "x$(HAVE_GSTACK)" = x \ + -a "$$p" = gstack.1; then \ + continue; \ + fi; \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ f=`echo $$p | sed -e 's|^.*/||' -e '$(transform)'`; \ echo " $(INSTALL_DATA) '$$d$$p' '$(DESTDIR)$(man1dir)/$$f'"; \ @@ -363,6 +368,10 @@ uninstall-man1: -a "$$i" = gcore.1; then \ continue; \ fi; \ + if test "x$(HAVE_GSTACK)" = x \ + -a "$$i" = gstack.1; then \ + continue; \ + fi; \ echo "$$i"; \ done | \ sed -n '/\.1[a-z]*$$/p'; \ diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index 85ac3d9aab6..3cae61a8e5b 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -50553,6 +50553,7 @@ Show the current verbosity setting. * gdb man:: The GNU Debugger man page * gdbserver man:: Remote Server for the GNU Debugger man page * gcore man:: Generate a core file of a running program +* gstack man:: Print a stack trace of a running program * gdbinit man:: gdbinit scripts * gdb-add-index man:: Add index files to speed up GDB @end menu @@ -51235,6 +51236,53 @@ Richard M. Stallman and Roland H. Pesch, July 1991. @end ifset @c man end +@node gstack man +@heading gstack + +@c man title gstack Print a stack trace of a running program + +@format +@c man begin SYNOPSIS gstack +gstack [-h | --help] [-v | --version] @var{pid} +@c man end +@end format + +@c man begin DESCRIPTION gstack +Print a stack trace of a running program with process ID @var{pid}. If the process +is multi-threaded, @command{gstack} outputs backtraces for every thread which exists +in the process. +@c man end + +@c man begin OPTIONS gstack +@table @env +@item --help +@itemx -h +List all options, with brief explanations. + +@item --version +@itemx -v +Print version information and then exit. +@end table +@c man end + +@c man begin SEEALSO gstack +@ifset man +The full documentation for @value{GDBN} is maintained as a Texinfo manual. +If the @code{info} and @code{gdb} programs and @value{GDBN}'s Texinfo +documentation are properly installed at your site, the command + +@smallexample +info gdb +@end smallexample + +@noindent +should give you access to the complete manual. + +@cite{Using GDB: A Guide to the GNU Source-Level Debugger}, +Richard M. Stallman and Roland H. Pesch, July 1991. +@end ifset +@c man end + @node gdbinit man @heading gdbinit diff --git a/gdb/gstack-1.in b/gdb/gstack-1.in new file mode 100755 index 00000000000..53249f01399 --- /dev/null +++ b/gdb/gstack-1.in @@ -0,0 +1,126 @@ +#!/usr/bin/env bash + +# Copyright (C) 2024 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 . + +# Print a stack trace of a running process. +# Similar to the gcore command, but instead of creating a core file, +# we simply have gdb print out the stack backtrace to the terminal. + +GDB=${GDB:-$(command -v gdb)} +GDBARGS=${GDBARGS:-} +PKGVERSION=@PKGVERSION@ +VERSION=@VERSION@ + +function print_usage() { + echo "Usage: $0 [-h|--help] [-v|--version] PID" 1>&2 +} + +function print_try_help() { + echo "Try '$0 --help' for more information." +} + +function print_help() { + print_usage + echo "Print a stack trace of a running program" + echo + echo " -h, --help Print this message then exit." + echo " -v, --version Print version information then exit." +} + +function print_version() { + echo "GNU gstack (${PKGVERSION}) ${VERSION}" +} + +# Parse options. +while getopts hv-: OPT; do + if [ "$OPT" = "-" ]; then + OPT="${OPTARG%%=*}" + OPTARG="${OPTARG#'$OPT'}" + OPTARG="${OPTARG#=}" + fi + + case "$OPT" in + h | help) + print_help + exit 0 + ;; + v | version) + print_version + exit 0 + ;; + \?) + # getopts has already output an error message. + print_try_help + exit 2 ;; + *) + echo "$0: unrecognized option '--$OPT'" >&2 + print_try_help + exit 2 + ;; + esac +done +shift $((OPTIND-1)) + +# The sole remaining argument should be the PID of the process +# whose backtrace is desired. +if [ $# -ne 1 ]; then + print_usage + exit 1 +fi + +PID=$1 + +awk_script=$(cat << EOF +BEGIN { + first=1 + attach_okay=0 +} + +/ATTACHED/ { + attach_okay=1 +} + +/^#/ { + if (attach_okay) { + print \$0 + } +} + +/^Thread/ { + if (attach_okay) { + if (!first) + print "" + first=0 + print \$0 + } +} +EOF + ) + +# Run GDB and remove some unwanted noise. +$GDB --quiet -nx $GDBARGS <. */ + +#include +#include + +int +main (void) +{ + const char msg[] = "looping\n"; + + /* Output a simple string for the expect script to monitor us. */ + write (1, msg, strlen (msg)); + + for (;;) ; /* forever */ + + return 0; +} diff --git a/gdb/testsuite/gdb.base/gstack.exp b/gdb/testsuite/gdb.base/gstack.exp new file mode 100644 index 00000000000..66ca233fa5b --- /dev/null +++ b/gdb/testsuite/gdb.base/gstack.exp @@ -0,0 +1,85 @@ +# Copyright (C) 2024 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 . + +require !gdb_protocol_is_remote +standard_testfile + +if {[prepare_for_testing "failed to prepare" $testfile $srcfile {debug}] == -1} { + return -1 +} + +set command "$binfile" +set res [remote_spawn host $command] +if { ![gdb_assert { ![expr {$res < 0 || $res == ""}] } "spawn inferior"] } { + return +} + +# The spawn id of the test inferior. +set test_spawn_id $res + +# Wait for the spawned program to loop. +set test "wait for inferior to loop" +gdb_expect { + -re "looping\r\n" { + pass $test + } + eof { + fail "$test (eof)" + return + } + timeout { + fail "$test (timeout)" + return + } +} + +# The test case uses a very simple notification not to get caught by attach on +# exiting the function. + +set test "spawn gstack" +set pid [spawn_id_get_pid $test_spawn_id] +set gstack_cmd [findfile $base_dir/../../gdb/gstack] +set command "sh -c GDB=$GDB\\ GDBARGS=-data-directory\\\\\\ $GDB_DATA_DIRECTORY\\ $gstack_cmd\\ $pid\\;echo\\ GSTACK-END" +set res [remote_spawn host $command] +if { ![gdb_assert { ![expr {$res < 0 || $res == ""}] } $test] } { + return +} + +set test "got backtrace" +set saw_backtrace false +set lineno [gdb_get_line_number "forever"] +gdb_test_multiple "" $test { + -i "$res" -re "#0 +(0x\[0-9a-f\]+ in )?main \(\).*${srcfile}:$lineno.*\r\nGSTACK-END\r\n\$" { + set saw_backtrace true + pass $test + exp_continue + } + + eof { + set result [wait -i $res] + verbose $result + + gdb_assert { [lindex $result 2] == 0 } "gstack exits with no error" + gdb_assert { [lindex $result 3] == 0 } "gstack's exit status is 0" + + remote_close host + } +} +if {!$saw_backtrace} { + fail $test +} + +# Kill the test inferior. +kill_wait_spawned_process $test_spawn_id base-commit: a5939d229614a4913daf3c687ec54fdf3020d496 -- 2.47.0