public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
* [PATCH] infrun: step through indirect branch thunks
@ 2018-02-19  5:16 Markus Metzger
  2018-03-26 17:38 ` Pedro Alves
  0 siblings, 1 reply; 14+ messages in thread
From: Markus Metzger @ 2018-02-19  5:16 UTC (permalink / raw)
  To: gdb-patches

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 and 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

2018-02-16  Markus Metzger  <markus.t.metzger@intel.com>

gdb/
	* infrun.c (in_indirect_branch_thunk): New.
	(process_event_stop_test): Call in_indirect_branch_thunk.
	* gdbarch.sh (in_indirect_branch_thunk): New.
	* gdbarch.c: Regenerated.
	* gdbarch.h: Regenerated.
	* i386-tdep (i386_is_thunk_regiser_name)
	(i386_in_indirect_branch_thunk): New.
	(i386_elf_init_abi): Set in_indirect_branch_thunk gdbarch function.
	* amd64-tdep (amd64_is_thunk_register_name)
	(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.
---
 gdb/amd64-tdep.c                                   | 54 +++++++++++++++++++
 gdb/gdbarch.c                                      | 32 ++++++++++++
 gdb/gdbarch.h                                      |  8 +++
 gdb/gdbarch.sh                                     |  3 ++
 gdb/i386-tdep.c                                    | 54 +++++++++++++++++++
 gdb/infrun.c                                       | 22 ++++++++
 gdb/testsuite/gdb.base/step-indirect-call-thunk.c  | 41 +++++++++++++++
 .../gdb.base/step-indirect-call-thunk.exp          | 33 ++++++++++++
 .../gdb.reverse/step-indirect-call-thunk.c         | 36 +++++++++++++
 .../gdb.reverse/step-indirect-call-thunk.exp       | 60 ++++++++++++++++++++++
 10 files changed, 343 insertions(+)
 create mode 100644 gdb/testsuite/gdb.base/step-indirect-call-thunk.c
 create mode 100644 gdb/testsuite/gdb.base/step-indirect-call-thunk.exp
 create mode 100644 gdb/testsuite/gdb.reverse/step-indirect-call-thunk.c
 create mode 100644 gdb/testsuite/gdb.reverse/step-indirect-call-thunk.exp

diff --git a/gdb/amd64-tdep.c b/gdb/amd64-tdep.c
index b589d93..8bd7109 100644
--- a/gdb/amd64-tdep.c
+++ b/gdb/amd64-tdep.c
@@ -3032,6 +3032,57 @@ static const int amd64_record_regmap[] =
   AMD64_DS_REGNUM, AMD64_ES_REGNUM, AMD64_FS_REGNUM, AMD64_GS_REGNUM
 };
 
+/* Check whether NAME is a register used in an indirect branch thunk.  */
+
+static int
+amd64_is_thunk_register_name (const char *name)
+{
+  int reg;
+  for (reg = AMD64_RAX_REGNUM; reg < AMD64_RIP_REGNUM; ++reg)
+    if (strcmp (name, amd64_register_names[reg]) == 0)
+      return 1;
+
+  return 0;
+}
+
+/* Implement the "in_indirect_branch_thunk" gdbarch function.  */
+
+static int
+amd64_in_indirect_branch_thunk (struct gdbarch *gdbarch, CORE_ADDR pc)
+{
+  struct bound_minimal_symbol bmfun = lookup_minimal_symbol_by_pc (pc);
+  if (bmfun.minsym == nullptr)
+    return 0;
+
+  const char *name = MSYMBOL_LINKAGE_NAME (bmfun.minsym);
+  if (name == nullptr)
+    return 0;
+
+  /* Check the indirect return thunk first.  */
+  if (strcmp (name, "__x86_return_thunk") == 0)
+    return 1;
+
+  /* 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 0;
+
+  /* If that's the complete name, we're in the memory thunk.  */
+  name += length;
+  if (*name == 0)
+    return 1;
+
+  /* Check for suffixes.  */
+  if (*name++ != '_')
+    return 0;
+
+  if (amd64_is_thunk_register_name (name))
+    return 1;
+
+  return 0;
+}
+
 void
 amd64_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch,
 		const target_desc *default_tdesc)
@@ -3204,6 +3255,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);
 }
 \f
 
diff --git a/gdb/gdbarch.c b/gdb/gdbarch.c
index fe3c12e..6243a41 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;
@@ -627,6 +628,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, has predicate.  */
   /* 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 +1105,12 @@ 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: gdbarch_in_indirect_branch_thunk_p() = %d\n",
+                      gdbarch_in_indirect_branch_thunk_p (gdbarch));
+  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,
@@ -3354,6 +3362,30 @@ set_gdbarch_in_solib_return_trampoline (struct gdbarch *gdbarch,
 }
 
 int
+gdbarch_in_indirect_branch_thunk_p (struct gdbarch *gdbarch)
+{
+  gdb_assert (gdbarch != NULL);
+  return gdbarch->in_indirect_branch_thunk != NULL;
+}
+
+int
+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)
 {
   gdb_assert (gdbarch != NULL);
diff --git a/gdb/gdbarch.h b/gdb/gdbarch.h
index 5664c4d..b080717 100644
--- a/gdb/gdbarch.h
+++ b/gdb/gdbarch.h
@@ -741,6 +741,14 @@ 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 non-zero if PC lies inside an indirect branch thunk. */
+
+extern int gdbarch_in_indirect_branch_thunk_p (struct gdbarch *gdbarch);
+
+typedef int (gdbarch_in_indirect_branch_thunk_ftype) (struct gdbarch *gdbarch, CORE_ADDR pc);
+extern int 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 a929e13..0b71df7 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 non-zero if PC lies inside an indirect branch thunk.
+M;int;in_indirect_branch_thunk;CORE_ADDR pc;pc
+
 # 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 cd56642..36d5855 100644
--- a/gdb/i386-tdep.c
+++ b/gdb/i386-tdep.c
@@ -4421,6 +4421,57 @@ i386_gnu_triplet_regexp (struct gdbarch *gdbarch)
 
 \f
 
+/* Check whether NAME is a register used in an indirect branch thunk.  */
+
+static int
+i386_is_thunk_register_name (const char *name)
+{
+  int reg;
+  for (reg = I386_EAX_REGNUM; reg < I386_EIP_REGNUM; ++reg)
+    if (strcmp (name, i386_register_names[reg]) == 0)
+      return 1;
+
+  return 0;
+}
+
+/* Implement the "in_indirect_branch_thunk" gdbarch function.  */
+
+static int
+i386_in_indirect_branch_thunk (struct gdbarch *gdbarch, CORE_ADDR pc)
+{
+  struct bound_minimal_symbol bmfun = lookup_minimal_symbol_by_pc (pc);
+  if (bmfun.minsym == nullptr)
+    return 0;
+
+  const char *name = MSYMBOL_LINKAGE_NAME (bmfun.minsym);
+  if (name == nullptr)
+    return 0;
+
+  /* Check the indirect return thunk first.  */
+  if (strcmp (name, "__x86_return_thunk") == 0)
+    return 1;
+
+  /* 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 0;
+
+  /* If that's the complete name, we're in the memory thunk.  */
+  name += length;
+  if (*name == 0)
+    return 1;
+
+  /* Check for suffixes.  */
+  if (*name++ != '_')
+    return 0;
+
+  if (i386_is_thunk_register_name (name))
+    return 1;
+
+  return 0;
+}
+
 /* Generic ELF.  */
 
 void
@@ -4447,6 +4498,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 1bc860b..e819b0d 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -6186,6 +6186,17 @@ handle_signal_stop (struct execution_control_state *ecs)
   process_event_stop_test (ecs);
 }
 
+/* Check whether PC lies inside an indirect branch thunk.  */
+
+static int
+in_indirect_branch_thunk (struct gdbarch *gdbarch, CORE_ADDR pc)
+{
+  if (!gdbarch_in_indirect_branch_thunk_p (gdbarch))
+    return 0;
+
+  return gdbarch_in_indirect_branch_thunk (gdbarch, pc);
+}
+
 /* Come here when we've got some debug event / signal we can explain
    (IOW, not a random signal), and test whether it should cause a
    stop, or whether we should resume the inferior (transparently).
@@ -6569,6 +6580,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
+      && 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/gdb.base/step-indirect-call-thunk.c b/gdb/testsuite/gdb.base/step-indirect-call-thunk.c
new file mode 100644
index 0000000..a43b3b3
--- /dev/null
+++ b/gdb/testsuite/gdb.base/step-indirect-call-thunk.c
@@ -0,0 +1,41 @@
+/* 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
+twice (int (*op)(int), int x)
+{
+  x = op (x);     /* twice.1 */
+  return op (x);  /* twice.2 */
+}                 /* twice.3 */
+
+int
+main ()
+{
+  int x;
+
+  x = twice (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..4bc04ba
--- /dev/null
+++ b/gdb/testsuite/gdb.base/step-indirect-call-thunk.exp
@@ -0,0 +1,33 @@
+# 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
+}
+
+gdb_test "step" "twice\.1.*" "step into twice ()"
+gdb_test "next" "twice\.2.*" "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" "twice\.3.*" "step through return thunk back into twice ()"
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..40a0237
--- /dev/null
+++ b/gdb/testsuite/gdb.reverse/step-indirect-call-thunk.exp
@@ -0,0 +1,60 @@
+# 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
+}
+
+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 ()"
+
+# We can step into the call thunk using instruction stepping.
+gdb_test "reverse-stepi 5" "indirect_thunk.*" "reverse-stepi into call thunk"
+gdb_test "stepi 5" "inc\.2.*" "stepi out of call thunk into inc ()"
+
+gdb_test "step" "inc\.3.*" "step inside inc ()"
+
+# We can also step into the return thunk using instruction stepping
+gdb_test "stepi 3" "return_thunk.*" "stepi into return thunk"
+gdb_test "reverse-stepi 3" "inc\.3.*" "reverse-stepi out of return thunk 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 "next" "apply\.3.*" "step through thunks and over inc ()"
+gdb_test "reverse-next" "apply\.2.*" "reverse-step through thunks and over inc ()"
-- 
1.8.3.1

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH] infrun: step through indirect branch thunks
  2018-02-19  5:16 [PATCH] infrun: step through indirect branch thunks Markus Metzger
@ 2018-03-26 17:38 ` Pedro Alves
  2018-04-09 14:20   ` Metzger, Markus T
  0 siblings, 1 reply; 14+ messages in thread
From: Pedro Alves @ 2018-03-26 17:38 UTC (permalink / raw)
  To: Markus Metzger, gdb-patches

On 02/19/2018 05:16 AM, Markus Metzger wrote:
> 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.

I was expecting to see the testscase looping over all possible
combinations, but only "thunk" is tested, it seems.  Why is that?

> 
> 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.

The tests sound useful, but isn't there some way we can make them more
robust to compiler's whims?  Maybe an upper-bounded number of instruction steps
until some pattern?

> 
> When using an older GCC, the tests will fail and be reported as untested:

I guess you meant s/will fail/will fail to build/

> 
>     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'
> 
> diff --git a/gdb/amd64-tdep.c b/gdb/amd64-tdep.c
> index b589d93..8bd7109 100644
> --- a/gdb/amd64-tdep.c
> +++ b/gdb/amd64-tdep.c
> @@ -3032,6 +3032,57 @@ static const int amd64_record_regmap[] =
>    AMD64_DS_REGNUM, AMD64_ES_REGNUM, AMD64_FS_REGNUM, AMD64_GS_REGNUM
>  };
>  
> +/* Check whether NAME is a register used in an indirect branch thunk.  */
> +
> +static int
> +amd64_is_thunk_register_name (const char *name)

Use C++ bool.

> +{
> +  int reg;
> +  for (reg = AMD64_RAX_REGNUM; reg < AMD64_RIP_REGNUM; ++reg)

   for (int reg = AMD64_RAX_REGNUM; reg < AMD64_RIP_REGNUM; ++reg)

> +    if (strcmp (name, amd64_register_names[reg]) == 0)
> +      return 1;
> +
> +  return 0;
> +}
> +
> +/* Implement the "in_indirect_branch_thunk" gdbarch function.  */
> +
> +static int

bool.

> +amd64_in_indirect_branch_thunk (struct gdbarch *gdbarch, CORE_ADDR pc)
> +{

> diff --git a/gdb/gdbarch.sh b/gdb/gdbarch.sh
> index a929e13..0b71df7 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 non-zero if PC lies inside an indirect branch thunk.
> +M;int;in_indirect_branch_thunk;CORE_ADDR pc;pc

bool.  s/non-zero/true/

> +
>  # 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 cd56642..36d5855 100644
> --- a/gdb/i386-tdep.c
> +++ b/gdb/i386-tdep.c

Same cosmetic comments apply here.

> @@ -4421,6 +4421,57 @@ i386_gnu_triplet_regexp (struct gdbarch *gdbarch)
>  
>  \f
>  
> +/* Check whether NAME is a register used in an indirect branch thunk.  */
> +
> +static int
> +i386_is_thunk_register_name (const char *name)
> +{
> +  int reg;
> +  for (reg = I386_EAX_REGNUM; reg < I386_EIP_REGNUM; ++reg)
> +    if (strcmp (name, i386_register_names[reg]) == 0)
> +      return 1;
> +
> +  return 0;
> +}
> +
> +/* Implement the "in_indirect_branch_thunk" gdbarch function.  */
> +
> +static int
> +i386_in_indirect_branch_thunk (struct gdbarch *gdbarch, CORE_ADDR pc)
> +{
> +  struct bound_minimal_symbol bmfun = lookup_minimal_symbol_by_pc (pc);
> +  if (bmfun.minsym == nullptr)
> +    return 0;
> +
> +  const char *name = MSYMBOL_LINKAGE_NAME (bmfun.minsym);
> +  if (name == nullptr)
> +    return 0;
> +
> +  /* Check the indirect return thunk first.  */
> +  if (strcmp (name, "__x86_return_thunk") == 0)
> +    return 1;
> +
> +  /* 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 0;
> +
> +  /* If that's the complete name, we're in the memory thunk.  */
> +  name += length;
> +  if (*name == 0)
> +    return 1;
> +
> +  /* Check for suffixes.  */
> +  if (*name++ != '_')
> +    return 0;
> +
> +  if (i386_is_thunk_register_name (name))
> +    return 1;
> +
> +  return 0;
> +}

Guess all this code could be shared betwee 32-bit/64-bit,
if you made this take the names array and a range as parameters:

bool
x86_in_indirect_branch_thunk (struct gdbarch *gdbarch, CORE_ADDR pc,
			      const char *register_names, 
                              int reg_lo, int reg_hi)
{
  ... mostly as above ...
}

And then:

static bool
i386_in_indirect_branch_thunk (struct gdbarch *gdbarch, CORE_ADDR pc)
{
  return x86_in_indirect_branch_thunk (gdbarch, pc, i386_register_names, 
                                       I386_EAX_REGNUM, I386_EIP_REGNUM);
}

static bool
amd64_in_indirect_branch_thunk (struct gdbarch *gdbarch, CORE_ADDR pc)
{
  return x86_in_indirect_branch_thunk (gdbarch, pc, amd64_register_names, 
                                       AMD64_RAX_REGNUM, AMD64_RIP_REGNUM);
}

>  }
>  
> +/* Check whether PC lies inside an indirect branch thunk.  */
> +
> +static int
> +in_indirect_branch_thunk (struct gdbarch *gdbarch, CORE_ADDR pc)
> +{
> +  if (!gdbarch_in_indirect_branch_thunk_p (gdbarch))
> +    return 0;

Do we need to check the _p predicate elsewhere?  Why not just
make the default return false, and always call the hook?

> +
> +  return gdbarch_in_indirect_branch_thunk (gdbarch, pc);
> +}
> +

> +gdb_test "step" "twice\.1.*" "step into twice ()"
> +gdb_test "next" "twice\.2.*" "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" "twice\.3.*" "step through return thunk back into twice ()"

No trailing " ()" in test names:

 https://sourceware.org/gdb/wiki/GDBTestcaseCookbook#Do_not_use_.22tail_parentheses.22_on_test_messages

Either drop the space before (), or drop the ()'s altogether.  

The other testcase too.

Should the gdb.base/ testcase have tests for stepping into the thunks?

Thanks,
Pedro Alves

^ permalink raw reply	[flat|nested] 14+ messages in thread

* RE: [PATCH] infrun: step through indirect branch thunks
  2018-03-26 17:38 ` Pedro Alves
