From patchwork Thu Aug 11 15:57:27 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Pedro Alves X-Patchwork-Id: 14498 Received: (qmail 91560 invoked by alias); 11 Aug 2016 15:57:41 -0000 Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org Delivered-To: mailing list gdb-patches@sourceware.org Received: (qmail 91544 invoked by uid 89); 11 Aug 2016 15:57:40 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-2.4 required=5.0 tests=BAYES_00, RP_MATCHES_RCVD, SPF_HELO_PASS autolearn=ham version=3.3.2 spammy=*data, 1370, 13, 70, sk:address X-HELO: mx1.redhat.com Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Thu, 11 Aug 2016 15:57:29 +0000 Received: from int-mx13.intmail.prod.int.phx2.redhat.com (int-mx13.intmail.prod.int.phx2.redhat.com [10.5.11.26]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 9EA27C056791; Thu, 11 Aug 2016 15:57:28 +0000 (UTC) Received: from [127.0.0.1] (ovpn01.gateway.prod.ext.ams2.redhat.com [10.39.146.11]) by int-mx13.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id u7BFvRII014312; Thu, 11 Aug 2016 11:57:27 -0400 Subject: Re: warning: Could not load shared library symbols for linux-vdso.so.1. To: Yao Qi , gdb-patches@sourceware.org References: <86twercyuv.fsf@gmail.com> From: Pedro Alves Message-ID: <89b5bdc8-0be2-538e-3932-1f5d4a1bc1e8@redhat.com> Date: Thu, 11 Aug 2016 16:57:27 +0100 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:45.0) Gecko/20100101 Thunderbird/45.1.1 MIME-Version: 1.0 In-Reply-To: <86twercyuv.fsf@gmail.com> On 08/11/2016 12:46 PM, Yao Qi wrote: > > Hi, > When I test gdb master/7.12 with glibc mainline on aarch64, I got the > following fail, > > (gdb) core-file build-gdb/gdb/testsuite/outputs/gdb.base/corefile/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 > Program terminated with signal SIGABRT, Aborted.^M > #0 __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:58^M > 58 ../sysdeps/unix/sysv/linux/raise.c: No such file or directory.^M > (gdb) FAIL: gdb.base/corefile.exp: core-file warning-free Hmm. gdb.base/vdso-warning.exp was written to expose this even on Fedora/RHEL, but it isn't simply because it doesn't try loading a core dump. > > Looks the warning "Could not load shared library symbols for > linux-vdso.so.1." makes the trouble. It was discussed and fixed in this > thread https://sourceware.org/ml/gdb-patches/2014-09/msg00361.html In > the fix, we filter out the vDSO module if l_ld is in the range of vDSO > module. However, it only works for native live debugging. We can > know the starting address of vDSO by AT_SYSINFO_EHDR, but we don't know > size of vDSO when target is corefile. In my observation, vDSO is _not_ > dumped in corefile at all. > > One version of Pedro's patch uses "(so->lm_info->l_addr_inferior > == vsyscall_addr)" to check whether "so" is vDSO (it works for me in my > fail here), but we changed it to range checking in order to handle > "prelinked" vDSO. I go through the mail thread above, but I don't know > how vDSO is "prelinked". > > Alternatively, we can filter vDSO by name matching, like "", > "linux-vdso.so.1" and "linux-gate.so.1", which was proposed by Doug > too. Is it a good approach to fix this problem? > How about something around this? From a49ac46860c9770dd57812a13f36105361825b01 Mon Sep 17 00:00:00 2001 From: Pedro Alves Date: Thu, 11 Aug 2016 16:04:37 +0100 Subject: [PATCH] Make vDSO detection work with core files - Make gdb.base/vdso-warning.exp test loading a core. With LD_DEBUG=unused, we see the warning on systems with local glibc patches as well (Fedora/RHEL). - When debugging a core, we can only tell the starting address of the vDSO. Make that a valid result out of linux_vsyscall_range. - When we can only tell the starting address, do the simpler lm_info->l_addr_inferior check. Older kernels lose, but I don't think older kernels should hold us back. Is there an easy way to check whether we're in the vdso prelinked situation just from doing some address comparisions? I feel like that should be possible, but I didn't think it through. It is is indeed possible, we could alwayy skip the /proc/pid/maps parsing entirely even against live processes, on modern kernels. --- gdb/linux-tdep.c | 22 ++++++---- gdb/solib-svr4.c | 33 +++++++++----- gdb/testsuite/gdb.base/vdso-warning.exp | 76 ++++++++++++++++++++++----------- 3 files changed, 87 insertions(+), 44 deletions(-) diff --git a/gdb/linux-tdep.c b/gdb/linux-tdep.c index ab110b0..6bc7a0d 100644 --- a/gdb/linux-tdep.c +++ b/gdb/linux-tdep.c @@ -2287,16 +2287,21 @@ 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 (¤t_target, AT_SYSINFO_EHDR, &range->start) <= 0) return 0; + /* Alright, we know the starting address. Let's see if we can find + the end address. */ + range->length = 0; + + /* Can't access /proc if debugging a core file, and NT_FILE notes + don't include the vDSO mapping. */ + if (!target_has_execution) + return 1; + /* We need to know the real target PID to access /proc. */ if (current_inferior ()->fake_pid_p) - return 0; - - if (target_auxv_search (¤t_target, AT_SYSINFO_EHDR, &range->start) <= 0) - return 0; + return 1; pid = current_inferior ()->pid; @@ -2330,8 +2335,7 @@ linux_vsyscall_range_raw (struct gdbarch *gdbarch, struct mem_range *range) p++; endaddr = strtoulst (p, &p, 16); range->length = endaddr - addr; - do_cleanups (cleanup); - return 1; + break; } } @@ -2340,7 +2344,7 @@ linux_vsyscall_range_raw (struct gdbarch *gdbarch, struct mem_range *range) else warning (_("unable to open /proc file '%s'"), filename); - return 0; + return 1; } /* Implementation of the "vsyscall_range" gdbarch hook. Handles diff --git a/gdb/solib-svr4.c b/gdb/solib-svr4.c index fe36d45..bd97bd6 100644 --- a/gdb/solib-svr4.c +++ b/gdb/solib-svr4.c @@ -1539,8 +1539,7 @@ svr4_current_sos (void) /* Filter out the vDSO module, if present. Its symbol file would not be found on disk. The vDSO/vsyscall's OBJFILE is instead managed by symfile-mem.c:add_vsyscall_page. */ - if (gdbarch_vsyscall_range (target_gdbarch (), &vsyscall_range) - && vsyscall_range.length != 0) + if (gdbarch_vsyscall_range (target_gdbarch (), &vsyscall_range)) { struct so_list **sop; @@ -1549,14 +1548,14 @@ svr4_current_sos (void) { struct so_list *so = *sop; - /* We can't simply match the vDSO by starting address alone, - because lm_info->l_addr_inferior (and also l_addr) do not - necessarily represent the real starting address of the - ELF if the vDSO's ELF itself is "prelinked". The l_ld - field (the ".dynamic" section of the shared object) - always points at the absolute/resolved address though. - So check whether that address is inside the vDSO's - mapping instead. + /* Simply matching the vDSO by starting address alone might + not work, because lm_info->l_addr_inferior (and also + l_addr) do not necessarily represent the real starting + address of the ELF if the vDSO's ELF itself is + "prelinked". The l_ld field (the ".dynamic" section of + the shared object) always points at the absolute/resolved + address though. So if we know the range, check whether + that address is inside the vDSO's mapping instead. E.g., on Linux 3.16 (x86_64) the vDSO is a regular 0-based ELF, and we see: @@ -1590,7 +1589,19 @@ svr4_current_sos (void) [...] [ 9] .dynamic DYNAMIC ffffffffff700580 000580 0000f0 */ - if (address_in_mem_range (so->lm_info->l_ld, &vsyscall_range)) + if (vsyscall_range.length != 0 + && address_in_mem_range (so->lm_info->l_ld, &vsyscall_range)) + { + *sop = so->next; + free_so (so); + break; + } + + /* However, if we only know the starting address address, + try a simple match. XXX: Is there an easy "SO is + prelinked" check we could do here? */ + if (vsyscall_range.length == 0 + && so->lm_info->l_addr_inferior == vsyscall_range.start) { *sop = so->next; free_so (so); diff --git a/gdb/testsuite/gdb.base/vdso-warning.exp b/gdb/testsuite/gdb.base/vdso-warning.exp index af2b2b0..aeb85a2 100644 --- a/gdb/testsuite/gdb.base/vdso-warning.exp +++ b/gdb/testsuite/gdb.base/vdso-warning.exp @@ -13,42 +13,70 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . +# 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" }