diff options
-rw-r--r-- | gdb/ChangeLog | 22 | ||||
-rw-r--r-- | gdb/Makefile.in | 5 | ||||
-rw-r--r-- | gdb/amd64-tdep.c | 14 | ||||
-rw-r--r-- | gdb/arch-utils.c | 8 | ||||
-rw-r--r-- | gdb/arch-utils.h | 5 | ||||
-rw-r--r-- | gdb/gdbarch.c | 23 | ||||
-rw-r--r-- | gdb/gdbarch.h | 6 | ||||
-rwxr-xr-x | gdb/gdbarch.sh | 3 | ||||
-rw-r--r-- | gdb/i386-tdep.c | 13 | ||||
-rw-r--r-- | gdb/infrun.c | 11 | ||||
-rw-r--r-- | gdb/testsuite/ChangeLog | 7 | ||||
-rw-r--r-- | gdb/testsuite/gdb.base/step-indirect-call-thunk.c | 42 | ||||
-rw-r--r-- | gdb/testsuite/gdb.base/step-indirect-call-thunk.exp | 73 | ||||
-rw-r--r-- | gdb/testsuite/gdb.reverse/step-indirect-call-thunk.c | 36 | ||||
-rw-r--r-- | gdb/testsuite/gdb.reverse/step-indirect-call-thunk.exp | 100 | ||||
-rw-r--r-- | gdb/x86-tdep.c | 76 | ||||
-rw-r--r-- | gdb/x86-tdep.h | 30 |
17 files changed, 473 insertions, 1 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 1141a1d..f379680 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,25 @@ +2018-04-13 Markus Metzger <markus.t.metzger@intel.com> + + * 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. + 2018-04-12 Jan Kratochvil <jan.kratochvil@redhat.com> PR gdb/23053 diff --git a/gdb/Makefile.in b/gdb/Makefile.in index e885dca..40c9f89 100644 --- a/gdb/Makefile.in +++ b/gdb/Makefile.in @@ -793,6 +793,7 @@ ALL_TARGET_OBS = \ vax-nbsd-tdep.o \ vax-tdep.o \ windows-tdep.o \ + x86-tdep.o \ xcoffread.o \ xstormy16-tdep.o \ xtensa-config.o \ @@ -1521,7 +1522,8 @@ HFILES_NO_SRCDIR = \ tui/tui-win.h \ tui/tui-windata.h \ tui/tui-wingeneral.h \ - tui/tui-winsource.h + tui/tui-winsource.h \ + x86-tdep.h # Header files that already have srcdir in them, or which are in objdir. @@ -2363,6 +2365,7 @@ ALLDEPFILES = \ windows-nat.c \ windows-tdep.c \ x86-nat.c \ + x86-tdep.c \ xcoffread.c \ xstormy16-tdep.c \ xtensa-config.c \ diff --git a/gdb/amd64-tdep.c b/gdb/amd64-tdep.c index bceb6e1..1fea264 100644 --- a/gdb/amd64-tdep.c +++ b/gdb/amd64-tdep.c @@ -48,6 +48,7 @@ #include "ax-gdb.h" #include "common/byte-vector.h" #include "osabi.h" +#include "x86-tdep.h" /* Note that the AMD64 architecture was previously known as x86-64. The latter is (forever) engraved into the canonical system name as @@ -3034,6 +3035,16 @@ static const int amd64_record_regmap[] = AMD64_DS_REGNUM, AMD64_ES_REGNUM, AMD64_FS_REGNUM, AMD64_GS_REGNUM }; +/* Implement the "in_indirect_branch_thunk" gdbarch function. */ + +static bool +amd64_in_indirect_branch_thunk (struct gdbarch *gdbarch, CORE_ADDR pc) +{ + return x86_in_indirect_branch_thunk (pc, amd64_register_names, + AMD64_RAX_REGNUM, + AMD64_RIP_REGNUM); +} + void amd64_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch, const target_desc *default_tdesc) @@ -3206,6 +3217,9 @@ amd64_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch, set_gdbarch_insn_is_call (gdbarch, amd64_insn_is_call); set_gdbarch_insn_is_ret (gdbarch, amd64_insn_is_ret); set_gdbarch_insn_is_jump (gdbarch, amd64_insn_is_jump); + + set_gdbarch_in_indirect_branch_thunk (gdbarch, + amd64_in_indirect_branch_thunk); } /* Initialize ARCH for x86-64, no osabi. */ diff --git a/gdb/arch-utils.c b/gdb/arch-utils.c index 5986ed6..cd9bd66 100644 --- a/gdb/arch-utils.c +++ b/gdb/arch-utils.c @@ -979,6 +979,14 @@ gdbarch_skip_prologue_noexcept (gdbarch *gdbarch, CORE_ADDR pc) noexcept return new_pc; } +/* See arch-utils.h. */ + +bool +default_in_indirect_branch_thunk (gdbarch *gdbarch, CORE_ADDR pc) +{ + return false; +} + void _initialize_gdbarch_utils (void) { diff --git a/gdb/arch-utils.h b/gdb/arch-utils.h index 3407a16..b785b24 100644 --- a/gdb/arch-utils.h +++ b/gdb/arch-utils.h @@ -262,4 +262,9 @@ extern int default_print_insn (bfd_vma memaddr, disassemble_info *info); extern CORE_ADDR gdbarch_skip_prologue_noexcept (gdbarch *gdbarch, CORE_ADDR pc) noexcept; +/* Default implementation of gdbarch_in_indirect_branch_thunk that returns + false. */ +extern bool default_in_indirect_branch_thunk (gdbarch *gdbarch, + CORE_ADDR pc); + #endif diff --git a/gdb/gdbarch.c b/gdb/gdbarch.c index ddafe25..1359c2f 100644 --- a/gdb/gdbarch.c +++ b/gdb/gdbarch.c @@ -266,6 +266,7 @@ struct gdbarch gdbarch_skip_trampoline_code_ftype *skip_trampoline_code; gdbarch_skip_solib_resolver_ftype *skip_solib_resolver; gdbarch_in_solib_return_trampoline_ftype *in_solib_return_trampoline; + gdbarch_in_indirect_branch_thunk_ftype *in_indirect_branch_thunk; gdbarch_stack_frame_destroyed_p_ftype *stack_frame_destroyed_p; gdbarch_elf_make_msymbol_special_ftype *elf_make_msymbol_special; gdbarch_coff_make_msymbol_special_ftype *coff_make_msymbol_special; @@ -433,6 +434,7 @@ gdbarch_alloc (const struct gdbarch_info *info, gdbarch->skip_trampoline_code = generic_skip_trampoline_code; gdbarch->skip_solib_resolver = generic_skip_solib_resolver; gdbarch->in_solib_return_trampoline = generic_in_solib_return_trampoline; + gdbarch->in_indirect_branch_thunk = default_in_indirect_branch_thunk; gdbarch->stack_frame_destroyed_p = generic_stack_frame_destroyed_p; gdbarch->coff_make_msymbol_special = default_coff_make_msymbol_special; gdbarch->make_symbol_special = default_make_symbol_special; @@ -627,6 +629,7 @@ verify_gdbarch (struct gdbarch *gdbarch) /* Skip verify of skip_trampoline_code, invalid_p == 0 */ /* Skip verify of skip_solib_resolver, invalid_p == 0 */ /* Skip verify of in_solib_return_trampoline, invalid_p == 0 */ + /* Skip verify of in_indirect_branch_thunk, invalid_p == 0 */ /* Skip verify of stack_frame_destroyed_p, invalid_p == 0 */ /* Skip verify of elf_make_msymbol_special, has predicate. */ /* Skip verify of coff_make_msymbol_special, invalid_p == 0 */ @@ -1103,6 +1106,9 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file) "gdbarch_dump: have_nonsteppable_watchpoint = %s\n", plongest (gdbarch->have_nonsteppable_watchpoint)); fprintf_unfiltered (file, + "gdbarch_dump: in_indirect_branch_thunk = <%s>\n", + host_address_to_string (gdbarch->in_indirect_branch_thunk)); + fprintf_unfiltered (file, "gdbarch_dump: in_solib_return_trampoline = <%s>\n", host_address_to_string (gdbarch->in_solib_return_trampoline)); fprintf_unfiltered (file, @@ -3353,6 +3359,23 @@ set_gdbarch_in_solib_return_trampoline (struct gdbarch *gdbarch, gdbarch->in_solib_return_trampoline = in_solib_return_trampoline; } +bool +gdbarch_in_indirect_branch_thunk (struct gdbarch *gdbarch, CORE_ADDR pc) +{ + gdb_assert (gdbarch != NULL); + gdb_assert (gdbarch->in_indirect_branch_thunk != NULL); + if (gdbarch_debug >= 2) + fprintf_unfiltered (gdb_stdlog, "gdbarch_in_indirect_branch_thunk called\n"); + return gdbarch->in_indirect_branch_thunk (gdbarch, pc); +} + +void +set_gdbarch_in_indirect_branch_thunk (struct gdbarch *gdbarch, + gdbarch_in_indirect_branch_thunk_ftype in_indirect_branch_thunk) +{ + gdbarch->in_indirect_branch_thunk = in_indirect_branch_thunk; +} + int gdbarch_stack_frame_destroyed_p (struct gdbarch *gdbarch, CORE_ADDR addr) { diff --git a/gdb/gdbarch.h b/gdb/gdbarch.h index 5cb131d..0084f19 100644 --- a/gdb/gdbarch.h +++ b/gdb/gdbarch.h @@ -741,6 +741,12 @@ typedef int (gdbarch_in_solib_return_trampoline_ftype) (struct gdbarch *gdbarch, extern int gdbarch_in_solib_return_trampoline (struct gdbarch *gdbarch, CORE_ADDR pc, const char *name); extern void set_gdbarch_in_solib_return_trampoline (struct gdbarch *gdbarch, gdbarch_in_solib_return_trampoline_ftype *in_solib_return_trampoline); +/* Return true if PC lies inside an indirect branch thunk. */ + +typedef bool (gdbarch_in_indirect_branch_thunk_ftype) (struct gdbarch *gdbarch, CORE_ADDR pc); +extern bool gdbarch_in_indirect_branch_thunk (struct gdbarch *gdbarch, CORE_ADDR pc); +extern void set_gdbarch_in_indirect_branch_thunk (struct gdbarch *gdbarch, gdbarch_in_indirect_branch_thunk_ftype *in_indirect_branch_thunk); + /* A target might have problems with watchpoints as soon as the stack frame of the current function has been destroyed. This mostly happens as the first action in a function's epilogue. stack_frame_destroyed_p() diff --git a/gdb/gdbarch.sh b/gdb/gdbarch.sh index 0923029..4fc54cb 100755 --- a/gdb/gdbarch.sh +++ b/gdb/gdbarch.sh @@ -660,6 +660,9 @@ m;CORE_ADDR;skip_solib_resolver;CORE_ADDR pc;pc;;generic_skip_solib_resolver;;0 # Some systems also have trampoline code for returning from shared libs. m;int;in_solib_return_trampoline;CORE_ADDR pc, const char *name;pc, name;;generic_in_solib_return_trampoline;;0 +# Return true if PC lies inside an indirect branch thunk. +m;bool;in_indirect_branch_thunk;CORE_ADDR pc;pc;;default_in_indirect_branch_thunk;;0 + # A target might have problems with watchpoints as soon as the stack # frame of the current function has been destroyed. This mostly happens # as the first action in a function's epilogue. stack_frame_destroyed_p() diff --git a/gdb/i386-tdep.c b/gdb/i386-tdep.c index 60dc801..bf4ca54 100644 --- a/gdb/i386-tdep.c +++ b/gdb/i386-tdep.c @@ -47,6 +47,7 @@ #include "i386-tdep.h" #include "i387-tdep.h" #include "x86-xstate.h" +#include "x86-tdep.h" #include "record.h" #include "record-full.h" @@ -4421,6 +4422,15 @@ i386_gnu_triplet_regexp (struct gdbarch *gdbarch) +/* Implement the "in_indirect_branch_thunk" gdbarch function. */ + +static bool +i386_in_indirect_branch_thunk (struct gdbarch *gdbarch, CORE_ADDR pc) +{ + return x86_in_indirect_branch_thunk (pc, i386_register_names, + I386_EAX_REGNUM, I386_EIP_REGNUM); +} + /* Generic ELF. */ void @@ -4447,6 +4457,9 @@ i386_elf_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) i386_stap_is_single_operand); set_gdbarch_stap_parse_special_token (gdbarch, i386_stap_parse_special_token); + + set_gdbarch_in_indirect_branch_thunk (gdbarch, + i386_in_indirect_branch_thunk); } /* System V Release 4 (SVR4). */ diff --git a/gdb/infrun.c b/gdb/infrun.c index c1db689..9e5e063 100644 --- a/gdb/infrun.c +++ b/gdb/infrun.c @@ -6565,6 +6565,17 @@ process_event_stop_test (struct execution_control_state *ecs) return; } + /* Step through an indirect branch thunk. */ + if (ecs->event_thread->control.step_over_calls != STEP_OVER_NONE + && gdbarch_in_indirect_branch_thunk (gdbarch, stop_pc)) + { + if (debug_infrun) + fprintf_unfiltered (gdb_stdlog, + "infrun: stepped into indirect branch thunk\n"); + keep_going (ecs); + return; + } + if (ecs->event_thread->control.step_range_end != 1 && (ecs->event_thread->control.step_over_calls == STEP_OVER_UNDEBUGGABLE || ecs->event_thread->control.step_over_calls == STEP_OVER_ALL) diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index d7722a8..0dc05dd 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,10 @@ +2018-04-13 Markus Metzger <markus.t.metzger@intel.com> + + * 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. + 2018-04-11 Simon Marchi <simon.marchi@ericsson.com> * gdb.base/pie-fork.c: New file. diff --git a/gdb/testsuite/gdb.base/step-indirect-call-thunk.c b/gdb/testsuite/gdb.base/step-indirect-call-thunk.c new file mode 100644 index 0000000..bd22ea6 --- /dev/null +++ b/gdb/testsuite/gdb.base/step-indirect-call-thunk.c @@ -0,0 +1,42 @@ +/* This testcase is part of GDB, the GNU debugger. + + 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/>. + +*/ + +static int +inc (int x) +{ /* inc.1 */ + return x + 1; /* inc.2 */ +} /* inc.3 */ + +static int +thrice (int (*op)(int), int x) +{ /* thrice.1 */ + x = op (x); /* thrice.2 */ + x = op (x); /* thrice.3 */ + return op (x); /* thrice.4 */ +} /* thrice.5 */ + +int +main () +{ + int x; + + x = thrice (inc, 40); + + return x; +} 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" diff --git a/gdb/testsuite/gdb.reverse/step-indirect-call-thunk.c b/gdb/testsuite/gdb.reverse/step-indirect-call-thunk.c new file mode 100644 index 0000000..85464c3 --- /dev/null +++ b/gdb/testsuite/gdb.reverse/step-indirect-call-thunk.c @@ -0,0 +1,36 @@ +/* This testcase is part of GDB, the GNU debugger. + + 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/>. + +*/ + +static int +inc (int x) +{ /* inc.1 */ + return x + 1; /* inc.2 */ +} /* inc.3 */ + +static int +apply (int (*op)(int), int x) +{ /* apply.1 */ + return op (x); /* apply.2 */ +} /* apply.3 */ + +int +main () +{ /* main.1 */ + return apply (inc, 41); /* main.2 */ +} /* main.3 */ diff --git a/gdb/testsuite/gdb.reverse/step-indirect-call-thunk.exp b/gdb/testsuite/gdb.reverse/step-indirect-call-thunk.exp new file mode 100644 index 0000000..bb7fbf6 --- /dev/null +++ b/gdb/testsuite/gdb.reverse/step-indirect-call-thunk.exp @@ -0,0 +1,100 @@ +# 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/>. + +if { ![supports_reverse] } { + untested "target does not support record" + return -1 +} + +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 stepping COMMANDs in order to reach TARGET from CURRENT +# +# COMMAND is a stepping command +# 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 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 step_until { command current target test } { + global gdb_prompt + + set count 0 + gdb_test_multiple "$command" "$test" { + -re "$current.*$gdb_prompt $" { + incr count + if { $count < 100 } { + send_gdb "$command\n" + exp_continue + } else { + fail "$test" + } + } + -re "$target.*$gdb_prompt $" { + pass "$test" + } + } +} + +gdb_test_no_output "record" +gdb_test "next" ".*" "record trace" + +# Normal stepping steps through all thunks. +gdb_test "reverse-step" "apply\.3.*" "reverse-step into apply" +gdb_test "reverse-step" "inc\.3.*" "reverse-step into inc" +gdb_test "reverse-step" "inc\.2.*" "reverse-step inside inc" +gdb_test "reverse-step" "apply\.2.*" \ + "reverse-step through call thunk into apply" +gdb_test "reverse-step" "main\.2.*" "reverse-step into main" +gdb_test "step" "apply\.2.*" "step into apply" +gdb_test "step" "inc\.2.*" "step through call thunk into inc" +gdb_test "reverse-step" "apply\.2.*" \ + "reverse-step through call thunk into apply" +gdb_test "next" "apply\.3.*" "step through thunks and over inc" +gdb_test "reverse-next" "apply\.2.*" \ + "reverse-step through thunks and over inc" + +# We can use instruction stepping to step into thunks. +step_until "stepi" "apply\.2" "indirect_thunk" "stepi into call thunk" +step_until "stepi" "indirect_thunk" "inc" \ + "stepi out of call thunk into inc" +step_until "stepi" "inc" "return_thunk" "stepi into return thunk" +step_until "stepi" "return_thunk" "apply" \ + "stepi out of return thunk back into apply" + +step_until "reverse-stepi" "apply" "return_thunk" \ + "reverse-stepi into return thunk" +step_until "reverse-stepi" "return_thunk" "inc" \ + "reverse-stepi out of return thunk into inc" +step_until "reverse-stepi" "inc" "indirect_thunk" \ + "reverse-stepi into call thunk" +step_until "reverse-stepi" "indirect_thunk" "apply" \ + "reverse-stepi out of call thunk into apply" diff --git a/gdb/x86-tdep.c b/gdb/x86-tdep.c new file mode 100644 index 0000000..3e665c2 --- /dev/null +++ b/gdb/x86-tdep.c @@ -0,0 +1,76 @@ +/* Target-dependent code for X86-based targets. + + Copyright (C) 2018 Free Software Foundation, Inc. + + This file is part of GDB. + + 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/>. */ + +#include "defs.h" +#include "x86-tdep.h" + + +/* Check whether NAME is included in NAMES[LO] (inclusive) to NAMES[HI] + (exclusive). */ + +static bool +x86_is_thunk_register_name (const char *name, const char **names, int lo, + int hi) +{ + int reg; + for (reg = lo; reg < hi; ++reg) + if (strcmp (name, names[reg]) == 0) + return true; + + return false; +} + +/* See x86-tdep.h. */ + +bool +x86_in_indirect_branch_thunk (CORE_ADDR pc, const char **register_names, + int lo, int hi) +{ + struct bound_minimal_symbol bmfun = lookup_minimal_symbol_by_pc (pc); + if (bmfun.minsym == nullptr) + return false; + + const char *name = MSYMBOL_LINKAGE_NAME (bmfun.minsym); + if (name == nullptr) + return false; + + /* Check the indirect return thunk first. */ + if (strcmp (name, "__x86_return_thunk") == 0) + return true; + + /* Then check a family of indirect call/jump thunks. */ + static const char thunk[] = "__x86_indirect_thunk"; + static const size_t length = sizeof (thunk) - 1; + if (strncmp (name, thunk, length) != 0) + return false; + + /* If that's the complete name, we're in the memory thunk. */ + name += length; + if (*name == '\0') + return true; + + /* Check for suffixes. */ + if (*name++ != '_') + return false; + + if (x86_is_thunk_register_name (name, register_names, lo, hi)) + return true; + + return false; +} diff --git a/gdb/x86-tdep.h b/gdb/x86-tdep.h new file mode 100644 index 0000000..807ad1d --- /dev/null +++ b/gdb/x86-tdep.h @@ -0,0 +1,30 @@ +/* Target-dependent code for X86-based targets. + + Copyright (C) 2018 Free Software Foundation, Inc. + + This file is part of GDB. + + 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/>. */ + +#ifndef X86_TDEP_H +#define X86_TDEP_H + +/* Checks whether PC lies in an indirect branch thunk using registers + REGISTER_NAMES[LO] (inclusive) to REGISTER_NAMES[HI] (exclusive). */ + +extern bool x86_in_indirect_branch_thunk (CORE_ADDR pc, + const char **register_names, + int lo, int hi); + +#endif /* x86-tdep.h */ |