@ 2018-04-09 14:20   ` Metzger, Markus T
  2018-04-09 14:42     ` [pushed/ob] Apply "Convert observers to C++" edit to gdbarch.sh (Re: [PATCH] infrun: step through indirect branch thunks) Pedro Alves
  2018-04-09 15:04     ` [PATCH] infrun: step through indirect branch thunks Pedro Alves
  0 siblings, 2 replies; 14+ messages in thread
From: Metzger, Markus T @ 2018-04-09 14:20 UTC (permalink / raw)
  To: Pedro Alves, gdb-patches

Hello Pedro,

Thanks for your review.

> > 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.
> 
> I was expecting to see the testscase looping over all possible
> combinations, but only "thunk" is tested, it seems.  Why is that?

Thunk and thunk-external result in the same code, except that the former
contains the thunk in a comdat section and the latter only contains a reference
to an external thunk that would need to be provided separately.

An inline thunk will be part of the caller and won't trigger GDB's
step-over-undebuggable heuristic.

And keep would not use a thunk so it should be covered by existing stepping
tests.


> > 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.
> 
> The tests sound useful, but isn't there some way we can make them more
> robust to compiler's whims?  Maybe an upper-bounded number of instruction
> steps
> until some pattern?

That might work.


> Guess all this code could be shared betwee 32-bit/64-bit,
> if you made this take the names array and a range as parameters:

So far, amd64-tdep.c was using functions from i386-tdep.c but it looks
cleaner if we put those into a common x86-tdep.c.  I'm adding one.


> > +/* Check whether PC lies inside an indirect branch thunk.  */
> > +
> > +static int
> > +in_indirect_branch_thunk (struct gdbarch *gdbarch, CORE_ADDR pc)
> > +{
> > +  if (!gdbarch_in_indirect_branch_thunk_p (gdbarch))
> > +    return 0;
> 
> Do we need to check the _p predicate elsewhere?  Why not just
> make the default return false, and always call the hook?

OK.

 
> Should the gdb.base/ testcase have tests for stepping into the thunks?

It is using the same code path as for the record tests.  But that holds for
all the new gdb.base/ tests I added.  I'll add it.

Below is the updated patch.  I ran the new tests on 64-bit and 32-bit IA.
I previously ran the full suite for v1 of this patch on 64-bit IA.

While regenerating gdbarch, I noticed that it generated the following
unrelated changes:

--- gdbarch.c   2018-04-09 14:56:08.976814000 +0200
+++ new-gdbarch.c       2018-04-09 14:57:33.914668000 +0200
@@ -44,7 +44,7 @@
 #include "reggroups.h"
 #include "osabi.h"
 #include "gdb_obstack.h"
-#include "observable.h"
+#include "observer.h"
 #include "regcache.h"
 #include "objfiles.h"
 #include "auxv.h"
@@ -5480,7 +5480,7 @@
   gdb_assert (new_gdbarch != NULL);
   gdb_assert (new_gdbarch->initialized_p);
   current_inferior ()->gdbarch = new_gdbarch;
-  gdb::observers::architecture_changed.notify (new_gdbarch);
+  observer_notify_architecture_changed (new_gdbarch);
   registers_changed ();
 }

, which result in a build error:

.../gdb/gdbarch.c:47:10: fatal error: observer.h: No such file or directory
 #include "observer.h"
          ^~~~~~~~~~~~
compilation terminated.

I excluded those from my patch.

Regards,
Markus.

---

commit 9d4066a96c132ebc8c671e54dd26338f73a8cf18
Author: Markus Metzger <markus.t.metzger@intel.com>
Date:   Wed Feb 14 14:30:57 2018 +0100

    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
    
    2018-04-09  Markus Metzger  <markus.t.metzger@intel.com>
    
    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.

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 0a07cab..eb8be2d 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -792,6 +792,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 \
@@ -1520,7 +1521,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.
 
@@ -2362,6 +2364,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..77b370c 100644
--- a/gdb/arch-utils.c
+++ b/gdb/arch-utils.c
@@ -979,6 +979,13 @@ 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 33dfa6b..b921950 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 d89f813..0df8e4d 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -6570,6 +6570,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/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..7f9ab60
--- /dev/null
+++ b/gdb/testsuite/gdb.base/step-indirect-call-thunk.exp
@@ -0,0 +1,61 @@
+# 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
+}
+
+proc stepi_until { current target test } {
+    global gdb_prompt
+
+    gdb_test_multiple "stepi" "$test: stepi" {
+        -re "$current.*$gdb_prompt $" {
+            send_gdb "stepi\n"
+            exp_continue
+        }
+        -re "$target.*$gdb_prompt $" {
+            pass "$test: $target reached"
+        }
+        -re "$gdb_prompt $" {
+            fail "$test: $target not reached"
+        }
+        timeout {
+            fail "$test: timeout"
+        }
+    }
+}
+
+# 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..93bac31
--- /dev/null
+++ b/gdb/testsuite/gdb.reverse/step-indirect-call-thunk.exp
@@ -0,0 +1,87 @@
+# 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
+}
+
+proc step_until { command current target test } {
+    global gdb_prompt
+
+    gdb_test_multiple "$command" "$test: $command" {
+        -re "$current.*$gdb_prompt $" {
+            send_gdb "$command\n"
+            exp_continue
+        }
+        -re "$target.*$gdb_prompt $" {
+            pass "$test: $target reached"
+        }
+        -re "$gdb_prompt $" {
+            fail "$test: $target not reached"
+        }
+        timeout {
+            fail "$test: timeout"
+        }
+    }
+}
+
+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..ff62947
--- /dev/null
+++ b/gdb/x86-tdep.c
@@ -0,0 +1,75 @@
+/* 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 "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..f3569ef
--- /dev/null
+++ b/gdb/x86-tdep.h
@@ -0,0 +1,32 @@
+/* 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
+
+#include "defs.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 */

Intel Deutschland GmbH
Registered Address: Am Campeon 10-12, 85579 Neubiberg, Germany
Tel: +49 89 99 8853-0, www.intel.de
Managing Directors: Christin Eisenschmid, Christian Lamprechter
Chairperson of the Supervisory Board: Nicole Lau
Registered Office: Munich
Commercial Register: Amtsgericht Muenchen HRB 186928

^ permalink raw reply	[flat|nested] 14+ messages in thread

* [pushed/ob] Apply "Convert observers to C++" edit to gdbarch.sh (Re: [PATCH] infrun: step through indirect branch thunks)
  2018-04-09 14:20   ` Metzger, Markus T
