Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
From: Andrew Burgess <aburgess@redhat.com>
To: Keith Seitz <keiths@redhat.com>, gdb-patches@sourceware.org
Subject: Re: [PATCH] Add gstack script
Date: Wed, 11 Dec 2024 16:51:45 +0000	[thread overview]
Message-ID: <87v7vqgo2m.fsf@redhat.com> (raw)
In-Reply-To: <ad8ac1e5d5b9c0c84150daa6800c3bc918879a4f.1732557806.git.keiths@redhat.com>

Keith Seitz <keiths@redhat.com> writes:

> 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.]

That would be amazing!

>
> 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                     |  15 +++-
>  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 |  78 ++++++++++++++++++
>  9 files changed, 353 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 ecb323d8f02..2bf4cda315c 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
> @@ -1951,7 +1952,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.
> @@ -2110,6 +2111,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 \
> @@ -2154,6 +2168,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 \
> @@ -2265,7 +2290,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
> @@ -2326,6 +2351,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 046daad0eae..4922a8aa38f 100644
> --- a/gdb/NEWS
> +++ b/gdb/NEWS
> @@ -56,6 +56,9 @@
>  
>  * The Ada 'Object_Size attribute is now supported.
>  
> +* 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 ec9bbd3a842..3f2e1450aa5 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
> @@ -24974,6 +24975,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.
>  
>  
> @@ -33694,6 +33701,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"
>  
>  
> @@ -34794,6 +34803,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" ;;
> @@ -36340,6 +36350,7 @@ _LT_EOF
>      done ;;
>      "nm.h":L) echo > stamp-nmh ;;
>      "gcore":F) chmod +x gcore ;;
> +    "gstack.in":F) chmod +x gstack.in ;;
>  
>    esac
>  done # for ac_tag
> diff --git a/gdb/configure.ac b/gdb/configure.ac
> index 21f5dc8dd30..49d420bfc41 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],
> @@ -2231,6 +2237,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], [chmod +x gstack.in])

I wonder if the '[chmod +x gstack.in]' part could be dropped.  When
gstack.in is converted to gstack we +x the new gstack script, but
gstack.in isn't really a script yet, right?

>  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 99720f1206e..0156eff8633 100644
> --- a/gdb/doc/gdb.texinfo
> +++ b/gdb/doc/gdb.texinfo
> @@ -50580,6 +50580,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
> @@ -51262,6 +51263,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..80e9b45e294
> --- /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 <http://www.gnu.org/licenses/>.
> +
> +# 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 <<EOF |
> +set width 0
> +set height 0
> +set pagination no
> +set debuginfod enabled off
> +define attach-bt
> +attach \$arg0
> +echo "ATTACHED"
> +thread apply all bt
> +end
> +attach-bt $PID
> +EOF
> +awk -- "$awk_script"
> diff --git a/gdb/testsuite/gdb.base/gstack.c b/gdb/testsuite/gdb.base/gstack.c
> new file mode 100644
> index 00000000000..a8716707560
> --- /dev/null
> +++ b/gdb/testsuite/gdb.base/gstack.c
> @@ -0,0 +1,32 @@
> +/* This testcase is part of GDB, the GNU debugger.
> +
> +   Copyright 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 <http://www.gnu.org/licenses/>.  */
> +
> +#include <unistd.h>
> +#include <string.h>
> +
> +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 (;;) ;
> +
> +  return 0;
> +}
> diff --git a/gdb/testsuite/gdb.base/gstack.exp b/gdb/testsuite/gdb.base/gstack.exp
> new file mode 100644
> index 00000000000..901a8fb7cef
> --- /dev/null
> +++ b/gdb/testsuite/gdb.base/gstack.exp
> @@ -0,0 +1,78 @@
> +# 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 <http://www.gnu.org/licenses/>.
> +
> +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 command "sh -c GDB=$GDB\\ GDBARGS=-data-directory\\\\\\ $GDB_DATA_DIRECTORY\\ sh\\ ${srcdir}/../contrib/gstack.sh\\ $pid\\;echo\\ GSTACK-END"

I haven't dug into what's going on in this test, but I notice that it
references contrib/gstack.sh, which isn't in HEAD, and isn't in this
patch.  And when I run the test I see:

  PASS: gdb.base/gstack.exp: spawn gstack
  sh: /tmp/build/gdb/testsuite/../../../src/gdb/testsuite/../contrib/gstack.sh: No such file or directory
  GSTACK-END
  PASS: gdb.base/gstack.exp: gstack exits with no error
  PASS: gdb.base/gstack.exp: gstack's exit status is 0

Which I guess indicates that (a) the file's missing, and (b) the test
should be improved to catch this case?

Thanks,
Andrew


> +set res [remote_spawn host $command]
> +if { ![gdb_assert { ![expr {$res < 0 || $res == ""}] } $test] } {
> +    return
> +}
> +
> +set test "got backtrace"
> +gdb_test_multiple "" $test {
> +    -i "$res" -re "^#0 +(0x\[0-9a-f\]+ in )?\\.?func \\(\\) at \[^\r\n\]*\r\n#1 +0x\[0-9a-f\]+ in \\.?main \\(\\) at \[^\r\n\]*\r\nGSTACK-END\r\n\$" {
> +	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
> +    }
> +}
> +
> +# Kill the test inferior.
> +kill_wait_spawned_process $test_spawn_id
>
> base-commit: be740e7cc62fed098ad62cef3b2e2b25b44d8748
> -- 
> 2.47.0


  reply	other threads:[~2024-12-11 16:53 UTC|newest]

Thread overview: 16+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-11-25 18:18 Keith Seitz
2024-12-11 16:51 ` Andrew Burgess [this message]
2024-12-11 16:58   ` Keith Seitz
2024-12-12 21:07 ` [PATCH v2] " Keith Seitz
2024-12-13  7:36   ` Eli Zaretskii
2024-12-13 18:21     ` Keith Seitz
2024-12-13 19:04       ` Eli Zaretskii
2024-12-13 19:45   ` Tom Tromey
2024-12-13 19:57     ` Keith Seitz
2024-12-18 18:05 ` [PATCH v3] " Keith Seitz
2024-12-18 19:22   ` Eli Zaretskii
2024-12-18 21:47     ` Keith Seitz
2024-12-20 16:15   ` Tom Tromey
2024-12-20 18:18     ` Keith Seitz
2024-12-20 18:26       ` Tom Tromey
2024-12-20 20:47         ` Keith Seitz

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=87v7vqgo2m.fsf@redhat.com \
    --to=aburgess@redhat.com \
    --cc=gdb-patches@sourceware.org \
    --cc=keiths@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox