public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
From: "Ijaz, Abdul B" <abdul.b.ijaz@intel.com>
To: Bruno Larsen <blarsen@redhat.com>,
	"gdb-patches@sourceware.org" <gdb-patches@sourceware.org>
Cc: "JiniSusan.George@amd.com" <JiniSusan.George@amd.com>,
	"tom@tromey.com" <tom@tromey.com>, "eliz@gnu.org" <eliz@gnu.org>
Subject: RE: [PATCH v3 3/4] gdb/infrun: handle stepping through functions with DW_AT_trampoline
Date: Sat, 29 Jul 2023 11:03:01 +0000	[thread overview]
Message-ID: <SA1PR11MB6846B3AAEA5D4893938176F6CB07A@SA1PR11MB6846.namprd11.prod.outlook.com> (raw)
In-Reply-To: <3a9e7a38-3326-f7f2-b90b-b7286560debf@redhat.com>

Thanks a lot Bruno for the feedback and catching the problem in reverse stepping for trampolines.

> I really like this feature. Unfortunately, this isn't working when first entering a trampoline in reverse stepping. ie:
Will fix the problem in V4 patch series. We should avoid processing the targets for trampoline calls in the reverse direction and just keep going in "infrunc.c\process_event_stop_test function". So hopefully this should be fixed by the V4 series of patch. So will test it then hopefully soon I will push it for review.

Thanks & Best Regards
Abdul Basit


-----Original Message-----
From: Bruno Larsen <blarsen@redhat.com> 
Sent: Thursday, July 27, 2023 1:47 PM
To: Ijaz, Abdul B <abdul.b.ijaz@intel.com>; gdb-patches@sourceware.org
Cc: JiniSusan.George@amd.com; tom@tromey.com; eliz@gnu.org; Nils-Christian Kempke <nils-christian.kempke@intel.com>
Subject: Re: [PATCH v3 3/4] gdb/infrun: handle stepping through functions with DW_AT_trampoline

On 11/07/2023 00:56, Abdul Basit Ijaz via Gdb-patches wrote:
> From: Nils-Christian Kempke <nils-christian.kempke@intel.com>
>
> This patch makes infrun continue stepping into and through trampoline 
> functions marked via the DW_AT_trampoline in DWARF.  The attribute can 
> be emitted by the compiler for certain subroutines/inlined subroutines 
> that are compiler generated and should be hidden from a user.
>
> Mainly, infrun is modified in 3 ways.
>
> First, GDB will now attempt to step through trampoline functions.
> Whenever we issued a step command that would make GDB step into a 
> function that is marked trampoline, GDB will try to step directly 
> towards the trampoline's 'target' instead and, e.g., not stop at the 
> first instruction of the trampoline.
> The target can be specified by the compiler by the value of 
> DW_AT_trampoline if its form is either an address, a name, or a DIE 
> reference.  DW_AT_trampoline is also allowed to be specified as a flag 
> (containing true or false), in which case the target is assumed to be 
> unknown.  If GDB successfully finds a target, so if the value of 
> DW_AT_trampoline was not a flag and could be resolved successfully, 
> GDB steps directly towards the target and through the trampoline, 
> hiding the trampoline from the user.  If GDB cannot, however deduce a 
> target, most likely because the DW_AT_trampoline was given as a flag 
> or because of broken debug info, it will instead continue inside 
> execution in the trampoline function until it reaches an instruction 
> that is not associated with a trampoline function, which is usually 
> the target function.  It will then stop and give control back to the user.
> It should be noted, that there might be the cases, where trampolines 
> call functions other than the target before the actual target call.  
> If, in such a situation, GDB fails to resolve the target, it would 
> resume execution until stepping into this other function call, and 
> hand back control to the user, without actually having reached the 
> target.  A second step would have to be issued by the user to arrive a 
> the target (by resuming in the trampoline and then until leaving it a second time).
> As this is a rather pathological case and no real instance of this is 
> known, I think the current behavior here is good enough and seems to 
> be the best GDB can do in such a situation.
>
> Secondly, as trampoline functions normally do not have any real source 
> code correlation, it is likely that they mostly appear without line 
> info.
> Normally, GDB would skip completely over a function call to a function 
> that has no source line information, so we would never get to the 
> aforementioned stepping through a trampoline and target resolution.  
> To remedy this, for debug info trampolines, GDB now attempts to step 
> through them regardless of them having source line information or not.  
> So issuing a step at a function call wrapped by a trampoline without 
> source line information will no longer skip the whole function call, 
> but now step through the trampoline and attempt to resolve the 
> trampoline target as described above (so usually, a single step at the 
> call site will step through the trampoline and towards the target, 
> even if the trampoline had not source line info).
>
> Last, in all other cases when GDB is about to stop at a location that 
> is included in a trampoline region (e.g. after a step from the target 
> back into the trampoline) GDB will instead continue until the 
> trampoline region is left again and only then give control back to the 
> user.  This change serves the purpose of allowing stepping back from a 
> target call through the trampoline without the user noticing the 
> artificial function call inbetween call site and target.
>
> Together, these changes attempt to hide the trampoline function from 
> the user while stepping.  Additionally, the skip-trampoline-functions 
> option has been introduced in infrun.  It is set by default, and, when 
> turned off, GDB will return to its 'normal' stepping behavior and 
> ignore any possible DW_AT_trampoline.

I really like this feature. Unfortunately, this isn't working when first entering a trampoline in reverse stepping. ie:

➜  gdb ./gdb -q
testsuite/outputs/gdb.dwarf2/dw2-function-trampolines/dw2-function-trampolines
Reading symbols from
testsuite/outputs/gdb.dwarf2/dw2-function-trampolines/dw2-function-trampolines...
(gdb) start
Temporary breakpoint 1, main ()
     at
/home/blarsen/Documents/fsf_build/gdb/testsuite/../../../binutils-gdb/gdb/testsuite/gdb.dwarf2/dw2-function-trampolines.c:69
warning: Source file is more recent than executable.
69        global_var = 0;                               /* main set global_var */
(gdb) record
(gdb) n
73        ans = trampoline ();                          /* main call trampoline */
(gdb) n
75        ans = chained_trampoline ();                  /* main call chained_trampoline */
(gdb) rs
0x000000000040114b in trampoline ()
(gdb)
Single stepping until exit from function trampoline, which has no line number information.
target ()
     at
/home/blarsen/Documents/fsf_build/gdb/testsuite/../../../binutils-gdb/gdb/testsuite/gdb.dwarf2/dw2-function-trampolines.c:28
28        return 9 + 10;                                /* target return */
(gdb)
26        ++global_var;                                 /* target add */
(gdb)
main ()
     at
/home/blarsen/Documents/fsf_build/gdb/testsuite/../../../binutils-gdb/gdb/testsuite/gdb.dwarf2/dw2-function-trampolines.c:73
73        ans = trampoline ();                          /* main call trampoline */
(gdb)

I think this should be fixed before this patch went in.

--
Cheers,
Bruno