@ 2018-04-09 14:42     ` Pedro Alves
  2018-04-09 15:04     ` [PATCH] infrun: step through indirect branch thunks Pedro Alves
  1 sibling, 0 replies; 14+ messages in thread
From: Pedro Alves @ 2018-04-09 14:42 UTC (permalink / raw)
  To: Metzger, Markus T, gdb-patches

On 04/09/2018 03:19 PM, Metzger, Markus T wrote:

> While regenerating gdbarch, I noticed that it generated the following
> unrelated changes:
> 
> --- gdbarch.c   2018-04-09 14:56:08.976814000 +0200
> +++ new-gdbarch.c       2018-04-09 14:57:33.914668000 +0200
> @@ -44,7 +44,7 @@
>  #include "reggroups.h"
>  #include "osabi.h"
>  #include "gdb_obstack.h"
> -#include "observable.h"
> +#include "observer.h"
>  #include "regcache.h"
>  #include "objfiles.h"
>  #include "auxv.h"
> @@ -5480,7 +5480,7 @@
>    gdb_assert (new_gdbarch != NULL);
>    gdb_assert (new_gdbarch->initialized_p);
>    current_inferior ()->gdbarch = new_gdbarch;
> -  gdb::observers::architecture_changed.notify (new_gdbarch);
> +  observer_notify_architecture_changed (new_gdbarch);
>    registers_changed ();
>  }
> 
> , which result in a build error:
> 
> .../gdb/gdbarch.c:47:10: fatal error: observer.h: No such file or directory
>  #include "observer.h"
>           ^~~~~~~~~~~~
> compilation terminated.
> 
> I excluded those from my patch.

