summary refs log tree commit diff
path: root/Makefile
diff options
context:
space:
mode:
authorGabriel F. T. Gomes <gabrielftg@linux.ibm.com>2019-09-24 14:21:42 -0300
committerGabriel F. T. Gomes <gabrielftg@linux.ibm.com>2019-09-30 08:37:18 -0300
commit79ced5a893677abf303b3a97290454c1b991b1ae (patch)
tree78b8382a60926d88afc7f741967b30f43a1c1617 /Makefile
parentd7a568af5546e0313abbc04060c8e9b0d3f750b4 (diff)
downloadglibc-79ced5a893677abf303b3a97290454c1b991b1ae.tar.gz
glibc-79ced5a893677abf303b3a97290454c1b991b1ae.tar.xz
glibc-79ced5a893677abf303b3a97290454c1b991b1ae.zip
Add helper script for glibc debugging
This patch adds a new make rule that generates a helper script for
debugging glibc test cases.  The new script, debugglibc.sh, is similar
to testrun.sh, in the sense that it allows the execution of the
specified test case, however, it opens the test case in GDB, setting the
library path the same way that testrun.sh does.  The commands are based
on the instructions on the wiki for glibc debugging [1,2].

By default, the script tells GDB to load the test case for symbol
information, so that, when a breakpoint is hit, the call stack is
displayed correctly (instead of printing lots of '??'s).  For instance,
after running 'make' and 'make check', one could do the following:

  $ ./debugglibc.sh nptl/tst-exec1 -b pthread_join

  Reading symbols from /home/gabriel/build/powerpc64le/glibc//elf/ld.so...done.
  Breakpoint 1 at 0x1444
  add symbol table from file "nptl/tst-exec1"
  [Thread debugging using libthread_db enabled]
  Using host libthread_db library "/home/gabriel/build/powerpc64le/glibc//nptl_db/libthread_db.so.1".

  Breakpoint 1, 0x00007ffff7fb1444 in _dl_start_user () from /home/gabriel/build/powerpc64le/glibc/elf/ld.so
  Breakpoint 2 at 0x7ffff7f49d48: file pthread_join.c, line 23.

Notice that the script will always start GDB with the program running
and halted at _dl_start_user.  So, in order to reach the actual
breakpoint of interest, one should hit 'c', not 'r':

  >>> c
  Continuing.
  [New Thread 0x7ffff7d1f180 (LWP 76443)]
  [Switching to Thread 0x7ffff7d1f180 (LWP 76443)]

  Thread 2 "ld.so" hit Breakpoint 2, __pthread_join (threadid=140737354087616, thread_return=0x0) at pthread_join.c:24
  24        return __pthread_timedjoin_ex (threadid, thread_return, NULL, true);

Then inspect the call stack with 'bt', as usual, and see symbols from
both the test case and from the libraries themselves:

  >>> bt
  #0  __pthread_join (threadid=140737354087616, thread_return=0x0) at pthread_join.c:24
  #1  0x0000000010001f4c in tf (arg=<optimized out>) at tst-exec1.c:37
  #2  0x00007ffff7f487e8 in start_thread (arg=0x7ffff7510000) at pthread_create.c:479
  #3  0x00007ffff7e523a8 in clone () at ../sysdeps/unix/sysv/linux/powerpc/powerpc64/clone.S:82

Tested for powerpc64le and x86_64.

[1] https://sourceware.org/glibc/wiki/Debugging/Loader_Debugging
[2] https://sourceware.org/glibc/wiki/Testing/Builds#Required_gdb_setup

Reviewed-by: Carlos O'Donell <carlos@redhat.com>
Reviewed-by: Dmitry V. Levin <ldv@altlinux.org>
Reviewed-by: Joseph Myers <joseph@codesourcery.com>
Reviewed-by: Andreas Schwab <schwab@suse.de>
Diffstat (limited to 'Makefile')
-rw-r--r--Makefile158
1 files changed, 157 insertions, 1 deletions
diff --git a/Makefile b/Makefile
index 67ddd01bfe..a50fb64dc2 100644
--- a/Makefile
+++ b/Makefile
@@ -187,7 +187,163 @@ $(common-objpfx)testrun.sh: $(common-objpfx)config.make \
 	mv -f $@T $@
 postclean-generated += testrun.sh
 
