Fix PR gdb/20505 - Make vDSO detection work with core files
authorPedro Alves <palves@redhat.com>
Mon, 22 Aug 2016 19:05:09 +0000 (20:05 +0100)
committerPedro Alves <palves@redhat.com>
Mon, 22 Aug 2016 19:05:09 +0000 (20:05 +0100)
Loading a core dump that was either generated on a system running
pristine glibc master, or on a Fedora/RHEL system with LD_DEBUG=unused
set in the environment, solib-svr4.c:svr4_current_sos fails to filter
out the vDSO, resulting in:

  (gdb) core-file corefile.core^M
  [New LWP 2362]^M
  warning: Could not load shared library symbols for linux-vdso.so.1.^M
  Do you need "set solib-search-path" or "set sysroot"?^M
  Core was generated by `build-gdb/gdb/testsuite/outputs/gdb.base/corefile/'.^M
  ...

The problem is that gdbarch_vsyscall_range does not support core
inferiors at all.

When live debugging, we're finding the vDSO's start address with
auxv/AT_SYSINFO_EHDR, and then we find the vDSO's size by look for the
corresponding mapping, by parsing /proc/PID/maps.  When debugging a
core dump, we can also determine the starting address from
auxv/AT_SYSINFO_EHDR.  However, we obviously can't read the core
mappings out of the host's /proc.  But we can instead look for a
corresponding load segment in the core's bfd.

gdb/ChangeLog:
2016-08-22  Pedro Alves  <palves@redhat.com>

PR gdb/20505
* linux-tdep.c (linux_vsyscall_range_raw): For core inferiors,
find the vDSO's start address with AT_SYSINFO_EHDR too, and
determine the vDSO's size by finding the PT_LOAD segment that
matches AT_SYSINFO_EHDR.

gdb/testsuite/ChangeLog:
2016-08-22  Pedro Alves  <palves@redhat.com>

PR gdb/20505
* gdb.base/vdso-warning.exp: Test core dumps too.  Use
with_test_prefix.  Factor out bits to ...
(test_no_vdso): ... this new procedure.

gdb/ChangeLog
gdb/linux-tdep.c
gdb/testsuite/ChangeLog
gdb/testsuite/gdb.base/vdso-warning.exp

index db3527bf30219553a08220609f22ac06e6ae869e..8de59d0969c9e5a28f14a46cdaeef77c8eda0673 100644 (file)
@@ -1,3 +1,11 @@
+2016-08-22  Pedro Alves  <palves@redhat.com>
+
+       PR gdb/20505
+       * linux-tdep.c (linux_vsyscall_range_raw): For core inferiors,
+       find the vDSO's start address with AT_SYSINFO_EHDR too, and
+       determine the vDSO's size by finding the PT_LOAD segment that
+       matches AT_SYSINFO_EHDR.
+
 2016-08-19  Yao Qi  <yao.qi@linaro.org>
 
        * aarch64-tdep.c (aarch64_analyze_prologue): Handle register
index ab110b0a6872b8e479430ada961dd252e444f801..718dc1ab6620f5ae5099c12f13de654f10c0d87b 100644 (file)
@@ -2287,17 +2287,42 @@ linux_vsyscall_range_raw (struct gdbarch *gdbarch, struct mem_range *range)
   long pid;
   char *data;
 
-  /* Can't access /proc if debugging a core file.  */
-  if (!target_has_execution)
+  if (target_auxv_search (&current_target, AT_SYSINFO_EHDR, &range->start) <= 0)
     return 0;
 
+  /* It doesn't make sense to access the host's /proc when debugging a
+     core file.  Instead, look for the PT_LOAD segment that matches
+     the vDSO.  */
+  if (!target_has_execution)
+    {
+      Elf_Internal_Phdr *phdrs;
+      long phdrs_size;
+      int num_phdrs, i;
+
+      phdrs_size = bfd_get_elf_phdr_upper_bound (core_bfd);
+      if (phdrs_size == -1)
+       return 0;
+
+      phdrs = (Elf_Internal_Phdr *) alloca (phdrs_size);
+      num_phdrs = bfd_get_elf_phdrs (core_bfd, phdrs);
+      if (num_phdrs == -1)
+       return 0;
+
+      for (i = 0; i < num_phdrs; i++)
+       if (phdrs[i].p_type == PT_LOAD
+           && phdrs[i].p_vaddr == range->start)
+         {
+           range->length = phdrs[i].p_memsz;
+           return 1;
+         }
+
+      return 0;
+    }
+
   /* We need to know the real target PID to access /proc.  */
   if (current_inferior ()->fake_pid_p)
     return 0;
 
-  if (target_auxv_search (&current_target, AT_SYSINFO_EHDR, &range->start) <= 0)
-    return 0;
-
   pid = current_inferior ()->pid;
 
   /* Note that reading /proc/PID/task/PID/maps (1) is much faster than
index 9f45c39654974be3e64c2678acb5a716d4f925c5..7e5fce6a1ac8c5354453498339dc1d45646956d1 100644 (file)
@@ -1,3 +1,10 @@
+2016-08-22  Pedro Alves  <palves@redhat.com>
+
+       PR gdb/20505
+       * gdb.base/vdso-warning.exp: Test core dumps too.  Use
+       with_test_prefix.  Factor out bits to ...
+       (test_no_vdso): ... this new procedure.
+
 2016-08-19  Carl Love  <cel@us.ibm.com>
 
        * gdb.arch/altivec-regs.exp: Use standard_testfile instead of
index af2b2b0e67aeab0541732b2a2d1f1409d2888551..aeb85a2a6030444d671b6f01022c3cb15e393123 100644 (file)
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
+# Test that on Linux, we don't warn about not finding the vDSO.  E.g.:
+#
+#   warning: Could not load shared library symbols for linux-vdso.so.1.
+
 standard_testfile
 
 if { [prepare_for_testing "failed to prepare" ${testfile} $srcfile] } {
     return -1
 }
 
-gdb_breakpoint "main"
+with_test_prefix "setup" {
+    gdb_breakpoint "main"
 
-# At least some versions of Fedora/RHEL glibc have local patches that
-# hide the vDSO.  This lines re-exposes it.  See PR libc/13097,
-# comment 2.  There's no support for passing environment variables in
-# the remote protocol, but that's OK -- if we're testing against a
-# glibc that doesn't list the vDSO without this, the test should still
-# pass.
-gdb_test_no_output "set environment LD_DEBUG=unused"
+    # At least some versions of Fedora/RHEL glibc have local patches that
+    # hide the vDSO.  This lines re-exposes it.  See PR libc/13097,
+    # comment 2.  There's no support for passing environment variables in
+    # the remote protocol, but that's OK -- if we're testing against a
+    # glibc that doesn't list the vDSO without this, the test should still
+    # pass.
+    gdb_test_no_output "set environment LD_DEBUG=unused"
+}
 
-gdb_run_cmd
+proc test_no_vdso {command} {
+    global srcfile
+    global gdb_prompt
 
-set test "stop without warning"
-gdb_test_multiple "" $test {
-    -re "Could not load shared library symbols .*\r\n$gdb_prompt $" {
-       fail $test
+    set message "startup"
+    gdb_test_multiple "$command" $message {
+       -re "Could not load shared library symbols .*\r\n$gdb_prompt $" {
+           fail $message
+       }
+       -re "main \\(\\) at .*$srcfile.*\r\n$gdb_prompt $" {
+           pass $message
+       }
     }
-    -re "\r\nBreakpoint \[0-9\]+, main .*\r\n$gdb_prompt $" {
-       pass $test
+
+    # Extra testing in case the warning changes and we miss updating
+    # the above.
+    set test "no vdso without symbols is listed"
+    gdb_test_multiple "info shared" $test {
+       -re "No\[^\r\n\]+linux-(vdso|gate).*$gdb_prompt $" {
+           fail $test
+       }
+       -re "$gdb_prompt $" {
+           pass $test
+       }
     }
 }
 
-# Extra testing in case the warning changes and we miss updating the
-# above.
-set test "no vdso without symbols is listed"
-gdb_test_multiple "info shared" $test {
-    -re "No\[^\r\n\]+linux-(vdso|gate).*$gdb_prompt $" {
-       fail $test
-    }
-    -re "$gdb_prompt $" {
-       pass $test
+# First, try a live process.
+with_test_prefix "run" {
+    gdb_run_cmd
+    test_no_vdso ""
+}
+
+# Now, dump a core, and reload it.
+with_test_prefix "core" {
+    set corefile [standard_output_file $testfile.core]
+    set core_supported [gdb_gcore_cmd "$corefile" "save a corefile"]
+    if {!$core_supported} {
+       return -1
     }
+
+    clean_restart ${testfile}
+
+    test_no_vdso "core-file $corefile"
 }