We should just fix that first.  Done now.

From 0bee6dd4aa42b928c2a7a496596490b694e5722b Mon Sep 17 00:00:00 2001
From: Pedro Alves <palves@redhat.com>
Date: Mon, 9 Apr 2018 15:34:48 +0100
Subject: [PATCH] Apply "Convert observers to C++" edit to gdbarch.sh

Regenerating gdbarch.c results in:

  --- gdbarch.c   2018-03-26 23:18:52.905548891 +0100
  +++ new-gdbarch.c       2018-04-09 15:32:30.006712207 +0100
  @@ -44,7 +44,7 @@
   #include "reggroups.h"
   #include "osabi.h"
   #include "gdb_obstack.h"
  -#include "observable.h"
  +#include "observer.h"
   #include "regcache.h"
   #include "objfiles.h"
   #include "auxv.h"
  @@ -5457,7 +5457,7 @@
     gdb_assert (new_gdbarch != NULL);
     gdb_assert (new_gdbarch->initialized_p);
     current_inferior ()->gdbarch = new_gdbarch;
  -  gdb::observers::architecture_changed.notify (new_gdbarch);
  +  observer_notify_architecture_changed (new_gdbarch);
     registers_changed ();
   }


Clearly commit 76727919ceb5 ("Convert observers to C++") edited
gdbarch.c directly instead of gdbarch.sh.  This fixes it.