-others: $(common-objpfx)testrun.sh
+define debugglibc
+#!/bin/bash
+
+SOURCE_DIR="$(CURDIR)"
+BUILD_DIR="$(common-objpfx)"
+CMD_FILE="$(common-objpfx)debugglibc.gdb"
+DIRECT=true
+SYMBOLSFILE=true
+unset TESTCASE
+unset BREAKPOINTS
+unset ENVVARS
+
+usage()
+{
+cat << EOF
+Usage: $$0 [OPTIONS] <testcase>
+
+  where <testcase> is the path to the program being tested.
+
+Options:
+
+  -h, --help
+	Prints this message and leaves.
+
+  The following options require one argument:
+
+  -b, --breakpoint
+	Breakpoints to set at the beginning of the execution
+	(each breakpoint demands its own -b option, e.g. -b foo -b bar)
+  -e, --environment-variable
+	Environment variables to be set with 'exec-wrapper env' in GDB
+	(each environment variable demands its own -e option, e.g.
+	-e FOO=foo -e BAR=bar)
+
+  The following options do not take arguments:
+
+  -i, --no-direct
+	Selects whether to pass the flag --direct to gdb.
+	Required for glibc test cases and not allowed for non-glibc tests.
+	Default behaviour is to pass the flag --direct to gdb.
+  -s, --no-symbols-file
+	Do not tell GDB to load debug symbols from the testcase.
+EOF
+}
+
+# Parse input options
+while [[ $$# > 0 ]]
+do
+  key="$$1"
+  case $$key in
+    -h|--help)
+      usage
+      exit 0
+      ;;
+    -b|--breakpoint)
+      BREAKPOINTS="break $$2\n$$BREAKPOINTS"
+      shift
+      ;;
+    -e|--environment-variable)
+      ENVVARS="$$2 $$ENVVARS"
+      shift
+      ;;
+    -i|--no-direct)
+      DIRECT=false
+      ;;
+    -s|--no-symbols-file)
+      SYMBOLSFILE=false
+      ;;
+    *)
+      TESTCASE=$$1
+      ;;
+  esac
+  shift
+done
+
+# Check for required argument
+if [ ! -v TESTCASE ]
+then
+  usage
+  exit 1
+fi
+
+# Expand environment setup command
+if [ -v ENVVARS ]
+then
+  ENVVARSCMD="set exec-wrapper env $$ENVVARS"
+fi
+
+# Expand direct argument
+if [ "$$DIRECT" == true ]
+then
+  DIRECT="--direct"
+else
+  DIRECT=""
+fi
+
+# Expand symbols loading command
+if [ "$$SYMBOLSFILE" == true ]
+then
+  SYMBOLSFILE="add-symbol-file $${TESTCASE}"
+else
+  SYMBOLSFILE=""
+fi
+
+# GDB commands template
+template ()
+{
+cat <<EOF
+set environment C -E -x c-header
+set auto-load safe-path $${BUILD_DIR}/nptl_db:\$$debugdir:\$$datadir/auto-load
+set libthread-db-search-path $${BUILD_DIR}/nptl_db
+__ENVVARS__
+__SYMBOLSFILE__
+break _dl_start_user
+run --library-path $(rpath-link):$${BUILD_DIR}/nptl_db \
+__TESTCASE__ __DIRECT__
+__BREAKPOINTS__
+EOF
+}
+
+# Generate the commands file for gdb initialization
+template | sed \
+  -e "s|__ENVVARS__|$$ENVVARSCMD|" \
+  -e "s|__SYMBOLSFILE__|$$SYMBOLSFILE|" \
+  -e "s|__TESTCASE__|$$TESTCASE|" \
+  -e "s|__DIRECT__|$$DIRECT|" \
+  -e "s|__BREAKPOINTS__|$$BREAKPOINTS|" \
+  > $$CMD_FILE
+
+echo
+echo "Debugging glibc..."
+echo "Build directory  : $$BUILD_DIR"
+echo "Source directory : $$SOURCE_DIR"
+echo "GLIBC Testcase   : $$TESTCASE"
+echo "GDB Commands     : $$CMD_FILE"
+echo "Env vars         : $$ENVVARS"
+echo
+
+# Start the test case debugging in two steps:
+#   1. the following command invokes gdb to run the loader;
+#   2. the commands file tells the loader to run the test case.
+gdb -q \
+  -x $${CMD_FILE} \
+  -d $${SOURCE_DIR} \
+  $${BUILD_DIR}/elf/ld.so
+endef
+
+# This is another handy script for debugging dynamically linked program
+# against the current libc build for testing.
+$(common-objpfx)debugglibc.sh: $(common-objpfx)config.make \
+			    $(..)Makeconfig $(..)Makefile
+	$(file >$@T,$(debugglibc))
+	chmod a+x $@T
+	mv -f $@T $@
+postclean-generated += debugglibc.sh debugglibc.gdb
+
+others: $(common-objpfx)testrun.sh $(common-objpfx)debugglibc.sh
 
 # Makerules creates a file `stubs' in each subdirectory, which
 # contains `#define __stub_FUNCTION' for each function defined in that