From patchwork Mon Aug 5 10:56:57 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Tom de Vries X-Patchwork-Id: 33963 Received: (qmail 55361 invoked by alias); 5 Aug 2019 10:57:02 -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 55352 invoked by uid 89); 5 Aug 2019 10:57:01 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-26.1 required=5.0 tests=AWL, BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, SPF_PASS autolearn=ham version=3.3.1 spammy=am, dictate, 85 X-HELO: mx1.suse.de Received: from mx2.suse.de (HELO mx1.suse.de) (195.135.220.15) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Mon, 05 Aug 2019 10:57:00 +0000 Received: from relay2.suse.de (unknown [195.135.220.254]) by mx1.suse.de (Postfix) with ESMTP id 27E58B009; Mon, 5 Aug 2019 10:56:58 +0000 (UTC) Subject: [committed][gdb/testsuite] Fail in gdb_compile if pie results in non-PIE executable To: Simon Marchi , Alan Hayward Cc: "gdb-patches@sourceware.org" , nd References: <20190723072210.GA24180@delia> <38ad4652-bc03-5873-0d2c-6f8c1561d313@simark.ca> From: Tom de Vries Openpgp: preference=signencrypt Message-ID: <03d77f4d-9c7d-6ab3-df87-90723512cc4c@suse.de> Date: Mon, 5 Aug 2019 12:56:57 +0200 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Thunderbird/60.8.0 MIME-Version: 1.0 In-Reply-To: <38ad4652-bc03-5873-0d2c-6f8c1561d313@simark.ca> X-IsSubscribed: yes [ was: Re: [PATCH][gdb/testsuite] Fail in gdb_compile if nopie results in PIE executable ] On 30-07-19 03:20, Simon Marchi wrote: > On 2019-07-29 5:57 a.m., Alan Hayward wrote: >>> OK for trunk? >> >> LGTM (but I’m not a global maintainer). >> >> I tried this on an Ubuntu18.04 (which defaults gcc to use PIE), and everything >> looks fine. > Thanks, LGTM too, please push. Hi, this follow-up patch deals with the opposite: Fail in gdb_compile if pie results in non-PIE executable. Thanks, - Tom [gdb/testsuite] Fail in gdb_compile if pie results in non-PIE executable When running gdb.base/break-idempotent.exp with --target_board=unix/-fno-PIE/-no-pie, we get: ... nr of expected passes 140 ... The test-case is compiled once with nopie and once with pie, but in both cases we end up with a non-PIE executable. The "-fno-PIE -no-pie" options specified using the target_board are interpreted by dejagnu as multilib_flags, and end up overriding the pie flags. Fix this by checking in gdb_compile if the resulting exec is non-PIE despite of a pie setting, and if so return an error: ... Running gdb/testsuite/gdb.base/break-idempotent.exp ... gdb compile failed, pie failed to generate PIE executable === gdb Summary === nr of expected passes 70 nr of untested testcases 1 ... Tested on x86_64-linux. gdb/testsuite/ChangeLog: 2019-08-05 Tom de Vries * lib/gdb.exp (version_at_least): Factor out of ... (tcl_version_at_least): ... here. (gdb_compile): Fail if pie results in non-PIE executable. (readelf_version, readelf_prints_pie): New proc. (exec_is_pie): Return -1 if unknown. --- gdb/testsuite/lib/gdb.exp | 78 ++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 64 insertions(+), 14 deletions(-) diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp index 6d16217f3b..529b6f6030 100644 --- a/gdb/testsuite/lib/gdb.exp +++ b/gdb/testsuite/lib/gdb.exp @@ -1103,21 +1103,27 @@ proc gdb_test { args } { }] } -# Return 1 if tcl version used is at least MAJOR.MINOR -proc tcl_version_at_least { major minor } { - global tcl_version - regexp {^([0-9]+)\.([0-9]+)$} $tcl_version \ - dummy tcl_version_major tcl_version_minor - if { $tcl_version_major > $major } { +# Return 1 if version MAJOR.MINOR is at least AT_LEAST_MAJOR.AT_LEAST_MINOR. +proc version_at_least { major minor at_least_major at_least_minor} { + if { $major > $at_least_major } { return 1 - } elseif { $tcl_version_major == $major \ - && $tcl_version_minor >= $minor } { + } elseif { $major == $at_least_major \ + && $minor >= $at_least_minor } { return 1 } else { return 0 } } +# Return 1 if tcl version used is at least MAJOR.MINOR +proc tcl_version_at_least { major minor } { + global tcl_version + regexp {^([0-9]+)\.([0-9]+)$} $tcl_version \ + dummy tcl_version_major tcl_version_minor + return [version_at_least $tcl_version_major $tcl_version_minor \ + $major $minor] +} + if { [tcl_version_at_least 8 5] == 0 } { # lrepeat was added in tcl 8.5. Only add if missing. proc lrepeat { n element } { @@ -3803,9 +3809,13 @@ proc gdb_compile {source dest type options} { regsub "\[\r\n\]*$" "$result" "" result regsub "^\[\r\n\]*" "$result" "" result - if { $type == "executable" && $result == "" && $nopie != -1 } { - if { [exec_is_pie "$dest"] } { + if { $type == "executable" && $result == "" \ + && ($nopie != -1 || $pie != -1) } { + set is_pie [exec_is_pie "$dest"] + if { $nopie != -1 && $is_pie == 1 } { set result "nopie failed to prevent PIE executable" + } elseif { $pie != -1 && $is_pie == 0 } { + set result "pie failed to generate PIE executable" } } @@ -5209,13 +5219,53 @@ proc exec_has_index_section { executable } { return 0 } -# Return true if EXECUTABLE is a Position Independent Executable. +# Return list with major and minor version of readelf, or an empty list. +gdb_caching_proc readelf_version { + set readelf_program [gdb_find_readelf] + set res [catch {exec $readelf_program --version} output] + if { $res != 0 } { + return [list] + } + set lines [split $output \n] + set line [lindex $lines 0] + set res [regexp {[ \t]+([0-9]+)[.]([0-9]+)[^ \t]*$} \ + $line dummy major minor] + if { $res != 1 } { + return [list] + } + return [list $major $minor] +} + +# Return 1 if readelf prints the PIE flag, 0 if is doesn't, and -1 if unknown. +proc readelf_prints_pie { } { + set version [readelf_version] + if { [llength $version] == 0 } { + return -1 + } + set major [lindex $version 0] + set minor [lindex $version 1] + # It would be better to construct a PIE executable and test if the PIE + # flag is printed by readelf, but we cannot reliably construct a PIE + # executable if the multilib_flags dictate otherwise + # (--target_board=unix/-no-pie/-fno-PIE). + return [version_at_least $major $minor 2 26] +} + +# Return 1 if EXECUTABLE is a Position Independent Executable, 0 if it is not, +# and -1 if unknown. proc exec_is_pie { executable } { + set res [readelf_prints_pie] + if { $res != 1 } { + return -1 + } set readelf_program [gdb_find_readelf] - set res [catch {exec $readelf_program -d $executable \ - | grep -E "(FLAGS_1).*Flags:.* PIE($| )" }] - if { $res == 0 } { + set res [catch {exec $readelf_program -d $executable} output] + if { $res != 0 } { + return -1 + } + set res [regexp -line {\(FLAGS_1\).*Flags:.* PIE($| )} $output] + if { $res == 1 } { return 1 } return 0