gdb/ChangeLog:
2018-04-09  Pedro Alves  <palves@redhat.com>

	* gdbarch.sh: Include "observable.h" instead of "observer.h".
	(set_target_gdbarch): Call
	gdb::observers::architecture_changed.notify instead of
	observer_notify_architecture_changed.
---
 gdb/ChangeLog  | 7 +++++++
 gdb/gdbarch.sh | 4 ++--
 2 files changed, 9 insertions(+), 2 deletions(-)

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index fc95d7632fd..71e175fe993 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,10 @@
+2018-04-09  Pedro Alves  <palves@redhat.com>
+
+	* gdbarch.sh: Include "observable.h" instead of "observer.h".
+	(set_target_gdbarch): Call
+	gdb::observers::architecture_changed.notify instead of
+	observer_notify_architecture_changed.
+
 2018-04-07  Simon Marchi  <simon.marchi@polymtl.ca>
 
 	* tracepoint.c (struct current_traceframe_cleanup): Remove.
diff --git a/gdb/gdbarch.sh b/gdb/gdbarch.sh
index 33dfa6b349d..092302993a7 100755
--- a/gdb/gdbarch.sh
+++ b/gdb/gdbarch.sh
@@ -1644,7 +1644,7 @@ cat <<EOF
 #include "reggroups.h"
 #include "osabi.h"
 #include "gdb_obstack.h"
-#include "observer.h"
+#include "observable.h"
 #include "regcache.h"
 #include "objfiles.h"
 #include "auxv.h"
@@ -2506,7 +2506,7 @@ set_target_gdbarch (struct gdbarch *new_gdbarch)
   gdb_assert (new_gdbarch != NULL);
   gdb_assert (new_gdbarch->initialized_p);
   current_inferior ()->gdbarch = new_gdbarch;
-  observer_notify_architecture_changed (new_gdbarch);
+  gdb::observers::architecture_changed.notify (new_gdbarch);
   registers_changed ();
 }
 
-- 
2.14.3

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH] infrun: step through indirect branch thunks
  2018-04-09 14:20   ` Metzger, Markus T
  2018-04-09 14:42     ` [pushed/ob] Apply "Convert observers to C++" edit to gdbarch.sh (Re: [PATCH] infrun: step through indirect branch thunks) Pedro Alves