>
> As currently only ifx emits the DW_AT_trampoline tag, a test has been 
> added to gdb.dwarf2 that artificially creates a set of trampoline 
> functions.
>
> 2023-07-10 Nils-Christian Kempke <nils-christian.kempke@intel.com>
> ---
>   gdb/NEWS                                      |  15 ++
>   gdb/doc/gdb.texinfo                           |  36 +++
>   gdb/infrun.c                                  |  81 +++++-
>   gdb/infrun.h                                  |   4 +
>   .../gdb.dwarf2/dw2-function-trampolines.c     |  80 ++++++
>   .../gdb.dwarf2/dw2-function-trampolines.exp   | 245 ++++++++++++++++++
>   6 files changed, 457 insertions(+), 4 deletions(-)
>   create mode 100644 gdb/testsuite/gdb.dwarf2/dw2-function-trampolines.c
>   create mode 100644 
> gdb/testsuite/gdb.dwarf2/dw2-function-trampolines.exp
>
> diff --git a/gdb/NEWS b/gdb/NEWS
> index b924834d3d7..8bca5540f58 100644
> --- a/gdb/NEWS
> +++ b/gdb/NEWS
> @@ -571,6 +571,21 @@ platform.
>   
>   * New commands
>   
> +set skip-trampoline-functions on|off
> +show skip-trampoline-functions
> +  This setting is 'on' by default.  When 'on' it controls whether 
> +GDB's
> +  stepping behavior will recognize function calls that have been 
> +marked as
> +  trampolines in the debug info.  It improves stepping behavior in 
> +that it
> +  steps through trampoline code and hides it from the user.  GDB can 
> +now step
> +  through trampolines that are correctly marked as such in the 
> +compiler's
> +  debug info.  If the target of a trampoline is unknown, GDB will 
> +continue
> +  until the trampoline section is left again and only then hand 
> +control back
> +  to the user.  GDB does this even if the trampoline has no 
> +associated line
> +  info.  If this is turned off, GDB will step into trampolines if 
> +there is
> +  line table information for them or step over the trampoline calls 
> +if there
> +  is no line table information.  Currently, only DWARF trampolines 
> +are
> +  supported.
> +
>   maint set backtrace-on-fatal-signal on|off
>   maint show backtrace-on-fatal-signal
>     This setting is 'on' by default.  When 'on' GDB will print a 
> limited diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index 
> b10c06ae91f..839c3e6a0f8 100644
> --- a/gdb/doc/gdb.texinfo
> +++ b/gdb/doc/gdb.texinfo
> @@ -6391,6 +6391,42 @@ debug information.  This is the default.
>   Show whether @value{GDBN} will stop in or step over functions without
>   source line debug information.
>   
> +@kindex set skip-trampoline-functions @cindex trampoline functions 
> +@cindex stepping through trampoline functions @item set 
> +skip-trampoline-functions @itemx set skip-trampoline-functions on 
> +When calling a function in any language, some compilers might 
> +generate so-called @dfn{trampoline functions}, which wrap the actual 
> +function call (the target of the trampoline).  The compiler might 
> +mark such a trampoline in its debug information.  Often, such 
> +trampolines do not have any source line information associated with 
> +them which will lead the @code{step} command to behave like a @code{next} and skip the function call completely.
> +
> +The default is @code{set skip-trampoline-functions on} and it will 
> +cause the @code{step} command to treat these trampolines differently.  
> +When issuing a @code{step} at the call site of a trampoline function 
> +if @code{skip-trampoline-functions} is set @value{GDBN} will attempt 
> +to determine the target of the trampoline and then step through the 
> +trampoline stopping at the target.  If the target could not be found 
> +or was not given in the debug info, @value{GDBN} will simply continue 
> +execution until it leaves the trampoline code again, even if the 
> +trampoline has no line info associated with it.  When returning from 
> +a target function call and stepping back into the trampoline, 
> +@value{GDBN} will again step through the trampoline towards the call 
> +site.  Additionally, even if stopped in a trampoline function with 
> +source line information, issuing a @code{step} will prompt 
> +@value{GDBN} to resume execution until leaving the trampoline region 
> +again.  The @code{stepi} command is not affected by the setting which is enabled by default.  Currently, only DWARF trampolines marked via DW_AT_trampoline are supported by this.
> +
> +@item set skip-trampoline-functions off Causes the @code{step} 
> +command to completely ignore any trampoline information a compiler 
> +might have emitted in its debug info.  Trampolines will be treated 
> +like any other function when stepping.
> +
> +@item show skip-trampoline-functions
> +Show whether @value{GDBN} tries to skip trampolines or not.
> +
>   @kindex finish
>   @kindex fin @r{(@code{finish})}
>   @item finish
> diff --git a/gdb/infrun.c b/gdb/infrun.c index 
> 58da1cef29e..dfafe7cdc74 100644
> --- a/gdb/infrun.c
> +++ b/gdb/infrun.c
> @@ -184,6 +184,12 @@ get_previous_thread ()
>   
>   static bool detach_fork = true;
>   
> +/* If set (default) GDB will step through functions/inlined subroutines marked
> +   DW_AT_trampoline by the compiler.  If false, GDB will ignore the
> +   attribute.  */
> +
> +static bool skip_trampoline_functions = true;
> +
>   bool debug_infrun = false;
>   static void
>   show_debug_infrun (struct ui_file *file, int from_tty, @@ -7265,7 
> +7271,6 @@ process_event_stop_test (struct execution_control_state *ecs)
>   		  != find_pc_function (ecs->event_thread->stop_pc ())))))
>       {
>         CORE_ADDR stop_pc = ecs->event_thread->stop_pc ();
> -      CORE_ADDR real_stop_pc;
>   
>         infrun_debug_printf ("stepped into subroutine");
>   
> @@ -7337,8 +7342,41 @@ process_event_stop_test (struct execution_control_state *ecs)
>   	 calling routine and the real function), locate the real
>   	 function.  That's what tells us (a) whether we want to step
>   	 into it at all, and (b) what prologue we want to run to the
> -	 end of, if we do step into it.  */
> -      real_stop_pc = skip_language_trampoline (frame, stop_pc);
> +	 end of, if we do step into it.  For functions marked as
> +	 trampoline functions we try to find their target and step
> +	 towards it (if skip_trampoline_functions is not set to false by the
> +	 user).  If no target can be determined we just step into the
> +	 trampoline and hand control back to the user.  */
> +      CORE_ADDR real_stop_pc = 0;
> +      bool in_trampoline = skip_trampoline_functions
> +			   && in_trampoline_function (stop_pc);
> +
> +      if (in_trampoline)
> +	{
> +	  real_stop_pc = find_function_trampoline_target (stop_pc);
> +
> +	  for (int i = 0; i < MAX_TRAMPOLINE_CHAIN_SIZE
> +			  && in_trampoline_function (real_stop_pc); ++i)
> +	    {
> +		real_stop_pc = find_function_trampoline_target (real_stop_pc);
> +		/* Exit if find_function_trampoline_target failed to find the
> +		   trampoline target.  Do not try to resolve the trampolines
> +		   in this case.  */
> +		if (real_stop_pc == 0x0)
> +		  break;
> +	    }
> +
> +	  /* If we failed to find a target we will just single step in the
> +	     hope of leaving the trampoline again soon.  */
> +	  if (real_stop_pc == 0x0)
> +	    {
> +	      keep_going (ecs);
> +	      return;
> +	    }
> +	}
> +
> +      if (real_stop_pc == 0)
> +	real_stop_pc = skip_language_trampoline (frame, stop_pc);
>         if (real_stop_pc == 0)
>   	real_stop_pc = gdbarch_skip_trampoline_code (gdbarch, frame, stop_pc);
>         if (real_stop_pc != 0)
> @@ -7359,6 +7397,8 @@ process_event_stop_test (struct execution_control_state *ecs)
>         /* If we have line number information for the function we are
>   	 thinking of stepping into and the function isn't on the skip
>   	 list, step into it.
> +	 If we are about to step into a function marked trampoline with no
> +	 line number information, we still want to enter it here.
>   
>   	 If there are several symtabs at that PC (e.g. with include
>   	 files), just want to know whether *any* of them have line @@ 
> -7367,7 +7407,9 @@ process_event_stop_test (struct execution_control_state *ecs)
>   	struct symtab_and_line tmp_sal;
>   
>   	tmp_sal = find_pc_line (ecs->stop_func_start, 0);
> -	if (tmp_sal.line != 0
> +	if ((tmp_sal.line != 0
> +	     || (skip_trampoline_functions
> +		 && in_trampoline_function (ecs->stop_func_start)))
>   	    && !function_name_is_marked_for_skip (ecs->stop_func_name,
>   						  tmp_sal)
>   	    && !inline_frame_is_marked_for_skip (true, ecs->event_thread)) 
> @@ -7520,6 +7562,19 @@ process_event_stop_test (struct execution_control_state *ecs)
>         return;
>       }
>   
> +  /* If we ended up in a function trampoline without stepping into a new
> +     function we are either in some inlined trampoline or returning through a
> +     trampoline function.  In either case we continue to single step until we
> +     are out of the trampoline code again.  This check has to be done before
> +     stop_pc_sal.line == 0 below, as trampolines usually don't have source
> +     line information associated with them.  */  if 
> + (skip_trampoline_functions && in_trampoline_function (stop_pc_sal.pc))
> +    {
> +      infrun_debug_printf ("stepped into trampoline code");
> +      keep_going (ecs);
> +      return;
> +    }
> +
>     if (stop_pc_sal.line == 0)
>       {
>         /* We have no line number information.  That means to stop @@ 
> -9731,6 +9786,14 @@ show_exec_direction_func (struct ui_file *out, int from_tty,
>     }
>   }
>   
> +static void
> +show_skip_trampoline_functions (ui_file *file, int from_tty,
> +				cmd_list_element *c,
> +				const char *value)
> +{
> +  gdb_printf (file, _("Skipping trampoline functions is %s.\n"), 
> +value); }
> +
>   static void
>   show_schedule_multiple (struct ui_file *file, int from_tty,
>   			struct cmd_list_element *c, const char *value) @@ -10076,6 
> +10139,16 @@ Options are 'forward' or 'reverse'."),
>   			set_exec_direction_func, show_exec_direction_func,
>   			&setlist, &showlist);
>   
> +  add_setshow_boolean_cmd ("skip-trampoline-functions", class_run,
> +			  &skip_trampoline_functions, _("\ Set whether gdb attempts to 
> +hide trampolines marked in the debug info."), _("\ Show whether gdb 
> +attempts to hide trampolines marked in the debug info."), _("\ If on, 
> +while stepping gdb will skip through functions and inlined 
> +functions\n\ marked as trampolines by the compiler.  If off, gdb will 
> +ignore such function\n\ trampolines."),
> +			  nullptr, show_skip_trampoline_functions, &setlist,
> +			  &showlist);
> +
>     /* Set/show detach-on-fork: user-settable mode.  */
>   
>     add_setshow_boolean_cmd ("detach-on-fork", class_run, 
> &detach_fork, _("\ diff --git a/gdb/infrun.h b/gdb/infrun.h index 
> a343d27f72d..d4a6b7892b5 100644
> --- a/gdb/infrun.h
> +++ b/gdb/infrun.h
> @@ -76,6 +76,10 @@ infrun_debug_show_threads (const char *title, ThreadRange threads)
>   }
>   
>   
> +/* Maximum size of trampoline chain to process while resolving
> +   trampolines.  */
> +#define MAX_TRAMPOLINE_CHAIN_SIZE 10
> +
>   /* Nonzero if we want to give control to the user when we're notified
>      of shared library events by the dynamic linker.  */
>   extern int stop_on_solib_events;
> diff --git a/gdb/testsuite/gdb.dwarf2/dw2-function-trampolines.c 
> b/gdb/testsuite/gdb.dwarf2/dw2-function-trampolines.c
> new file mode 100644
> index 00000000000..1f0eb2e0efa
> --- /dev/null
> +++ b/gdb/testsuite/gdb.dwarf2/dw2-function-trampolines.c
> @@ -0,0 +1,80 @@
> +/* Copyright 2023 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/>.  */
> +
> +/* This test relies on inlined_trampoline being inlined into main and the other
> +   functions not.  All functions except target will be marked via
> +   DW_AT_trampoline in the debug info and we'll check whether one can step
> +   through the trampolines towards target.  */ volatile int 
> +global_var;
> +
> +int __attribute__ ((noinline))
> +target ()					/* target decl line */
> +{						/* target prologue */
> +  asm ("target_label: .globl target_label");
> +  ++global_var;					/* target add */
> +  asm ("target_label2: .globl target_label2");
> +  return 9 + 10;				/* target return */
> +}						/* target end */
> +
> +int __attribute__ ((noinline))
> +trampoline ()
> +{						/* trampoline prologue */
> +  asm ("trampoline_label: .globl trampoline_label");
> +  ++global_var;
> +  return target ();				/* trampoline target call */
> +}						/* trampoline end */
> +
> +static inline int __attribute__ ((always_inline)) inlined_trampoline 
> +()
> +{						/* inlined_trampoline prologue */
> +  asm ("inlined_trampoline_label: .globl inlined_trampoline_label");
> +  ++global_var;					/* inlined_trampoline add */
> +  asm ("inlined_trampoline_label2: .globl inlined_trampoline_label2");
> +  return target ();				/* inlined_trampoline target call */
> +}						/* inlined_trampoline end */
> +
> +int __attribute__ ((noinline))
> +chained_trampoline ()
> +{						/* chained_trampoline prologue */
> +  asm ("chained_trampoline_label: .globl chained_trampoline_label");
> +  ++global_var;
> +  return trampoline ();				/* chained_trampoline trampoline call */
> +}						/* chained_trampoline end */
> +
> +int __attribute__ ((noinline))
> +doubly_chained_trampoline ()
> +{						/* doubly_chained_trampoline prologue */
> +  asm ("doubly_chained_trampoline_label: .globl 
> +doubly_chained_trampoline_label");
> +  ++global_var;
> +  return chained_trampoline ();			/* doubly_chained_trampoline chained_trampoline call */
> +}						/* doubly_chained_trampoline end */
> +
> +int
> +main ()						/* main decl line */
> +{						/* main prologue */
> +  int ans;
> +  asm ("main_label: .globl main_label");
> +  global_var = 0;				/* main set global_var */
> +  asm ("main_label2: .globl main_label2");
> +  ans = inlined_trampoline ();			/* main call inlined_trampoline */
> +  asm ("main_label3: .globl main_label3");
> +  ans = trampoline ();				/* main call trampoline */
> +  asm ("main_label4: .globl main_label4");
> +  ans = chained_trampoline ();			/* main call chained_trampoline */
> +  asm ("main_label5: .globl main_label5");
> +  ans = doubly_chained_trampoline ();		/* main call doubly_chained_trampoline */
> +  asm ("main_label6: .globl main_label6");
> +  return ans;					/* main call return */
> +}						/* main end */
> diff --git a/gdb/testsuite/gdb.dwarf2/dw2-function-trampolines.exp 
> b/gdb/testsuite/gdb.dwarf2/dw2-function-trampolines.exp
> new file mode 100644
> index 00000000000..67eec2b5540
> --- /dev/null
> +++ b/gdb/testsuite/gdb.dwarf2/dw2-function-trampolines.exp
> @@ -0,0 +1,245 @@
> +# Copyright 2023 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/>.
> +
> +# This test checks GDB's handling of functions/inlined functions 
> +marked # DW_AT_trampoline by the compiler.  A function marked as 
> +trampoline should # generally be hidden from the user.  We check 
> +whether we can step through # trampolines.  Every trampoline is 
> +defined using a different type for its # target: a string, an address, a DIE reference or a flag.
> +# Setting skip-trampoline-functions to false inside GDB should make 
> +it return # to its 'normal' behavior, ignore the DW_AT_trampoline, 
> +and skip all of the # non-inlined trampoline calls (as their DIEs 
> +don't have any source # information).
> +
> +load_lib dwarf.exp
> +
> +# This test can only be run on targets which support DWARF-2 and use gas.
> +if {![dwarf2_support]} {
> +    return 0
> +}
> +
> +standard_testfile .c .S
> +
> +set asm_file [standard_output_file $srcfile2] Dwarf::assemble 
> +$asm_file {
> +    global srcdir subdir srcfile
> +    declare_labels lines_label trampoline_label
> +
> +    get_func_info target
> +    get_func_info trampoline
> +    get_func_info chained_trampoline
> +    get_func_info doubly_chained_trampoline
> +    get_func_info main
> +
> +    set target_decl_line [gdb_get_line_number "target decl line"]
> +    set main_decl_line [gdb_get_line_number "main decl line"]
> +    set main_call_inlined_trampoline_line [gdb_get_line_number "main 
> + call inlined_trampoline"]
> +
> +    cu {} {
> +	compile_unit {
> +	    {language @DW_LANG_C}
> +	    {name dw2-function-trampolines.c}
> +	    {low_pc 0 addr}
> +	    {stmt_list ${lines_label} DW_FORM_sec_offset}
> +	} {
> +	    subprogram {
> +		{name target}
> +		{low_pc $target_start addr}
> +		{high_pc "$target_start + $target_len" addr}
> +		{decl_file 1 data1}
> +		{decl_line $target_decl_line data1}
> +	    }
> +	    # The 'trampoline' subprogram declares its target by name.
> +	    trampoline_label: subprogram {
> +		    {name trampoline}
> +		    {low_pc $trampoline_start addr}
> +		    {high_pc "$trampoline_start + $trampoline_len" addr}
> +		    {trampoline target string}
> +		}
> +	    # The 'chained_trampoline' subprogram declares its target as die
> +	    # reference.
> +	    subprogram {
> +		{name chained_trampoline}
> +		{low_pc $chained_trampoline_start addr}
> +		{high_pc "$chained_trampoline_start + $chained_trampoline_len" addr}
> +		{trampoline %$trampoline_label}
> +	    }
> +	    # The 'doubly_chained_trampoline' subprogram declares no target.
> +	    # Its DW_AT_trampoline is a flag set to true.
> +	    subprogram {
> +		{name doubly_chained_trampoline}
> +		{low_pc $doubly_chained_trampoline_start addr}
> +		{high_pc "$doubly_chained_trampoline_start + $doubly_chained_trampoline_len" addr}
> +		{trampoline 1 flag}
> +	    }
> +	    subprogram {
> +		{external 1 flag}
> +		{name main}
> +		{main_subprogram 1 flag}
> +		{low_pc $main_start addr}
> +		{high_pc "$main_start + $main_len" addr}
> +		{decl_file 1 data1}
> +		{decl_line $main_decl_line data1}
> +	    } {
> +		# The 'inlined_trampoline' subroutine declares its target as
> +		# an address.
> +		inlined_subroutine {
> +		    {name inlined_trampoline}
> +		    {low_pc main_label2 addr}
> +		    {high_pc main_label3 addr}
> +		    {trampoline $target_start addr}
> +		    {call_file 1 data1}
> +		    {call_line $main_call_inlined_trampoline_line data1}
> +		}
> +	    }
> +	}
> +    }
> +
> +    lines {version 2} lines_label {
> +	include_dir "${srcdir}/${subdir}"
> +	file_name "$srcfile" 1
> +
> +	program {
> +	    DW_LNE_set_address $main_start
> +	    line [gdb_get_line_number "main set global_var"]
> +	    DW_LNS_copy
> +	    DW_LNE_set_address main_label
> +	    line [gdb_get_line_number "main set global_var"]
> +	    DW_LNS_copy
> +	    DW_LNE_set_address main_label2
> +	    line [gdb_get_line_number "main call inlined_trampoline"]
> +	    DW_LNS_copy
> +	    DW_LNE_set_address inlined_trampoline_label
> +	    line [gdb_get_line_number "inlined_trampoline add"]
> +	    DW_LNS_copy
> +	    DW_LNE_set_address inlined_trampoline_label2
> +	    line [gdb_get_line_number "inlined_trampoline target call"]
> +	    DW_LNS_copy
> +	    DW_LNE_set_address main_label3
> +	    line [gdb_get_line_number "main call trampoline"]
> +	    DW_LNS_copy
> +	    DW_LNE_set_address main_label4
> +	    line [gdb_get_line_number "main call chained_trampoline"]
> +	    DW_LNS_copy
> +	    DW_LNE_set_address main_label5
> +	    line [gdb_get_line_number "main call doubly_chained_trampoline"]
> +	    DW_LNS_copy
> +	    DW_LNE_set_address main_label6
> +	    line [gdb_get_line_number "main call return"]
> +	    DW_LNS_copy
> +	    DW_LNE_set_address $main_end
> +	    DW_LNE_end_sequence
> +
> +	    DW_LNE_set_address $target_start
> +	    line [gdb_get_line_number "target prologue"]
> +	    DW_LNS_negate_stmt
> +	    DW_LNS_copy
> +	    DW_LNE_set_address target_label
> +	    line [gdb_get_line_number "target add"]
> +	    DW_LNS_negate_stmt
> +	    DW_LNS_copy
> +	    DW_LNE_set_address target_label2
> +	    line [gdb_get_line_number "target return"]
> +	    DW_LNS_copy
> +	    DW_LNE_set_address $target_end
> +	    DW_LNE_end_sequence
> +	}
> +    }
> +}
> +
> +if {[prepare_for_testing "failed to prepare" ${testfile} \
> +	[list $srcfile $asm_file] {nodebug additional_flags=-O0}]} {
> +    return -1
> +}
> +
> +set target_first_line_pattern ".*target add.*"
> +set target_second_line_pattern ".*target return.*"
> +
> +if ![runto_main] {
> +    return -1
> +}
> +
> +gdb_test "show skip-trampoline-functions" \
> +    "Skipping trampoline functions is on\." \
> +    "check skip-trampoline-functions is enabled"
> +
> +with_test_prefix "with trampoline handling" {
> +    foreach {trampoline return_line} { "inlined_trampoline" "trampoline" \
> +	"trampoline" "chained_trampoline" \
> +	"chained_trampoline" "doubly_chained_trampoline" } {
> +
> +	gdb_test "s" "$target_first_line_pattern" "step through $trampoline"
> +	gdb_test "s" "$target_second_line_pattern" \
> +	    "step target second line from $trampoline"
> +	gdb_test "s" ".*main call $return_line.*" \
> +	    "step back through $trampoline"
> +    }
> +
> +    # The doubly_chained_trampoline has only been marked as trampoline but no
> +    # target was given.  In this case GDB steps into the trampoline and then
> +    # continues until the trampoline section is left again.
> +
> +    # When compiled with gcc 7.5 (and possibly others) on a 32 bit system, the
> +    # trampoline function contains a call to __x86.get_pc_thunk.ax before the
> +    # actual target call.  So, we end up in __x86.get_pc_thunk.ax.  Issuing a
> +    # second step command will return from the function call back into the
> +    # trampoline and go on inside the trampoline towards the actual target call.
> +    # On other targets we step directly towards the target call.
> +    gdb_test_multiple "s" "step through double_chained_trampoline" {
> +	-re -wrap "$target_first_line_pattern" {
> +	    pass $gdb_test_name
> +	}
> +	-re -wrap ".*__x86.get_pc_thunk.ax.*" {
> +	    gdb_test "s" "$target_first_line_pattern" \
> +		"step through double_chained_trampoline 2nd try"
> +	}
> +    }
> +    gdb_test "s" "$target_second_line_pattern" \
> +	"step target second line fromdoubly_chained_trampoline"
> +    gdb_test "s" ".*main call return.*" \
> +	"step back through doubly_chained_trampoline"
> +}
> +
> +clean_restart ${testfile}
> +
> +if ![runto_main] {
> +    return -1
> +}
> +
> +gdb_test_no_output "set skip-trampoline-functions off" \
> +    "disable trampoline handling"
> +gdb_test "show skip-trampoline-functions" \
> +    "Skipping trampoline functions is off." \
> +    "check skip-trampoline-functions is disabled"
> +
> +with_test_prefix "without trampoline handling" {
> +    gdb_test "s" ".*main call inlined_trampoline.*"
> +    gdb_test "s" ".*inlined_trampoline add.*" \
> +	"step into inlined_trampoline with skip-trampoline off"
> +    gdb_test "s" ".*inlined_trampoline target call.*" \
> +	"step in inlined_trampoline with skip-trampoline off"
> +    gdb_test "s" "$target_first_line_pattern" \
> +	"step into target with skip-trampoline off"
> +    gdb_test "s" "$target_second_line_pattern" \
> +	"step second line in target with skip-trampoline off"
> +    gdb_test "s" ".*main call trampoline.*" \
> +	"step brack from target with skip-trampoline off"
> +    gdb_test "s" ".*main call chained_trampoline.*" \
> +	"skip trampoline call with no line info"
> +    gdb_test "s" ".*main call doubly_chained_trampoline.*" \
> +	"skip chained_trampoline call with no line info"
> +    gdb_test "s" ".*main call return.*" \
> +	"skip doubly_chained_trampoline call with no line info"
> +}

Intel Deutschland GmbH
Registered Address: Am Campeon 10, 85579 Neubiberg, Germany
Tel: +49 89 99 8853-0, www.intel.de <http://www.intel.de>
Managing Directors: Christin Eisenschmid, Sharon Heck, Tiffany Doon Silva  
Chairperson of the Supervisory Board: Nicole Lau
Registered Office: Munich
Commercial Register: Amtsgericht Muenchen HRB 186928

  reply	other threads:[~2023-07-29 11:03 UTC|newest]

Thread overview: 12+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-07-10 22:56 [PATCH v3 0/4] GDB support for DW_AT_trampoline Abdul Basit Ijaz
2023-07-10 22:56 ` [PATCH v3 1/4] gdb, dwarf: add support for DW_AT_trampoline in DWARF reader Abdul Basit Ijaz
2023-07-27  9:09   ` Bruno Larsen
2023-07-29 11:36     ` Ijaz, Abdul B
2023-07-31  7:16       ` Bruno Larsen
2023-07-10 22:56 ` [PATCH v3 2/4] gdb/symtab: add lookup for trampoline functions Abdul Basit Ijaz
2023-07-10 22:56 ` [PATCH v3 3/4] gdb/infrun: handle stepping through functions with DW_AT_trampoline Abdul Basit Ijaz
2023-07-11 11:21   ` Eli Zaretskii
2023-07-27 11:46   ` Bruno Larsen
2023-07-29 11:03     ` Ijaz, Abdul B [this message]
2023-07-10 22:56 ` [PATCH v3 4/4] gdb: Skip trampoline frames in the stack for printing or finish command Abdul Basit Ijaz
2023-07-11 11:23   ` Eli Zaretskii

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=SA1PR11MB6846B3AAEA5D4893938176F6CB07A@SA1PR11MB6846.namprd11.prod.outlook.com \
    --to=abdul.b.ijaz@intel.com \
    --cc=JiniSusan.George@amd.com \
    --cc=blarsen@redhat.com \
    --cc=eliz@gnu.org \
    --cc=gdb-patches@sourceware.org \
    --cc=tom@tromey.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).