From: Victor Collod Date: Sat, 19 Sep 2020 00:53:02 +0000 (-0700) Subject: gdb: Update i386_analyze_prologue to skip endbr32 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=14f9473ca225290680c8b21240cdca49f8d3b332;p=binutils-gdb.git gdb: Update i386_analyze_prologue to skip endbr32 With -m32 -fcf-protection, GCC generates an `endbr32` instruction at the function entry: [hjl@gnu-cfl-2 gdb]$ cat /tmp/x.c int main(void) { return 0; } [hjl@gnu-cfl-2 gdb]$ gcc -g -fcf-protection /tmp/x.c -m32 (gdb) b main Breakpoint 1 at 0x8049176: file /tmp/x.c, line 3. (gdb) r Breakpoint 1, main () at /tmp/x.c:3 3 { (gdb) disass Dump of assembler code for function main: => 0x08049176 <+0>: endbr32 0x0804917a <+4>: push %ebp 0x0804917b <+5>: mov %esp,%ebp 0x0804917d <+7>: mov $0x0,%eax 0x08049182 <+12>: pop %ebp 0x08049183 <+13>: ret End of assembler dump. (gdb) Update i386_analyze_prologue to skip `endbr32`: (gdb) b main Breakpoint 1 at 0x804917d: file /tmp/x.c, line 4. (gdb) r Breakpoint 1, main () at /tmp/x.c:4 4 return 0; (gdb) disass Dump of assembler code for function main: 0x08049176 <+0>: endbr32 0x0804917a <+4>: push %ebp 0x0804917b <+5>: mov %esp,%ebp => 0x0804917d <+7>: mov $0x0,%eax 0x08049182 <+12>: pop %ebp 0x08049183 <+13>: ret End of assembler dump. (gdb) Tested with $ make check RUNTESTFLAGS="--target_board='unix{-m32,}' i386-prologue-skip-cf-protection.exp" on Fedora 32/x86-64. 2020-0X-YY Victor Collod gdb/ChangeLog: PR gdb/26635 * i386-tdep.c (i386_skip_endbr): Add a helper function to skip endbr. (i386_analyze_prologue): Call i386_skip_endbr. gdb/testsuite/ChangeLog: PR gdb/26635 * gdb.arch/amd64-prologue-skip-cf-protection.exp: Make the test compatible with i386, and move it to... * gdb.arch/i386-prologue-skip-cf-protection.exp: ... here. * gdb.arch/amd64-prologue-skip-cf-protection.c: Move to... * gdb.arch/i386-prologue-skip-cf-protection.c: ... here. --- diff --git a/gdb/ChangeLog b/gdb/ChangeLog index a052d4f5e50..8b010e525f6 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,9 @@ +2020-09-18 Victor Collod + + PR gdb/26635 + * i386-tdep.c (i386_skip_endbr): Add a helper function to skip endbr. + (i386_analyze_prologue): Call i386_skip_endbr. + 2020-09-18 Tom Tromey * windows-nat.c (struct windows_nat_target) : Update. diff --git a/gdb/i386-tdep.c b/gdb/i386-tdep.c index 95cfe5b820e..b485f0b296a 100644 --- a/gdb/i386-tdep.c +++ b/gdb/i386-tdep.c @@ -1538,6 +1538,24 @@ struct i386_insn i386_frame_setup_skip_insns[] = { 0 } }; +/* Check whether PC points to an endbr32 instruction. */ +static CORE_ADDR +i386_skip_endbr (CORE_ADDR pc) +{ + static const gdb_byte endbr32[] = { 0xf3, 0x0f, 0x1e, 0xfb }; + + gdb_byte buf[sizeof (endbr32)]; + + /* Stop there if we can't read the code */ + if (target_read_code (pc, buf, sizeof (endbr32))) + return pc; + + /* If the instruction isn't an endbr32, stop */ + if (memcmp (buf, endbr32, sizeof (endbr32)) != 0) + return pc; + + return pc + sizeof (endbr32); +} /* Check whether PC points to a no-op instruction. */ static CORE_ADDR @@ -1815,6 +1833,7 @@ i386_analyze_prologue (struct gdbarch *gdbarch, CORE_ADDR pc, CORE_ADDR current_pc, struct i386_frame_cache *cache) { + pc = i386_skip_endbr (pc); pc = i386_skip_noop (pc); pc = i386_follow_jump (gdbarch, pc); pc = i386_analyze_struct_return (pc, current_pc, cache); diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index ef4006bff6f..b7c1ce81d58 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,12 @@ +2020-09-18 Victor Collod + + PR gdb/26635 + * gdb.arch/amd64-prologue-skip-cf-protection.exp: Make the test + compatible with i386, and move it to... + * gdb.arch/i386-prologue-skip-cf-protection.exp: ... here. + * gdb.arch/amd64-prologue-skip-cf-protection.c: Move to... + * gdb.arch/i386-prologue-skip-cf-protection.c: ... here. + 2020-09-18 Pedro Alves PR gdb/26631 diff --git a/gdb/testsuite/gdb.arch/amd64-prologue-skip-cf-protection.c b/gdb/testsuite/gdb.arch/amd64-prologue-skip-cf-protection.c deleted file mode 100644 index a6505857e17..00000000000 --- a/gdb/testsuite/gdb.arch/amd64-prologue-skip-cf-protection.c +++ /dev/null @@ -1,21 +0,0 @@ -/* This testcase is part of GDB, the GNU debugger. - - Copyright 2020 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 . */ - -int main (void) -{ - return 0; -} diff --git a/gdb/testsuite/gdb.arch/amd64-prologue-skip-cf-protection.exp b/gdb/testsuite/gdb.arch/amd64-prologue-skip-cf-protection.exp deleted file mode 100644 index 3c51fd30352..00000000000 --- a/gdb/testsuite/gdb.arch/amd64-prologue-skip-cf-protection.exp +++ /dev/null @@ -1,65 +0,0 @@ -# Copyright 2020 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 . - -# Test skipping a prologue that was generated with gcc's -fcf-protection=full -# (control flow protection) option. -# -# This option places an `endbr64` instruction at the start of all functions, -# which can interfere with prologue analysis. - -standard_testfile .c -set binfile ${binfile} - -if { ![istarget x86_64-*-* ] || ![is_lp64_target] } { - verbose "Skipping ${testfile}." - return -} - -if { ![supports_fcf_protection] } { - untested "-fcf-protection not supported" - return -} - -set opts {debug additional_flags=-fcf-protection=full} - -if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable $opts] != "" } { - untested "failed to compile" - return -} - -clean_restart ${binfile} - -# Get start address of function main. -set main_addr [get_integer_valueof &main -1] -gdb_assert {$main_addr != -1} - -set bp_addr -1 - -# Put breakpoint on main, get the address where the breakpoint was installed. -gdb_test_multiple "break main" "break on main, get address" { - -re -wrap "Breakpoint $decimal at ($hex).*" { - set bp_addr $expect_out(1,string) - - # Convert to decimal. - set bp_addr [expr $bp_addr] - - pass $gdb_test_name - } -} - -if { $bp_addr != -1 } { - # Make sure some prologue was skipped. - gdb_assert {$bp_addr > $main_addr} -} diff --git a/gdb/testsuite/gdb.arch/i386-prologue-skip-cf-protection.c b/gdb/testsuite/gdb.arch/i386-prologue-skip-cf-protection.c new file mode 100644 index 00000000000..a6505857e17 --- /dev/null +++ b/gdb/testsuite/gdb.arch/i386-prologue-skip-cf-protection.c @@ -0,0 +1,21 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2020 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 . */ + +int main (void) +{ + return 0; +} diff --git a/gdb/testsuite/gdb.arch/i386-prologue-skip-cf-protection.exp b/gdb/testsuite/gdb.arch/i386-prologue-skip-cf-protection.exp new file mode 100644 index 00000000000..9ba64f9c375 --- /dev/null +++ b/gdb/testsuite/gdb.arch/i386-prologue-skip-cf-protection.exp @@ -0,0 +1,65 @@ +# Copyright 2020 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 . + +# Test skipping a prologue that was generated with gcc's -fcf-protection=full +# (control flow protection) option. +# +# This option places an `endbr32`/`endbr64` instruction at the start of +# all functions, which can interfere with prologue analysis. + +standard_testfile .c +set binfile ${binfile} + +if { ![istarget x86_64-*-*] && ![istarget i?86-*-*] } { + verbose "Skipping ${testfile}." + return +} + +if { ![supports_fcf_protection] } { + untested "-fcf-protection not supported" + return +} + +set opts {debug additional_flags=-fcf-protection=full} + +if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable $opts] != "" } { + untested "failed to compile" + return +} + +clean_restart ${binfile} + +# Get start address of function main. +set main_addr [get_integer_valueof &main -1] +gdb_assert {$main_addr != -1} + +set bp_addr -1 + +# Put breakpoint on main, get the address where the breakpoint was installed. +gdb_test_multiple "break main" "break on main, get address" { + -re -wrap "Breakpoint $decimal at ($hex).*" { + set bp_addr $expect_out(1,string) + + # Convert to decimal. + set bp_addr [expr $bp_addr] + + pass $gdb_test_name + } +} + +if { $bp_addr != -1 } { + # Make sure some prologue was skipped. + gdb_assert {$bp_addr > $main_addr} +}