@ 2018-04-09 15:04     ` Pedro Alves
  2018-04-09 16:24       ` Metzger, Markus T
  2018-04-10  9:02       ` Metzger, Markus T
  1 sibling, 2 replies; 14+ messages in thread
From: Pedro Alves @ 2018-04-09 15:04 UTC (permalink / raw)
  To: Metzger, Markus T, gdb-patches

Hello Markus,

This is OK with a few minor changes pointed out below.

On 04/09/2018 03:19 PM, Metzger, Markus T wrote:

> diff --git a/gdb/arch-utils.c b/gdb/arch-utils.c
> index 5986ed6..77b370c 100644
> --- a/gdb/arch-utils.c
> +++ b/gdb/arch-utils.c
> @@ -979,6 +979,13 @@ 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)

Line break after "bool".

> +{
> +  return false;
> +}
> +
>  void
>  _initialize_gdbarch_utils (void)
>  {

> --- 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

If that last 0 is the default (I never remember off hand), then please write
"false" instead.  Assuming that works.

> 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..7f9ab60
> --- /dev/null
> +++ b/gdb/testsuite/gdb.base/step-indirect-call-thunk.exp
> @@ -0,0 +1,61 @@
> +# Copyright 2018 Free Software Foundation, Inc.
> +

...

> +
> +proc stepi_until { current target test } {

Please add a describing comment, particularly what
the parameters mean.

> +    global gdb_prompt
> +
> +    gdb_test_multiple "stepi" "$test: stepi" {
> +        -re "$current.*$gdb_prompt $" {
> +            send_gdb "stepi\n"
> +            exp_continue

This should probably have some upper bound.

> +        }
> +        -re "$target.*$gdb_prompt $" {
> +            pass "$test: $target reached"
> +        }
> +        -re "$gdb_prompt $" {
> +            fail "$test: $target not reached"
> +        }

It's better for result diffing, buildbot, etc. if FAIL/PASS
have the same test message.  And with that, the "fail" case
won't be necessary, since it's already taken care of by
gdb_test_multiple.  See below.

> +        timeout {
> +            fail "$test: timeout"
> +        }

A timeout handler is usually not needed because
gdb_test_multiple already handles it.

So that leaves you with something like this, with
upper bound for steps added while at it:

    set step_count 0

    set test "stepi until target"
    gdb_test_multiple "stepi" $test {
        -re "$current.*$gdb_prompt $" {
            send_gdb "stepi\n"
 
            # Cap number of steps just in case we end up
            # stuck in an infinite loop.
	    incr step_count
            if {$step_count < 100} {
	      exp_continue
            } else {
              fail $test
            }
        }
        -re "$target.*$gdb_prompt $" {
            pass $test
        }
    }

Same comments apply to step_until in the other test file.

> +++ b/gdb/x86-tdep.c
> @@ -0,0 +1,75 @@
> +/* 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 "x86-tdep.h"

"defs.h" should be included here, at the top, instead of ...

> +++ b/gdb/x86-tdep.h
> @@ -0,0 +1,32 @@
> +
> +#ifndef X86_TDEP_H
> +#define X86_TDEP_H
> +
> +#include "defs.h"
> +

... here.

See <https://sourceware.org/gdb/wiki/Internals%20GDB-C-Coding-Standards#Include_Files>.

> +
> +bool
> +x86_in_indirect_branch_thunk (CORE_ADDR pc, const char **register_names,
> +			      int lo, int hi)
> +{

...

> +  if (*name == 0)

Nit, we tend to write instead:

  if (*name == '\0')

> +++ b/gdb/x86-tdep.h
> @@ -0,0 +1,32 @@
> +
> +#ifndef X86_TDEP_H
> +#define X86_TDEP_H
> +
> +#include "defs.h"
> +
Thanks,
Pedro Alves

^ permalink raw reply	[flat|nested] 14+ messages in thread

* RE: [PATCH] infrun: step through indirect branch thunks
  2018-04-09 15:04     ` [PATCH] infrun: step through indirect branch thunks Pedro Alves
@ 2018-04-09 16:24       ` Metzger, Markus T
  2018-04-09 16:29         ` Pedro Alves
  2018-04-10  9:02       ` Metzger, Markus T
  1 sibling, 1 reply; 14+ messages in thread
From: Metzger, Markus T @ 2018-04-09 16:24 UTC (permalink / raw)
  To: Pedro Alves, gdb-patches

Hello Pedro,

> > --- 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
> 
> If that last 0 is the default (I never remember off hand), then please write "false"
> instead.  Assuming that works.

It is not the default.  I had to add a new function to return the default.  IIUC this
is disabling INVALID_P checks to allow default_in_indirect_branch_thunk to be
used as default.


> > +    gdb_test_multiple "stepi" "$test: stepi" {
> > +        -re "$current.*$gdb_prompt $" {
> > +            send_gdb "stepi\n"
> > +            exp_continue
> 
> This should probably have some upper bound.

Unless some compiler bug generated an infinite loop or GDB's stepping is
completely broken, we should eventually step out of $current.

I read your comment about an upper bound in your first reply but thought
that it wouldn't be necessary.  Do you think we need one?

Thanks,
Markus.

Intel Deutschland GmbH
Registered Address: Am Campeon 10-12, 85579 Neubiberg, Germany
Tel: +49 89 99 8853-0, www.intel.de
Managing Directors: Christin Eisenschmid, Christian Lamprechter
Chairperson of the Supervisory Board: Nicole Lau
Registered Office: Munich
Commercial Register: Amtsgericht Muenchen HRB 186928

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH] infrun: step through indirect branch thunks
  2018-04-09 16:24       ` Metzger, Markus T
@ 2018-04-09 16:29         ` Pedro Alves
  0 siblings, 0 replies; 14+ messages in thread
From: Pedro Alves @ 2018-04-09 16:29 UTC (permalink / raw)
  To: Metzger, Markus T, gdb-patches

On 04/09/2018 05:24 PM, Metzger, Markus T wrote:

> It is not the default.  I had to add a new function to return the default.  IIUC this
> is disabling INVALID_P checks to allow default_in_indirect_branch_thunk to be
> used as default.

Ah, yeah.

> 
> 
>>> +    gdb_test_multiple "stepi" "$test: stepi" {
>>> +        -re "$current.*$gdb_prompt $" {
>>> +            send_gdb "stepi\n"
>>> +            exp_continue
>>
>> This should probably have some upper bound.
> 
> Unless some compiler bug generated an infinite loop or GDB's stepping is
> completely broken, we should eventually step out of $current.

If nothing would ever break, we wouldn't need regression tests.  :-)

Keep developers doing local changes and breaking things routinely in
mind as well.

> I read your comment about an upper bound in your first reply but thought
> that it wouldn't be necessary.  Do you think we need one?

I do, because if for some reason the end up in the infinite loop, the
testcase will never timeout, hanging the test run.

Thanks,
Pedro Alves

^ permalink raw reply	[flat|nested] 14+ messages in thread

* RE: [PATCH] infrun: step through indirect branch thunks
  2018-04-09 15:04     ` [PATCH] infrun: step through indirect branch thunks Pedro Alves
  2018-04-09 16:24       ` Metzger, Markus T
@ 2018-04-10  9:02       ` Metzger, Markus T
  2018-04-10  9:10         ` Pedro Alves
  2018-04-13 14:58         ` Gary Benson
  1 sibling, 2 replies; 14+ messages in thread
