diff options
author | Markus Metzger <markus.t.metzger@intel.com> | 2018-02-14 14:30:57 +0100 |
---|---|---|
committer | Markus Metzger <markus.t.metzger@intel.com> | 2018-04-13 10:44:47 +0200 |
commit | 1d509aa625f891e20b37b8cee4659771e87b1ba4 (patch) | |
tree | fe552af320ac898cabcfaa37c709e324b3c96b25 /gdb/testsuite/gdb.base/step-indirect-call-thunk.exp | |
parent | 7a2711e437c50041c0a83761a90ea5e6c9ad8b98 (diff) | |
download | fsf-binutils-gdb-1d509aa625f891e20b37b8cee4659771e87b1ba4.zip fsf-binutils-gdb-1d509aa625f891e20b37b8cee4659771e87b1ba4.tar.gz fsf-binutils-gdb-1d509aa625f891e20b37b8cee4659771e87b1ba4.tar.bz2 |
infrun: step through indirect branch thunks
With version 7.3 GCC supports new options
-mindirect-branch=<choice>
-mfunction-return=<choice>
The choices are:
keep behaves as before
thunk jumps through a thunk
thunk-external jumps through an external thunk
thunk-inline jumps through an inlined thunk
For thunk and thunk-external, GDB would, on a call to the thunk, step into
the thunk and then resume to its caller assuming that this is an
undebuggable function. On a return thunk, GDB would stop inside the
thunk.
Make GDB step through such thunks instead.
Before:
Temporary breakpoint 1, main ()
at gdb.base/step-indirect-call-thunk.c:37
37 x = apply (inc, 41);
(gdb) s
apply (op=0x80483e6 <inc>, x=41)
at gdb.base/step-indirect-call-thunk.c:29
29 return op (x);
(gdb)
30 }
After:
Temporary breakpoint 1, main ()
at gdb.base/step-indirect-call-thunk.c:37
37 x = apply (inc, 41);
(gdb) s
apply (op=0x80483e6 <inc>, x=41)
at gdb.base/step-indirect-call-thunk.c:29
29 return op (x);
(gdb)
inc (x=41) at gdb.base/step-indirect-call-thunk.c:23
23 return x + 1;
This is independent of the step-mode. In order to step into the thunk,
you would need to use stepi.
When stepping over an indirect call thunk, GDB would first step through
the thunk, then recognize that it stepped into a sub-routine and resume to
the caller (of the thunk). Not sure whether this is worth optimizing.
Thunk detection is implemented via gdbarch. I implemented the methods for
IA. Other architectures may run into unexpected fails.
The tests assume a fixed number of instruction steps to reach a thunk.
This depends on the compiler as well as the architecture. They may need
adjustments when we add support for more architectures. Or we can simply
drop those tests that cover being able to step into thunks using
instruction stepping.
When using an older GCC, the tests will fail to build and will be reported
as untested:
Running .../gdb.base/step-indirect-call-thunk.exp ...
gdb compile failed, \
gcc: error: unrecognized command line option '-mindirect-branch=thunk'
gcc: error: unrecognized command line option '-mfunction-return=thunk'
=== gdb Summary ===
# of untested testcases 1
gdb/
* infrun.c (process_event_stop_test): Call
gdbarch_in_indirect_branch_thunk.
* gdbarch.sh (in_indirect_branch_thunk): New.
* gdbarch.c: Regenerated.
* gdbarch.h: Regenerated.
* x86-tdep.h: New.
* x86-tdep.c: New.
* Makefile.in (ALL_TARGET_OBS): Add x86-tdep.o.
(HFILES_NO_SRCDIR): Add x86-tdep.h.
(ALLDEPFILES): Add x86-tdep.c.
* arch-utils.h (default_in_indirect_branch_thunk): New.
* arch-utils.c (default_in_indirect_branch_thunk): New.
* i386-tdep: Include x86-tdep.h.
(i386_in_indirect_branch_thunk): New.
(i386_elf_init_abi): Set in_indirect_branch_thunk gdbarch
function.
* amd64-tdep: Include x86-tdep.h.
(amd64_in_indirect_branch_thunk): New.
(amd64_init_abi): Set in_indirect_branch_thunk gdbarch function.
testsuite/
* gdb.base/step-indirect-call-thunk.exp: New.
* gdb.base/step-indirect-call-thunk.c: New.
* gdb.reverse/step-indirect-call-thunk.exp: New.
* gdb.reverse/step-indirect-call-thunk.c: New.
Diffstat (limited to 'gdb/testsuite/gdb.base/step-indirect-call-thunk.exp')
-rw-r--r-- | gdb/testsuite/gdb.base/step-indirect-call-thunk.exp | 73 |
1 files changed, 73 insertions, 0 deletions
diff --git a/gdb/testsuite/gdb.base/step-indirect-call-thunk.exp b/gdb/testsuite/gdb.base/step-indirect-call-thunk.exp new file mode 100644 index 0000000..baeb6d6 --- /dev/null +++ b/gdb/testsuite/gdb.base/step-indirect-call-thunk.exp @@ -0,0 +1,73 @@ +# Copyright 2018 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 <http://www.gnu.org/licenses/>. + +standard_testfile + +set cflags "-mindirect-branch=thunk -mfunction-return=thunk" +if { [prepare_for_testing "failed to prepare" $testfile $srcfile \ + [list debug "additional_flags=$cflags"]] } { + return -1 +} + +if { ![runto_main] } { + untested "failed to run to main" + return -1 +} + +# Do repeated instruction steps in order to reach TARGET from CURRENT +# +# CURRENT is a string matching the current location +# TARGET is a string matching the target location +# TEST is the test name +# +# The function issues repeated "stepi" commands as long as the location +# matches CURRENT up to a maximum of 100 steps. +# +# TEST passes if the resulting location matches TARGET and fails +# otherwise. +# +proc stepi_until { current target test } { + global gdb_prompt + + set count 0 + gdb_test_multiple "stepi" "$test" { + -re "$current.*$gdb_prompt $" { + incr count + if { $count < 100 } { + send_gdb "stepi\n" + exp_continue + } else { + fail "$test" + } + } + -re "$target.*$gdb_prompt $" { + pass "$test" + } + } +} + +# Normal stepping steps through all thunks. +gdb_test "step" "thrice\.2.*" "step into thrice" +gdb_test "next" "thrice\.3.*" "step through thunks and over inc" +gdb_test "step" "inc\.2.*" "step through call thunk into inc" +gdb_test "step" "inc\.3.*" "step inside inc" +gdb_test "step" "thrice\.4.*" "step through return thunk back into thrice" + +# We can use instruction stepping to step into thunks. +stepi_until "thrice" "indirect_thunk" "stepi into call thunk" +stepi_until "indirect_thunk" "inc." "stepi out of call thunk into inc" +stepi_until "inc" "return_thunk" "stepi into return thunk" +stepi_until "return_thunk" "thrice" \ + "stepi out of return thunk back into thrice" |