From: Metzger, Markus T @ 2018-04-10  9:02 UTC (permalink / raw)
  To: Pedro Alves, gdb-patches

Hello Pedro,

> This is OK with a few minor changes pointed out below.

Thanks.  Below is the updated patch.  Unless there are further comments
I will push it end of this week.

Thanks,
Markus.

commit 5086dc0ba931de64b4d66425561773ec2e11fbea
Author: Markus Metzger <markus.t.metzger@intel.com>
Date:   Wed Feb 14 14:30:57 2018 +0100

    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
    
    2018-04-10  Markus Metzger  <markus.t.metzger@intel.com>
    
    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.

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 d89f813..0df8e4d 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -6570,6 +6570,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/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 */

Intel Deutschland GmbH
Registered Address: Am Campeon 10-12, 85579 Neubiberg, Germany
Tel: +49 89 99 8853-0, www.intel.de
Managing Directors: Christin Eisenschmid, Christian Lamprechter
Chairperson of the Supervisory Board: Nicole Lau
Registered Office: Munich
Commercial Register: Amtsgericht Muenchen HRB 186928

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH] infrun: step through indirect branch thunks
  2018-04-10  9:02       ` Metzger, Markus T
@ 2018-04-10  9:10         ` Pedro Alves
  2018-04-13 14:58         ` Gary Benson
  1 sibling, 0 replies; 14+ messages in thread
From: Pedro Alves @ 2018-04-10  9:10 UTC (permalink / raw)
  To: Metzger, Markus T, gdb-patches

On 04/10/2018 10:02 AM, Metzger, Markus T wrote:

> Thanks.  Below is the updated patch.  Unless there are further comments
> I will push it end of this week.
No further comments from me.

Thanks,
Pedro Alves

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH] infrun: step through indirect branch thunks
  2018-04-10  9:02       ` Metzger, Markus T
  2018-04-10  9:10         ` Pedro Alves
@ 2018-04-13 14:58         ` Gary Benson
  2018-04-13 16:07           ` Simon Marchi
  1 sibling, 1 reply; 14+ messages in thread
From: Gary Benson @ 2018-04-13 14:58 UTC (permalink / raw)
  To: Metzger, Markus T; +Cc: Pedro Alves, gdb-patches

Hi Markus,

I'm getting the following error:

  CXXLD  gdb
i386-tdep.o: In function `i386_in_indirect_branch_thunk(gdbarch*, unsigned long)':
/home/gary/work/archer/scratch/src/gdb/i386-tdep.c:4431: undefined reference to `x86_in_indirect_branch_thunk(unsigned long, char const**, int, int)'
amd64-tdep.o: In function `amd64_in_indirect_branch_thunk(gdbarch*, unsigned long)':
/home/gary/work/archer/scratch/src/gdb/amd64-tdep.c:3045: undefined reference to `x86_in_indirect_branch_thunk(unsigned long, char const**, int, int)'
collect2: error: ld returned 1 exit status
make[3]: *** [Makefile:1915: gdb] Error 1

with this commit:

Metzger, Markus T wrote:
> commit 5086dc0ba931de64b4d66425561773ec2e11fbea
> Author: Markus Metzger <markus.t.metzger@intel.com>
> Date:   Wed Feb 14 14:30:57 2018 +0100
>
>     infrun: step through indirect branch thunks

This is with a clean build on x86_64 RHEL 7.4,
CFLAGS="-g -O0" CXXFLAGS="-g -O0" ./configure --with-separate-debug-dir=/usr/lib/debug --enable-targets=all

Is anyone else seeing this or is it just me?

Thanks,
Gary

--
https://gbenson.net/

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH] infrun: step through indirect branch thunks
  2018-04-13 14:58         ` Gary Benson
@ 2018-04-13 16:07           ` Simon Marchi
  2018-04-15 19:47             ` Simon Marchi
  0 siblings, 1 reply; 14+ messages in thread
From: Simon Marchi @ 2018-04-13 16:07 UTC (permalink / raw)
  To: Gary Benson, Metzger, Markus T; +Cc: Pedro Alves, gdb-patches

On 2018-04-13 10:58 AM, Gary Benson wrote:
> Hi Markus,
> 
> I'm getting the following error:
> 
>   CXXLD  gdb
> i386-tdep.o: In function `i386_in_indirect_branch_thunk(gdbarch*, unsigned long)':
> /home/gary/work/archer/scratch/src/gdb/i386-tdep.c:4431: undefined reference to `x86_in_indirect_branch_thunk(unsigned long, char const**, int, int)'
> amd64-tdep.o: In function `amd64_in_indirect_branch_thunk(gdbarch*, unsigned long)':
> /home/gary/work/archer/scratch/src/gdb/amd64-tdep.c:3045: undefined reference to `x86_in_indirect_branch_thunk(unsigned long, char const**, int, int)'
> collect2: error: ld returned 1 exit status
> make[3]: *** [Makefile:1915: gdb] Error 1
> 
> with this commit:
> 
> Metzger, Markus T wrote:
>> commit 5086dc0ba931de64b4d66425561773ec2e11fbea
>> Author: Markus Metzger <markus.t.metzger@intel.com>
>> Date:   Wed Feb 14 14:30:57 2018 +0100
>>
>>     infrun: step through indirect branch thunks
> 
> This is with a clean build on x86_64 RHEL 7.4,
> CFLAGS="-g -O0" CXXFLAGS="-g -O0" ./configure --with-separate-debug-dir=/usr/lib/debug --enable-targets=all
> 
> Is anyone else seeing this or is it just me?
> 
> Thanks,
> Gary

Is x86-tdep.o built and included in the link command (make V=1)?

Simon

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH] infrun: step through indirect branch thunks
  2018-04-13 16:07           ` Simon Marchi
@ 2018-04-15 19:47             ` Simon Marchi
  2018-04-16  6:51               ` Metzger, Markus T
  2018-04-17 13:32               ` Gary Benson
  0 siblings, 2 replies; 14+ messages in thread
From: Simon Marchi @ 2018-04-15 19:47 UTC (permalink / raw)
  To: Simon Marchi, Gary Benson, Metzger, Markus T; +Cc: Pedro Alves, gdb-patches

On 2018-04-13 12:06 PM, Simon Marchi wrote:
> On 2018-04-13 10:58 AM, Gary Benson wrote:
>> This is with a clean build on x86_64 RHEL 7.4,
>> CFLAGS="-g -O0" CXXFLAGS="-g -O0" ./configure --with-separate-debug-dir=/usr/lib/debug --enable-targets=all
>>
>> Is anyone else seeing this or is it just me?
>>
>> Thanks,
>> Gary
> 
> Is x86-tdep.o built and included in the link command (make V=1)?
> 
> Simon
> 

Ok, so actually this happened with _not_ using --enable-targets=all.  I just
pushed a patch which should fix it:

https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;a=commit;h=eda4efb12763893b8a49c10c6f2823a465c1c6ba

Simon

^ permalink raw reply	[flat|nested] 14+ messages in thread

* RE: [PATCH] infrun: step through indirect branch thunks
  2018-04-15 19:47             ` Simon Marchi
@ 2018-04-16  6:51               ` Metzger, Markus T
  2018-04-17 13:32               ` Gary Benson
  1 sibling, 0 replies; 14+ messages in thread
From: Metzger, Markus T @ 2018-04-16  6:51 UTC (permalink / raw)
  To: Simon Marchi, Simon Marchi, Gary Benson; +Cc: Pedro Alves, gdb-patches

> Ok, so actually this happened with _not_ using --enable-targets=all.  I just pushed
> a patch which should fix it:
> 
> https://sourceware.org/git/gitweb.cgi?p=binutils-
> gdb.git;a=commit;h=eda4efb12763893b8a49c10c6f2823a465c1c6ba

Thanks, Simon.

Markus.

> -----Original Message-----
> From: Simon Marchi [mailto:simark@simark.ca]
> Sent: 15 April 2018 21:47
> To: Simon Marchi <simon.marchi@ericsson.com>; Gary Benson
> <gbenson@redhat.com>; Metzger, Markus T <markus.t.metzger@intel.com>
> Cc: Pedro Alves <palves@redhat.com>; gdb-patches@sourceware.org
> Subject: Re: [PATCH] infrun: step through indirect branch thunks
> 
> On 2018-04-13 12:06 PM, Simon Marchi wrote:
> > On 2018-04-13 10:58 AM, Gary Benson wrote:
> >> This is with a clean build on x86_64 RHEL 7.4, CFLAGS="-g -O0"
> >> CXXFLAGS="-g -O0" ./configure
> >> --with-separate-debug-dir=/usr/lib/debug --enable-targets=all
> >>
> >> Is anyone else seeing this or is it just me?
> >>
> >> Thanks,
> >> Gary
> >
> > Is x86-tdep.o built and included in the link command (make V=1)?
> >
> > Simon
> >
> 
> Ok, so actually this happened with _not_ using --enable-targets=all.  I just pushed
> a patch which should fix it:
> 
> https://sourceware.org/git/gitweb.cgi?p=binutils-
> gdb.git;a=commit;h=eda4efb12763893b8a49c10c6f2823a465c1c6ba
> 
> Simon
Intel Deutschland GmbH
Registered Address: Am Campeon 10-12, 85579 Neubiberg, Germany
Tel: +49 89 99 8853-0, www.intel.de
Managing Directors: Christin Eisenschmid, Christian Lamprechter
Chairperson of the Supervisory Board: Nicole Lau
Registered Office: Munich
Commercial Register: Amtsgericht Muenchen HRB 186928

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH] infrun: step through indirect branch thunks
  2018-04-15 19:47             ` Simon Marchi
  2018-04-16  6:51               ` Metzger, Markus T
@ 2018-04-17 13:32               ` Gary Benson
  1 sibling, 0 replies; 14+ messages in thread
From: Gary Benson @ 2018-04-17 13:32 UTC (permalink / raw)
  To: Simon Marchi; +Cc: Simon Marchi, Metzger, Markus T, Pedro Alves, gdb-patches

On Sun, Apr 15, 2018 at 8:47 PM, Simon Marchi <simark@simark.ca> wrote:
> Ok, so actually this happened with _not_ using --enable-targets=all.  I just
> pushed a patch which should fix it:
>
> https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;a=commit;h=eda4efb12763893b8a49c10c6f2823a465c1c6ba

Thanks Simon!

^ permalink raw reply	[flat|nested] 14+ messages in thread

end of thread, other threads:[~2018-04-17 13:32 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-02-19  5:16 [PATCH] infrun: step through indirect branch thunks Markus Metzger
2018-03-26 17:38 ` Pedro Alves
2018-04-09 14:20   ` Metzger, Markus T
2018-04-09 14:42     ` [pushed/ob] Apply "Convert observers to C++" edit to gdbarch.sh (Re: [PATCH] infrun: step through indirect branch thunks) Pedro Alves
2018-04-09 15:04     ` [PATCH] infrun: step through indirect branch thunks Pedro Alves
2018-04-09 16:24       ` Metzger, Markus T
2018-04-09 16:29         ` Pedro Alves
2018-04-10  9:02       ` Metzger, Markus T
2018-04-10  9:10         ` Pedro Alves
2018-04-13 14:58         ` Gary Benson
2018-04-13 16:07           ` Simon Marchi
2018-04-15 19:47             ` Simon Marchi
2018-04-16  6:51               ` Metzger, Markus T
2018-04-17 13:32               ` Gary Benson

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).